This is an automated email from the git hooks/post-receive script.

Git pushed a commit to branch master
in repository ffmpeg.

The following commit(s) were added to refs/heads/master by this push:
     new 5a75d905cb avformat/mpegts: create stream groups after having parsed 
the entire PMT
5a75d905cb is described below

commit 5a75d905cb24572d14c4e37ad68e3965bfdacd84
Author:     James Almer <[email protected]>
AuthorDate: Thu Mar 26 14:44:49 2026 -0300
Commit:     James Almer <[email protected]>
CommitDate: Sat Mar 28 18:13:36 2026 -0300

    avformat/mpegts: create stream groups after having parsed the entire PMT
    
    Some faulty files have an LCEVC descriptor with a single stream, resulting 
in
    a group being created but never fully populated with the current
    implementation.
    
    Signed-off-by: James Almer <[email protected]>
---
 libavformat/mpegts.c | 107 ++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 80 insertions(+), 27 deletions(-)

diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c
index 6f58e52e70..8eb3bae720 100644
--- a/libavformat/mpegts.c
+++ b/libavformat/mpegts.c
@@ -116,12 +116,22 @@ struct Stream {
 
 #define MAX_STREAMS_PER_PROGRAM 128
 #define MAX_PIDS_PER_PROGRAM (MAX_STREAMS_PER_PROGRAM + 2)
+
+struct StreamGroup {
+    enum AVStreamGroupParamsType type;
+    int id;
+    unsigned int nb_streams;
+    AVStream *streams[MAX_STREAMS_PER_PROGRAM];
+};
+
 struct Program {
     unsigned int id; // program id/service id
     unsigned int nb_pids;
     unsigned int pids[MAX_PIDS_PER_PROGRAM];
     unsigned int nb_streams;
     struct Stream streams[MAX_STREAMS_PER_PROGRAM];
+    unsigned int nb_stream_groups;
+    struct StreamGroup stream_groups[MAX_STREAMS_PER_PROGRAM];
 
     /** have we found pmt for this program */
     int pmt_found;
@@ -309,6 +319,8 @@ static void clear_program(struct Program *p)
         return;
     p->nb_pids = 0;
     p->nb_streams = 0;
+    p->nb_stream_groups = 0;
+    memset(p->stream_groups, 0, sizeof(p->stream_groups));
     p->pmt_found = 0;
 }
 
@@ -1917,82 +1929,87 @@ static int 
parse_mpeg2_extension_descriptor(AVFormatContext *fc, AVStream *st, i
         break;
     case LCEVC_VIDEO_DESCRIPTOR:
         {
-            AVStreamGroup *stg = NULL;
+            struct Program *p = get_program(ts, prg_id);
+            struct StreamGroup *stg;
             int lcevc_stream_tag = get8(pp, desc_end);
-            int ret, i;
+            int i;
 
-            if (!get_program(ts, prg_id))
+            if (!p)
                 return 0;
 
             if (st->codecpar->codec_id != AV_CODEC_ID_LCEVC)
                 return AVERROR_INVALIDDATA;
 
-            for (i = 0; i < fc->nb_stream_groups; i++) {
-                stg = fc->stream_groups[i];
+            for (i = 0; i < p->nb_stream_groups; i++) {
+                stg = &p->stream_groups[i];
                 if (stg->type != AV_STREAM_GROUP_PARAMS_LCEVC)
                     continue;
                 if (stg->id == lcevc_stream_tag)
                     break;
             }
-            if (i == fc->nb_stream_groups)
-                stg = avformat_stream_group_create(fc, 
AV_STREAM_GROUP_PARAMS_LCEVC, NULL);
-            if (!stg)
-                return AVERROR(ENOMEM);
+            if (i == p->nb_stream_groups) {
+                if (p->nb_stream_groups == MAX_STREAMS_PER_PROGRAM)
+                    return AVERROR(EINVAL);
+                p->nb_stream_groups++;
+            }
 
+            stg = &p->stream_groups[i];
             stg->id = lcevc_stream_tag;
+            stg->type = AV_STREAM_GROUP_PARAMS_LCEVC;
             for (i = 0; i < stg->nb_streams; i++) {
                 if (stg->streams[i]->codecpar->codec_id == AV_CODEC_ID_LCEVC)
                     break;
             }
             if (i == stg->nb_streams) {
-                ret = avformat_stream_group_add_stream(stg, st);
-                av_assert0(ret != AVERROR(EEXIST));
-                if (ret < 0)
-                    return ret;
+                if (stg->nb_streams == MAX_STREAMS_PER_PROGRAM)
+                    return AVERROR(EINVAL);
+                stg->streams[stg->nb_streams++] = st;
             } else
                 stg->streams[i] = st;
 
             av_assert0(i < stg->nb_streams);
-            stg->params.lcevc->lcevc_index = i;
         }
         break;
     case LCEVC_LINKAGE_DESCRIPTOR:
         {
+            struct Program *p = get_program(ts, prg_id);
             int num_lcevc_stream_tags = get8(pp, desc_end);
 
-            if (!get_program(ts, prg_id))
+            if (!p)
                 return 0;
 
             if (st->codecpar->codec_id == AV_CODEC_ID_LCEVC)
                 return AVERROR_INVALIDDATA;
 
             for (int i = 0; i < num_lcevc_stream_tags; i++) {
-                AVStreamGroup *stg = NULL;
+                struct StreamGroup *stg = NULL;
                 int lcevc_stream_tag = get8(pp, desc_end);;
-                int ret, j;
+                int j;
 
-                for (j = 0; j < fc->nb_stream_groups; j++) {
-                    stg = fc->stream_groups[j];
+                for (j = 0; j < p->nb_stream_groups; j++) {
+                    stg = &p->stream_groups[j];
                     if (stg->type != AV_STREAM_GROUP_PARAMS_LCEVC)
                         continue;
                     if (stg->id == lcevc_stream_tag)
                         break;
                 }
-                if (j == fc->nb_stream_groups)
-                    stg = avformat_stream_group_create(fc, 
AV_STREAM_GROUP_PARAMS_LCEVC, NULL);
-                if (!stg)
-                    return AVERROR(ENOMEM);
+                if (j == p->nb_stream_groups) {
+                    if (p->nb_stream_groups == MAX_STREAMS_PER_PROGRAM)
+                        return AVERROR(EINVAL);
+                    p->nb_stream_groups++;
+                }
 
+                stg = &p->stream_groups[j];
                 stg->id = lcevc_stream_tag;
+                stg->type = AV_STREAM_GROUP_PARAMS_LCEVC;
                 for (j = 0; j < stg->nb_streams; j++) {
                     if (stg->streams[j]->index == st->index)
                         break;
                 }
                 if (j == stg->nb_streams) {
-                    ret = avformat_stream_group_add_stream(stg, st);
-                    av_assert0(ret != AVERROR(EEXIST));
-                    if (ret < 0)
-                        return ret;
+                    if (stg->nb_streams == MAX_STREAMS_PER_PROGRAM)
+                        return AVERROR(EINVAL);
+                    stg->streams[stg->nb_streams++] = st;
                 }
             }
         }
@@ -2529,6 +2546,39 @@ static int is_pes_stream(int stream_type, uint32_t 
prog_reg_desc)
     }
 }
 
+static void create_stream_groups(MpegTSContext *ts, const struct Program *prg)
+{
+    for (int i = 0; i < prg->nb_stream_groups; i++) {
+        const struct StreamGroup *grp = &prg->stream_groups[i];
+        AVStreamGroup *stg;
+        int j;
+        if (grp->nb_streams < 2)
+            continue;
+        for (j = 0; j < ts->stream->nb_stream_groups; j++) {
+            stg = ts->stream->stream_groups[j];
+            if (stg->id == grp->id)
+                break;
+        }
+        if (j == ts->stream->nb_stream_groups)
+            stg = avformat_stream_group_create(ts->stream, grp->type, NULL);
+        else
+            continue;
+        if (!stg)
+            continue;
+        av_assert0(grp->type == AV_STREAM_GROUP_PARAMS_LCEVC);
+        stg->id = grp->id;
+        for (int j = 0; j < grp->nb_streams; j++) {
+            int ret = avformat_stream_group_add_stream(stg, grp->streams[j]);
+            if (ret < 0) {
+                ff_remove_stream_group(ts->stream, stg);
+                continue;
+            }
+            if (grp->streams[j]->codecpar->codec_id == AV_CODEC_ID_LCEVC)
+                stg->params.lcevc->lcevc_index = stg->nb_streams - 1;
+        }
+    }
+}
+
 static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int 
section_len)
 {
     MpegTSContext *ts = filter->u.section_filter.opaque;
@@ -2746,6 +2796,9 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t 
*section, int section_len
         mpegts_open_pcr_filter(ts, pcr_pid);
 
 out:
+    if (prg)
+        create_stream_groups(ts, prg);
+
     for (i = 0; i < mp4_descr_count; i++)
         av_free(mp4_descr[i].dec_config_descr);
 }

_______________________________________________
ffmpeg-cvslog mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to