PR #22598 opened by James Almer (jamrial)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22598
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22598.patch


>From 28aea485753038828dabebaa8240635dc6992b26 Mon Sep 17 00:00:00 2001
From: James Almer <[email protected]>
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 <[email protected]>
---
 libavformat/dashdec.c | 61 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 60 insertions(+), 1 deletion(-)

diff --git a/libavformat/dashdec.c b/libavformat/dashdec.c
index 9a2ea78149..8e2aecef77 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,37 @@ 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->params.lcevc->lcevc_index = stg->nb_streams - 1;
+    }
+
     return 0;
 }
 
-- 
2.52.0

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

Reply via email to