Commit 6a4f712549 for ffmpeg

commit 6a4f7125498f6ba796d208e32087dc06dea50ee4
Author: James Almer <jamrial@gmail.com>
Date:   Mon Oct 5 16:08:06 2026 -0300

    avformat/dump: Support printing child groups within a group

    Only for Layered Video of Gain Map type for now.

    Signed-off-by: James Almer <jamrial@gmail.com>

diff --git a/libavformat/dump.c b/libavformat/dump.c
index 34f93e24a4..0f2eef33c9 100644
--- a/libavformat/dump.c
+++ b/libavformat/dump.c
@@ -684,34 +684,36 @@ static void dump_stream_format(const AVFormatContext *ic, int i,
 }

 static void dump_stream_group(const AVFormatContext *ic, uint8_t *printed,
-                              int i, int index, int is_output)
+                              int i, int index, int is_output, int log_level)
 {
     const AVStreamGroup *stg = ic->stream_groups[i];
+    const char *group_indent = log_level != AV_LOG_INFO ? "  " : "";
+    const char *extra_indent = log_level != AV_LOG_INFO ? "      " : "    ";
     int flags = (is_output ? ic->oformat->flags : ic->iformat->flags);
     char buf[512];
     int ret;

-    av_log(NULL, AV_LOG_INFO, "  Stream group #%d:%d", index, i);
+    av_log(NULL, log_level, "%s  Stream group #%d:%d", group_indent, index, i);
     if (flags & AVFMT_SHOW_IDS)
-        av_log(NULL, AV_LOG_INFO, "[0x%"PRIx64"]", stg->id);
-    av_log(NULL, AV_LOG_INFO, ":");
+        av_log(NULL, log_level, "[0x%"PRIx64"]", stg->id);
+    av_log(NULL, log_level, ":");

     switch (stg->type) {
     case AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT: {
         const AVIAMFAudioElement *audio_element = stg->params.iamf_audio_element;
-        av_log(NULL, AV_LOG_INFO, " IAMF Audio Element:");
-        dump_disposition(stg->disposition, AV_LOG_INFO);
-        av_log(NULL, AV_LOG_INFO, "\n");
-        dump_metadata(NULL, stg->metadata, "    ", AV_LOG_INFO);
+        av_log(NULL, log_level, " IAMF Audio Element:");
+        dump_disposition(stg->disposition, log_level);
+        av_log(NULL, log_level, "\n");
+        dump_metadata(NULL, stg->metadata, "    ", log_level);
         for (int j = 0; j < audio_element->nb_layers; j++) {
             const AVIAMFLayer *layer = audio_element->layers[j];
             int channel_count = layer->ch_layout.nb_channels;
-            av_log(NULL, AV_LOG_INFO, "    Layer %d:", j);
+            av_log(NULL, log_level, "    Layer %d:", j);
             ret = av_channel_layout_describe(&layer->ch_layout, buf, sizeof(buf));
             if (ret >= 0)
-                av_log(NULL, AV_LOG_INFO, " %s", buf);
-            av_log(NULL, AV_LOG_INFO, "\n");
-            for (int k = 0; channel_count > 0 && k < stg->nb_entries; k++) {
+                av_log(NULL, log_level, " %s", buf);
+            av_log(NULL, log_level, "\n");
+            for (int k = 0; log_level == AV_LOG_INFO && channel_count > 0 && k < stg->nb_entries; k++) {
                 const AVStreamGroupEntry *entry = stg->entries[k];
                 if (entry->type != AV_STREAM_GROUP_ENTRY_STREAM)
                     continue;
@@ -727,14 +729,14 @@ static void dump_stream_group(const AVFormatContext *ic, uint8_t *printed,
     }
     case AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION: {
         const AVIAMFMixPresentation *mix_presentation = stg->params.iamf_mix_presentation;
-        av_log(NULL, AV_LOG_INFO, " IAMF Mix Presentation:");
-        dump_disposition(stg->disposition, AV_LOG_INFO);
-        av_log(NULL, AV_LOG_INFO, "\n");
-        dump_metadata(NULL, stg->metadata, "    ", AV_LOG_INFO);
-        dump_dictionary(NULL, mix_presentation->annotations, "Annotations", "    ", AV_LOG_INFO);
+        av_log(NULL, log_level, " IAMF Mix Presentation:");
+        dump_disposition(stg->disposition, log_level);
+        av_log(NULL, log_level, "\n");
+        dump_metadata(NULL, stg->metadata, "    ", log_level);
+        dump_dictionary(NULL, mix_presentation->annotations, "Annotations", "    ", log_level);
         for (int j = 0; j < mix_presentation->nb_submixes; j++) {
             AVIAMFSubmix *sub_mix = mix_presentation->submixes[j];
-            av_log(NULL, AV_LOG_INFO, "    Submix %d:\n", j);
+            av_log(NULL, log_level, "    Submix %d:\n", j);
             for (int k = 0; k < sub_mix->nb_elements; k++) {
                 const AVIAMFSubmixElement *submix_element = sub_mix->elements[k];
                 const AVStreamGroup *audio_element = NULL;
@@ -745,24 +747,24 @@ static void dump_stream_group(const AVFormatContext *ic, uint8_t *printed,
                         break;
                     }
                 if (audio_element) {
-                    av_log(NULL, AV_LOG_INFO, "      IAMF Audio Element #%d:%d",
+                    av_log(NULL, log_level, "      IAMF Audio Element #%d:%d",
                            index, audio_element->index);
                     if (flags & AVFMT_SHOW_IDS)
-                        av_log(NULL, AV_LOG_INFO, "[0x%"PRIx64"]", audio_element->id);
-                    av_log(NULL, AV_LOG_INFO, "\n");
-                    dump_dictionary(NULL, submix_element->annotations, "Annotations", "        ", AV_LOG_INFO);
+                        av_log(NULL, log_level, "[0x%"PRIx64"]", audio_element->id);
+                    av_log(NULL, log_level, "\n");
+                    dump_dictionary(NULL, submix_element->annotations, "Annotations", "        ", log_level);
                 }
             }
             for (int k = 0; k < sub_mix->nb_layouts; k++) {
                 const AVIAMFSubmixLayout *submix_layout = sub_mix->layouts[k];
-                av_log(NULL, AV_LOG_INFO, "      Layout #%d:", k);
+                av_log(NULL, log_level, "      Layout #%d:", k);
                 if (submix_layout->layout_type == 2 ||
                     submix_layout->layout_type == 3) {
                     ret = av_channel_layout_describe(&submix_layout->sound_system, buf, sizeof(buf));
                     if (ret >= 0)
-                        av_log(NULL, AV_LOG_INFO, " %s", buf);
+                        av_log(NULL, log_level, " %s", buf);
                 }
-                av_log(NULL, AV_LOG_INFO, "\n");
+                av_log(NULL, log_level, "\n");
             }
         }
         break;
@@ -771,7 +773,7 @@ static void dump_stream_group(const AVFormatContext *ic, uint8_t *printed,
         const AVStreamGroupTileGrid *tile_grid = stg->params.tile_grid;
         AVCodecContext *avctx = avcodec_alloc_context3(NULL);
         const char *ptr = NULL;
-        av_log(NULL, AV_LOG_INFO, " Tile Grid:");
+        av_log(NULL, log_level, " Tile Grid:");
         if (avctx && stg->nb_entries && stg->entries[0]->type == AV_STREAM_GROUP_ENTRY_STREAM) {
             const AVStream *st = stg->entries[0]->stream;
             if (!avcodec_parameters_to_context(avctx, st->codecpar)) {
@@ -788,13 +790,13 @@ static void dump_stream_group(const AVFormatContext *ic, uint8_t *printed,
         }
         avcodec_free_context(&avctx);
         if (ptr)
-            av_log(NULL, AV_LOG_INFO, "%s", ptr);
-        dump_disposition(stg->disposition, AV_LOG_INFO);
-        av_log(NULL, AV_LOG_INFO, "\n");
-        dump_metadata(NULL, stg->metadata, "    ", AV_LOG_INFO);
+            av_log(NULL, log_level, "%s", ptr);
+        dump_disposition(stg->disposition, log_level);
+        av_log(NULL, log_level, "\n");
+        dump_metadata(NULL, stg->metadata, extra_indent, log_level);
         dump_sidedata(NULL, stg->coded_side_data, stg->nb_coded_side_data,
                       tile_grid->width, tile_grid->height, (AVRational) {0,1},
-                      "    ", AV_LOG_INFO);
+                      extra_indent, log_level);
         for (int i = 0; i < tile_grid->nb_tiles; i++) {
             const AVStream *st = NULL;
             if (tile_grid->offsets[i].idx < stg->nb_entries) {
@@ -814,7 +816,7 @@ static void dump_stream_group(const AVFormatContext *ic, uint8_t *printed,
                 continue;
             const AVStream *st = entry->stream;
             if (!printed[st->index]) {
-                dump_stream_format(ic, st->index, i, index, is_output, AV_LOG_INFO);
+                dump_stream_format(ic, st->index, i, index, is_output, log_level);
                 printed[st->index] = 1;
             }
         }
@@ -844,8 +846,13 @@ static void dump_stream_group(const AVFormatContext *ic, uint8_t *printed,
         }
         avcodec_free_context(&avctx);
         if (ptr)
-            av_log(NULL, AV_LOG_INFO, "%s", ptr);
-        av_log(NULL, AV_LOG_INFO, "\n");
+            av_log(NULL, log_level, "%s", ptr);
+        dump_disposition(stg->disposition, log_level);
+        av_log(NULL, log_level, "\n");
+        dump_metadata(NULL, stg->metadata, extra_indent, log_level);
+        dump_sidedata(NULL, stg->coded_side_data, stg->nb_coded_side_data,
+                      layered_video->width, layered_video->height, (AVRational) {0,1},
+                      extra_indent, log_level);
         for (int i = 0; i < stg->nb_entries; i++) {
             const AVStreamGroupEntry *entry = stg->entries[i];
             if (entry->type != AV_STREAM_GROUP_ENTRY_STREAM)
@@ -857,26 +864,41 @@ static void dump_stream_group(const AVFormatContext *ic, uint8_t *printed,
         break;
     }
     case AV_STREAM_GROUP_PARAMS_TREF: {
-        av_log(NULL, AV_LOG_INFO, " Track Reference:\n");
+        av_log(NULL, log_level, " Track Reference:\n");
         for (int i = 0; i < stg->nb_entries; i++) {
             const AVStreamGroupEntry *entry = stg->entries[i];
             if (entry->type != AV_STREAM_GROUP_ENTRY_STREAM)
                 continue;
             const AVStream *st = entry->stream;
-            dump_stream_format(ic, st->index, i, index, is_output, AV_LOG_INFO);
+            dump_stream_format(ic, st->index, i, index, is_output, log_level);
             printed[st->index] = 1;
         }
         break;
     }
     case AV_STREAM_GROUP_PARAMS_GAIN_MAP: {
-        av_log(NULL, AV_LOG_INFO, " Gain Map:\n");
+        const AVStreamGroupLayeredVideo *layered_video = stg->params.layered_video;
+        const char *ptr = NULL;
+        av_log(NULL, AV_LOG_INFO, " Gain Map:");
+        buf[0] = 0;
+        av_strlcatf(buf, sizeof(buf), " %dx%d", layered_video->width, layered_video->height);
+        ptr = av_stristr(buf, " ");
+        if (ptr)
+            av_log(NULL, log_level, "%s", ptr);
+        dump_disposition(stg->disposition, log_level);
+        av_log(NULL, log_level, "\n");
+        dump_metadata(NULL, stg->metadata, extra_indent, log_level);
+        dump_sidedata(NULL, stg->coded_side_data, stg->nb_coded_side_data,
+                      layered_video->width, layered_video->height, (AVRational) {0,1},
+                      extra_indent, log_level);
         for (int i = 0; i < stg->nb_entries; i++) {
             const AVStreamGroupEntry *entry = stg->entries[i];
-            if (entry->type != AV_STREAM_GROUP_ENTRY_STREAM)
-                continue;
-            const AVStream *st = entry->stream;
-            dump_stream_format(ic, st->index, i, index, is_output, AV_LOG_INFO);
-            printed[st->index] = 1;
+            if (entry->type == AV_STREAM_GROUP_ENTRY_STREAM) {
+                const AVStream *st = entry->stream;
+                dump_stream_format(ic, st->index, i, index, is_output, log_level);
+                printed[st->index] = 1;
+            } else if (entry->type == AV_STREAM_GROUP_ENTRY_STREAM_GROUP)
+                dump_stream_group(ic, printed, entry->stream_group->index, index,
+                                  is_output, AV_LOG_VERBOSE);
         }
         break;
     }
@@ -968,7 +990,7 @@ void av_dump_format(AVFormatContext *ic, int index,
     }

     for (i = 0; i < ic->nb_stream_groups; i++)
-         dump_stream_group(ic, printed, i, index, is_output);
+         dump_stream_group(ic, printed, i, index, is_output, AV_LOG_INFO);

     for (i = 0; i < ic->nb_streams; i++)
         if (!printed[i])