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]
