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

Git pushed a commit to branch master
in repository ffmpeg.

commit 8fad6dcfd906485cffc9becab8b4071f46224f20
Author:     James Almer <[email protected]>
AuthorDate: Mon Apr 27 16:56:50 2026 -0300
Commit:     James Almer <[email protected]>
CommitDate: Wed Apr 29 14:00:03 2026 +0000

    avformat/dashdec: support more than one underlying stream per Representation
    
    Some Dash manifests contain Representations within an Adaptation Set that
    reference an underlying mp4 context that contain more than the stream it
    describes, as is the case of LCEVC enhancements.
    
    Despite the fact open_demux_for_component() loops through all streams in the
    underlying context, the rest of the demuxer is writen assuming only the
    stream described by the corresponding representation will be present, which
    results in completely wrong stream index assignments.
    
    Signed-off-by: James Almer <[email protected]>
---
 libavformat/dashdec.c | 85 +++++++++++++++++++++++++++++++++------------------
 1 file changed, 55 insertions(+), 30 deletions(-)

diff --git a/libavformat/dashdec.c b/libavformat/dashdec.c
index 9902f68d0e..7aa6121695 100644
--- a/libavformat/dashdec.c
+++ b/libavformat/dashdec.c
@@ -90,7 +90,8 @@ struct representation {
     char *dependencyid;
     char *codecs;
     AVRational framerate;
-    AVStream *assoc_stream; /* demuxer stream associated with this 
representation */
+    AVStream **assoc_stream; /* demuxer streams associated with this 
representation */
+    int nb_assoc_stream;
 
     int n_fragments;
     struct fragment **fragments; /* VOD list of fragment for profile */
@@ -365,6 +366,7 @@ static void free_representation(struct representation *pls)
         avformat_close_input(&pls->ctx);
     }
 
+    av_freep(&pls->assoc_stream);
     av_freep(&pls->url_template);
     av_freep(&pls->lang);
     av_freep(&pls->dependencyid);
@@ -2007,7 +2009,7 @@ static int open_demux_for_component(AVFormatContext *s, 
struct representation *p
         if (!st)
             return AVERROR(ENOMEM);
 
-        st->id = i;
+        st->id = i + pls->stream_index;
 
         ret = avcodec_parameters_copy(st->codecpar, ist->codecpar);
         if (ret < 0)
@@ -2108,12 +2110,12 @@ static int dash_read_header(AVFormatContext *s)
             if (ret < 0)
                 return ret;
         }
+        rep->stream_index = stream_index;
         ret = open_demux_for_component(s, rep);
 
         if (ret)
             return ret;
-        rep->stream_index = stream_index;
-        ++stream_index;
+        stream_index += rep->ctx->nb_streams;
     }
 
     if(c->n_audios)
@@ -2126,12 +2128,12 @@ static int dash_read_header(AVFormatContext *s)
             if (ret < 0)
                 return ret;
         }
+        rep->stream_index = stream_index;
         ret = open_demux_for_component(s, rep);
 
         if (ret)
             return ret;
-        rep->stream_index = stream_index;
-        ++stream_index;
+        stream_index += rep->ctx->nb_streams;
     }
 
     if (c->n_subtitles)
@@ -2144,12 +2146,12 @@ static int dash_read_header(AVFormatContext *s)
             if (ret < 0)
                 return ret;
         }
+        rep->stream_index = stream_index;
         ret = open_demux_for_component(s, rep);
 
         if (ret)
             return ret;
-        rep->stream_index = stream_index;
-        ++stream_index;
+        stream_index += rep->ctx->nb_streams;
     }
 
     if (!stream_index)
