From e7696357de6402ad097f031abb72bd68d5deea49 Mon Sep 17 00:00:00 2001 From: James Almer Date: Mon, 23 Mar 2026 14:07:42 -0300 Subject: [PATCH] avformat/dashdec: export LCEVC Stream Groups when the manifest reports the relevant dependency Signed-off-by: James Almer --- libavformat/dashdec.c | 62 ++++++++++++++++++++++++++++++++++++++++++- libavformat/version.h | 2 +- 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/libavformat/dashdec.c b/libavformat/dashdec.c index 9a2ea78149..9902f68d0e 100644 --- a/libavformat/dashdec.c +++ b/libavformat/dashdec.c @@ -87,6 +87,8 @@ struct representation { char *id; char *lang; int bandwidth; + char *dependencyid; + char *codecs; AVRational framerate; AVStream *assoc_stream; /* demuxer stream associated with this representation */ @@ -365,6 +367,8 @@ static void free_representation(struct representation *pls) av_freep(&pls->url_template); av_freep(&pls->lang); + av_freep(&pls->dependencyid); + av_freep(&pls->codecs); av_freep(&pls->id); av_freep(&pls); } @@ -908,6 +912,8 @@ static int parse_manifest_representation(AVFormatContext *s, const char *url, xmlNodePtr baseurl_nodes[4]; xmlNodePtr representation_node = node; char *rep_bandwidth_val; + char *rep_codecs_val; + char *rep_dependencyid_val; enum AVMediaType type = AVMEDIA_TYPE_UNKNOWN; // try get information from representation @@ -942,6 +948,10 @@ static int parse_manifest_representation(AVFormatContext *s, const char *url, representation_baseurl_node = find_child_node_by_name(representation_node, "BaseURL"); representation_segmentlist_node = find_child_node_by_name(representation_node, "SegmentList"); rep_bandwidth_val = xmlGetProp(representation_node, "bandwidth"); + rep_dependencyid_val = xmlGetProp(representation_node, "dependencyId"); + rep_codecs_val = xmlGetProp(representation_node, "codecs"); + if (!rep_codecs_val) + rep_codecs_val = xmlGetProp(adaptionset_node, "codecs"); val = xmlGetProp(representation_node, "id"); if (val) { rep->id = av_strdup(val); @@ -1094,6 +1104,20 @@ static int parse_manifest_representation(AVFormatContext *s, const char *url, if (rep->fragment_duration > 0 && !rep->fragment_timescale) rep->fragment_timescale = 1; rep->bandwidth = rep_bandwidth_val ? atoi(rep_bandwidth_val) : 0; + if (rep_dependencyid_val) { + rep->dependencyid = av_strdup(rep_dependencyid_val); + if (!rep->dependencyid) { + xmlFree(rep_dependencyid_val); + goto enomem; + } + } + if (rep_codecs_val) { + rep->codecs = av_strdup(rep_codecs_val); + if (!rep->codecs) { + xmlFree(rep_codecs_val); + goto enomem; + } + } rep->framerate = av_make_q(0, 0); if (type == AVMEDIA_TYPE_VIDEO) { char *rep_framerate_val = xmlGetProp(representation_node, "frameRate"); @@ -1122,6 +1146,10 @@ static int parse_manifest_representation(AVFormatContext *s, const char *url, end: if (rep_bandwidth_val) xmlFree(rep_bandwidth_val); + if (rep_dependencyid_val) + xmlFree(rep_dependencyid_val); + if (rep_codecs_val) + xmlFree(rep_codecs_val); return ret; enomem: @@ -2051,7 +2079,7 @@ static int dash_read_header(AVFormatContext *s) AVProgram *program; int ret = 0; int stream_index = 0; - int i; + int i, j; c->interrupt_callback = &s->interrupt_callback; @@ -2157,6 +2185,38 @@ static int dash_read_header(AVFormatContext *s) move_metadata(rep->assoc_stream, "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) + 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 (!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) + 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); + if (ret < 0) + return ret; + ret = avformat_stream_group_add_stream(stg, rep->assoc_stream); + if (ret < 0) + return ret; + stg->id = stg->index; + stg->params.lcevc->lcevc_index = stg->nb_streams - 1; + } + return 0; } diff --git a/libavformat/version.h b/libavformat/version.h index cd62aaf1ca..ff831498b3 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -32,7 +32,7 @@ #include "version_major.h" #define LIBAVFORMAT_VERSION_MINOR 13 -#define LIBAVFORMAT_VERSION_MICRO 101 +#define LIBAVFORMAT_VERSION_MICRO 102 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ LIBAVFORMAT_VERSION_MINOR, \