@@ -2162,55 +2164,75 @@ static int dash_read_header(AVFormatContext *s)
 
     for (i = 0; i < c->n_videos; i++) {
         rep = c->videos[i];
-        av_program_add_stream_index(s, 0, rep->stream_index);
-        rep->assoc_stream = s->streams[rep->stream_index];
+        rep->assoc_stream = av_malloc_array(rep->ctx->nb_streams, 
sizeof(*rep->assoc_stream));
+        if (!rep->assoc_stream)
+            return AVERROR(ENOMEM);
+        rep->nb_assoc_stream = rep->ctx->nb_streams;
+        for (int j = 0; j < rep->ctx->nb_streams; j++) {
+            av_program_add_stream_index(s, 0, rep->stream_index + j);
+            rep->assoc_stream[j] = s->streams[rep->stream_index + j];
+        }
         if (rep->bandwidth > 0)
-            av_dict_set_int(&rep->assoc_stream->metadata, "variant_bitrate", 
rep->bandwidth, 0);
-        move_metadata(rep->assoc_stream, "id", &rep->id);
+            av_dict_set_int(&rep->assoc_stream[0]->metadata, 
"variant_bitrate", rep->bandwidth, 0);
+        move_metadata(rep->assoc_stream[0], "id", &rep->id);
     }
     for (i = 0; i < c->n_audios; i++) {
         rep = c->audios[i];
-        av_program_add_stream_index(s, 0, rep->stream_index);
-        rep->assoc_stream = s->streams[rep->stream_index];
+        rep->assoc_stream = av_malloc_array(rep->ctx->nb_streams, 
sizeof(*rep->assoc_stream));
+        if (!rep->assoc_stream)
+            return AVERROR(ENOMEM);
+        rep->nb_assoc_stream = rep->ctx->nb_streams;
+        for (int j = 0; j < rep->ctx->nb_streams; j++) {
+            av_program_add_stream_index(s, 0, rep->stream_index + j);
+            rep->assoc_stream[j] = s->streams[rep->stream_index + j];
+        }
         if (rep->bandwidth > 0)
-            av_dict_set_int(&rep->assoc_stream->metadata, "variant_bitrate", 
rep->bandwidth, 0);
-        move_metadata(rep->assoc_stream, "id", &rep->id);
-        move_metadata(rep->assoc_stream, "language", &rep->lang);
+            av_dict_set_int(&rep->assoc_stream[0]->metadata, 
"variant_bitrate", rep->bandwidth, 0);
+        move_metadata(rep->assoc_stream[0], "id", &rep->id);
+        move_metadata(rep->assoc_stream[0], "language", &rep->lang);
     }
     for (i = 0; i < c->n_subtitles; i++) {
         rep = c->subtitles[i];
-        av_program_add_stream_index(s, 0, rep->stream_index);
-        rep->assoc_stream = s->streams[rep->stream_index];
-        move_metadata(rep->assoc_stream, "id", &rep->id);
-        move_metadata(rep->assoc_stream, "language", &rep->lang);
+        rep->assoc_stream = av_malloc_array(rep->ctx->nb_streams, 
sizeof(*rep->assoc_stream));
+        if (!rep->assoc_stream)
+            return AVERROR(ENOMEM);
+        rep->nb_assoc_stream = rep->ctx->nb_streams;
+        for (int j = 0; j < rep->ctx->nb_streams; j++) {
+            av_program_add_stream_index(s, 0, rep->stream_index + j);
+            rep->assoc_stream[j] = s->streams[rep->stream_index + j];
+        }
+        move_metadata(rep->assoc_stream[0], "id", &rep->id);
+        move_metadata(rep->assoc_stream[0], "language", &rep->lang);
     }
 
     /* Create stream groups if needed */
     for (i = 0; i < c->n_videos; i++) {
         struct representation *ref;
         rep = c->videos[i];
-        if (!rep->dependencyid)
+        if (!rep->dependencyid || !rep->nb_assoc_stream)
             continue;
         for (j = 0; j < c->n_videos; j++) {
             if (j == i)
                 continue;
             ref = c->videos[j];
-            const AVDictionaryEntry *id = 
av_dict_get(ref->assoc_stream->metadata, "id", NULL, AV_DICT_MATCH_CASE);
+            if (!ref->nb_assoc_stream)
+                continue;
+            const AVDictionaryEntry *id = 
av_dict_get(ref->assoc_stream[0]->metadata, "id", NULL, AV_DICT_MATCH_CASE);
             if (!strcmp(rep->dependencyid, id->value))
                 break;
         }
         if (j >= c->n_videos || !av_strstart(rep->codecs, "lvc1", NULL) ||
-            rep->assoc_stream->codecpar->codec_id != AV_CODEC_ID_LCEVC)
+            rep->assoc_stream[0]->codecpar->codec_id != AV_CODEC_ID_LCEVC)
             continue;
         AVStreamGroup *stg = avformat_stream_group_create(s, 
AV_STREAM_GROUP_PARAMS_LCEVC, NULL);
         if (!stg)
             return AVERROR(ENOMEM);
-        stg->params.lcevc->width  = rep->assoc_stream->codecpar->width;
-        stg->params.lcevc->height = rep->assoc_stream->codecpar->height;
-        ret = avformat_stream_group_add_stream(stg, ref->assoc_stream);
+        stg->params.lcevc->width  = rep->assoc_stream[0]->codecpar->width;
+        stg->params.lcevc->height = rep->assoc_stream[0]->codecpar->height;
+        ret = avformat_stream_group_add_stream(stg, ref->assoc_stream[0]);
         if (ret < 0)
             return ret;
-        ret = avformat_stream_group_add_stream(stg, rep->assoc_stream);
+        ret = avformat_stream_group_add_stream(stg, rep->assoc_stream[0]);
         if (ret < 0)
             return ret;
         stg->id = stg->index;
@@ -2226,7 +2248,10 @@ static void recheck_discard_flags(AVFormatContext *s, 
struct representation **p,
 
     for (i = 0; i < n; i++) {
         struct representation *pls = p[i];
-        int needed = !pls->assoc_stream || pls->assoc_stream->discard < 
AVDISCARD_ALL;
+        int needed = !pls->nb_assoc_stream;
+
+        for (int j = 0; j < pls->nb_assoc_stream; j++)
+            needed |= pls->assoc_stream[j]->discard < AVDISCARD_ALL;
 
         if (needed && !pls->ctx) {
             pls->cur_seg_offset = 0;
@@ -2294,7 +2319,7 @@ static int dash_read_packet(AVFormatContext *s, AVPacket 
*pkt)
         if (ret >= 0) {
             /* If we got a packet, return it */
             cur->cur_timestamp = av_rescale(pkt->pts, 
(int64_t)cur->ctx->streams[0]->time_base.num * 90000, 
cur->ctx->streams[0]->time_base.den);
-            pkt->stream_index = cur->stream_index;
+            pkt->stream_index += cur->stream_index;
             return 0;
         }
         if (cur->is_restart_needed) {

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

Reply via email to