diff mbox series

[FFmpeg-devel,1/2] fftools/ffprobe: add support for Stream Groups

Message ID 20240302190321.1851-1-jamrial@gmail.com
State New
Headers show
Series [FFmpeg-devel,1/2] fftools/ffprobe: add support for Stream Groups | expand

Checks

Context Check Description
yinshiyou/make_loongarch64 success Make finished
yinshiyou/make_fate_loongarch64 fail Make fate failed
andriy/make_x86 success Make finished
andriy/make_fate_x86 fail Make fate failed

Commit Message

James Almer March 2, 2024, 7:03 p.m. UTC
Signed-off-by: James Almer <jamrial@gmail.com>
---
 fftools/ffprobe.c | 186 ++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 157 insertions(+), 29 deletions(-)
diff mbox series

Patch

diff --git a/fftools/ffprobe.c b/fftools/ffprobe.c
index ea225f14ab..ec3c713849 100644
--- a/fftools/ffprobe.c
+++ b/fftools/ffprobe.c
@@ -112,8 +112,10 @@  static int do_show_format  = 0;
 static int do_show_frames  = 0;
 static int do_show_packets = 0;
 static int do_show_programs = 0;
+static int do_show_stream_groups = 0;
 static int do_show_streams = 0;
 static int do_show_stream_disposition = 0;
+static int do_show_stream_group_disposition = 0;
 static int do_show_data    = 0;
 static int do_show_program_version  = 0;
 static int do_show_library_versions = 0;
@@ -126,6 +128,7 @@  static int do_show_chapter_tags = 0;
 static int do_show_format_tags = 0;
 static int do_show_frame_tags = 0;
 static int do_show_program_tags = 0;
+static int do_show_stream_group_tags = 0;
 static int do_show_stream_tags = 0;
 static int do_show_packet_tags = 0;
 
@@ -159,7 +162,7 @@  static int find_stream_info  = 1;
 
 /* section structure definition */
 
-#define SECTION_MAX_NB_CHILDREN 10
+#define SECTION_MAX_NB_CHILDREN 11
 
 typedef enum {
     SECTION_ID_NONE = -1,
@@ -210,6 +213,14 @@  typedef enum {
     SECTION_ID_STREAM_TAGS,
     SECTION_ID_STREAM_SIDE_DATA_LIST,
     SECTION_ID_STREAM_SIDE_DATA,
+    SECTION_ID_STREAM_GROUP_STREAM_DISPOSITION,
+    SECTION_ID_STREAM_GROUP_STREAM_TAGS,
+    SECTION_ID_STREAM_GROUP,
+    SECTION_ID_STREAM_GROUP_STREAMS,
+    SECTION_ID_STREAM_GROUP_STREAM,
+    SECTION_ID_STREAM_GROUP_DISPOSITION,
+    SECTION_ID_STREAM_GROUP_TAGS,
+    SECTION_ID_STREAM_GROUPS,
     SECTION_ID_SUBTITLE,
 } SectionID;
 
@@ -286,7 +297,7 @@  static struct section sections[] = {
     [SECTION_ID_PROGRAM_VERSION] =    { SECTION_ID_PROGRAM_VERSION, "program_version", 0, { -1 } },
     [SECTION_ID_PROGRAMS] =                   { SECTION_ID_PROGRAMS, "programs", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PROGRAM, -1 } },
     [SECTION_ID_ROOT] =               { SECTION_ID_ROOT, "root", SECTION_FLAG_IS_WRAPPER,
-                                        { SECTION_ID_CHAPTERS, SECTION_ID_FORMAT, SECTION_ID_FRAMES, SECTION_ID_PROGRAMS, SECTION_ID_STREAMS,
+                                        { SECTION_ID_CHAPTERS, SECTION_ID_FORMAT, SECTION_ID_FRAMES, SECTION_ID_PROGRAMS, SECTION_ID_STREAM_GROUPS, SECTION_ID_STREAMS,
                                           SECTION_ID_PACKETS, SECTION_ID_ERROR, SECTION_ID_PROGRAM_VERSION, SECTION_ID_LIBRARY_VERSIONS,
                                           SECTION_ID_PIXEL_FORMATS, -1} },
     [SECTION_ID_STREAMS] =            { SECTION_ID_STREAMS, "streams", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM, -1 } },
@@ -295,6 +306,14 @@  static struct section sections[] = {
     [SECTION_ID_STREAM_TAGS] =        { SECTION_ID_STREAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "stream_tags" },
     [SECTION_ID_STREAM_SIDE_DATA_LIST] ={ SECTION_ID_STREAM_SIDE_DATA_LIST, "side_data_list", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_SIDE_DATA, -1 }, .element_name = "side_data", .unique_name = "stream_side_data_list" },
     [SECTION_ID_STREAM_SIDE_DATA] =     { SECTION_ID_STREAM_SIDE_DATA, "side_data", SECTION_FLAG_HAS_TYPE|SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .unique_name = "stream_side_data", .element_name = "side_datum", .get_type = get_packet_side_data_type },
+    [SECTION_ID_STREAM_GROUP_STREAM_DISPOSITION] = { SECTION_ID_STREAM_GROUP_STREAM_DISPOSITION, "disposition", 0, { -1 }, .unique_name = "stream_group_stream_disposition" },
+    [SECTION_ID_STREAM_GROUP_STREAM_TAGS] =        { SECTION_ID_STREAM_GROUP_STREAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "stream_group_stream_tags" },
+    [SECTION_ID_STREAM_GROUP] =                    { SECTION_ID_STREAM_GROUP, "stream_group", 0, { SECTION_ID_STREAM_GROUP_TAGS, SECTION_ID_STREAM_GROUP_DISPOSITION, SECTION_ID_STREAM_GROUP_STREAMS, -1 } },
+    [SECTION_ID_STREAM_GROUP_STREAMS] =            { SECTION_ID_STREAM_GROUP_STREAMS, "streams", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP_STREAM, -1 }, .unique_name = "stream_group_streams" },
+    [SECTION_ID_STREAM_GROUP_STREAM] =             { SECTION_ID_STREAM_GROUP_STREAM, "stream", 0, { SECTION_ID_STREAM_GROUP_STREAM_DISPOSITION, SECTION_ID_STREAM_GROUP_STREAM_TAGS, -1 }, .unique_name = "stream_group_stream" },
+    [SECTION_ID_STREAM_GROUP_DISPOSITION] =        { SECTION_ID_STREAM_GROUP_DISPOSITION, "disposition", 0, { -1 }, .unique_name = "stream_group_disposition" },
+    [SECTION_ID_STREAM_GROUP_TAGS] =               { SECTION_ID_STREAM_GROUP_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "stream_group_tags" },
+    [SECTION_ID_STREAM_GROUPS] =                   { SECTION_ID_STREAM_GROUPS, "stream_groups", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP, -1 } },
     [SECTION_ID_SUBTITLE] =           { SECTION_ID_SUBTITLE, "subtitle", 0, { -1 } },
 };
 
@@ -3039,7 +3058,8 @@  static int read_packets(WriterContext *w, InputFile *ifile)
     return ret;
 }
 
-static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_idx, InputStream *ist, int in_program)
+static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_idx, InputStream *ist,
+                       int in_program, int in_group)
 {
     AVStream *stream = ist->st;
     AVCodecParameters *par;
@@ -3049,12 +3069,18 @@  static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_id
     AVRational sar, dar;
     AVBPrint pbuf;
     const AVCodecDescriptor *cd;
+    SectionID section_header =  in_program ? SECTION_ID_PROGRAM_STREAM :
+                               (in_group   ? SECTION_ID_STREAM_GROUP_STREAM : SECTION_ID_STREAM);
+    SectionID section_disposition =  in_program ? SECTION_ID_PROGRAM_STREAM_DISPOSITION :
+                                    (in_group   ? SECTION_ID_STREAM_GROUP_STREAM_DISPOSITION : SECTION_ID_STREAM_DISPOSITION);
+    SectionID section_tags = in_program ? SECTION_ID_PROGRAM_STREAM_TAGS :
+                            (in_group   ? SECTION_ID_STREAM_GROUP_STREAM_TAGS : SECTION_ID_STREAM_TAGS);
     int ret = 0;
     const char *profile = NULL;
 
     av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
 
-    writer_print_section_header(w, NULL, in_program ? SECTION_ID_PROGRAM_STREAM : SECTION_ID_STREAM);
+    writer_print_section_header(w, NULL, section_header);
 
     print_int("index", stream->index);
 
@@ -3215,35 +3241,35 @@  static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_id
     }
 
     /* Print disposition information */
-#define PRINT_DISPOSITION(flagname, name) do {                                \
-        print_int(name, !!(stream->disposition & AV_DISPOSITION_##flagname)); \
+#define PRINT_DISPOSITION(flagname, ctx, name) do {                        \
+        print_int(name, !!(ctx->disposition & AV_DISPOSITION_##flagname)); \
     } while (0)
 
     if (do_show_stream_disposition) {
-        writer_print_section_header(w, NULL, in_program ? SECTION_ID_PROGRAM_STREAM_DISPOSITION : SECTION_ID_STREAM_DISPOSITION);
-        PRINT_DISPOSITION(DEFAULT,          "default");
-        PRINT_DISPOSITION(DUB,              "dub");
-        PRINT_DISPOSITION(ORIGINAL,         "original");
-        PRINT_DISPOSITION(COMMENT,          "comment");
-        PRINT_DISPOSITION(LYRICS,           "lyrics");
-        PRINT_DISPOSITION(KARAOKE,          "karaoke");
-        PRINT_DISPOSITION(FORCED,           "forced");
-        PRINT_DISPOSITION(HEARING_IMPAIRED, "hearing_impaired");
-        PRINT_DISPOSITION(VISUAL_IMPAIRED,  "visual_impaired");
-        PRINT_DISPOSITION(CLEAN_EFFECTS,    "clean_effects");
-        PRINT_DISPOSITION(ATTACHED_PIC,     "attached_pic");
-        PRINT_DISPOSITION(TIMED_THUMBNAILS, "timed_thumbnails");
-        PRINT_DISPOSITION(NON_DIEGETIC,     "non_diegetic");
-        PRINT_DISPOSITION(CAPTIONS,         "captions");
-        PRINT_DISPOSITION(DESCRIPTIONS,     "descriptions");
-        PRINT_DISPOSITION(METADATA,         "metadata");
-        PRINT_DISPOSITION(DEPENDENT,        "dependent");
-        PRINT_DISPOSITION(STILL_IMAGE,      "still_image");
+        writer_print_section_header(w, NULL, section_disposition);
+        PRINT_DISPOSITION(DEFAULT, stream,          "default");
+        PRINT_DISPOSITION(DUB, stream,              "dub");
+        PRINT_DISPOSITION(ORIGINAL, stream,         "original");
+        PRINT_DISPOSITION(COMMENT, stream,          "comment");
+        PRINT_DISPOSITION(LYRICS, stream,           "lyrics");
+        PRINT_DISPOSITION(KARAOKE, stream,          "karaoke");
+        PRINT_DISPOSITION(FORCED, stream,           "forced");
+        PRINT_DISPOSITION(HEARING_IMPAIRED, stream, "hearing_impaired");
+        PRINT_DISPOSITION(VISUAL_IMPAIRED, stream,  "visual_impaired");
+        PRINT_DISPOSITION(CLEAN_EFFECTS, stream,    "clean_effects");
+        PRINT_DISPOSITION(ATTACHED_PIC, stream,     "attached_pic");
+        PRINT_DISPOSITION(TIMED_THUMBNAILS, stream, "timed_thumbnails");
+        PRINT_DISPOSITION(NON_DIEGETIC, stream,     "non_diegetic");
+        PRINT_DISPOSITION(CAPTIONS, stream,         "captions");
+        PRINT_DISPOSITION(DESCRIPTIONS, stream,     "descriptions");
+        PRINT_DISPOSITION(METADATA, stream,         "metadata");
+        PRINT_DISPOSITION(DEPENDENT, stream,        "dependent");
+        PRINT_DISPOSITION(STILL_IMAGE, stream,      "still_image");
         writer_print_section_footer(w);
     }
 
     if (do_show_stream_tags)
-        ret = show_tags(w, stream->metadata, in_program ? SECTION_ID_PROGRAM_STREAM_TAGS : SECTION_ID_STREAM_TAGS);
+        ret = show_tags(w, stream->metadata, section_tags);
 
     if (stream->codecpar->nb_coded_side_data) {
         writer_print_section_header(w, NULL, SECTION_ID_STREAM_SIDE_DATA_LIST);
@@ -3270,7 +3296,7 @@  static int show_streams(WriterContext *w, InputFile *ifile)
     writer_print_section_header(w, NULL, SECTION_ID_STREAMS);
     for (i = 0; i < ifile->nb_streams; i++)
         if (selected_streams[i]) {
-            ret = show_stream(w, fmt_ctx, i, &ifile->streams[i], 0);
+            ret = show_stream(w, fmt_ctx, i, &ifile->streams[i], 0, 0);
             if (ret < 0)
                 break;
         }
@@ -3298,7 +3324,7 @@  static int show_program(WriterContext *w, InputFile *ifile, AVProgram *program)
     writer_print_section_header(w, NULL, SECTION_ID_PROGRAM_STREAMS);
     for (i = 0; i < program->nb_stream_indexes; i++) {
         if (selected_streams[program->stream_index[i]]) {
-            ret = show_stream(w, fmt_ctx, program->stream_index[i], &ifile->streams[program->stream_index[i]], 1);
+            ret = show_stream(w, fmt_ctx, program->stream_index[i], &ifile->streams[program->stream_index[i]], 1, 0);
             if (ret < 0)
                 break;
         }
@@ -3328,6 +3354,95 @@  static int show_programs(WriterContext *w, InputFile *ifile)
     return ret;
 }
 
+
+static void print_stream_group_params(WriterContext *w, AVStreamGroup *stg)
+{
+    if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
+        print_str("type", "IAMF Audio Element");
+    else if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION)
+        print_str("type", "IAMF Mix Presentation");
+    else if (stg->type == AV_STREAM_GROUP_PARAMS_TILE_GRID) {
+        print_str("type", "Tile Grid");
+    } else
+        print_str_opt("type", "unknown");
+}
+
+static int show_stream_group(WriterContext *w, InputFile *ifile, AVStreamGroup *stg)
+{
+    AVFormatContext *fmt_ctx = ifile->fmt_ctx;
+    AVBPrint pbuf;
+    int i, ret = 0;
+
+    av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
+    writer_print_section_header(w, NULL, SECTION_ID_STREAM_GROUP);
+    print_int("index", stg->index);
+    if (fmt_ctx->iformat->flags & AVFMT_SHOW_IDS) print_fmt    ("id", "0x%"PRIx64, stg->id);
+    else                                          print_str_opt("id", "N/A");
+    print_int("nb_streams", stg->nb_streams);
+    print_stream_group_params(w, stg);
+
+    if (do_show_stream_group_disposition) {
+        writer_print_section_header(w, NULL, SECTION_ID_STREAM_GROUP_DISPOSITION);
+        PRINT_DISPOSITION(DEFAULT, stg,          "default");
+        PRINT_DISPOSITION(DUB, stg,              "dub");
+        PRINT_DISPOSITION(ORIGINAL, stg,         "original");
+        PRINT_DISPOSITION(COMMENT, stg,          "comment");
+        PRINT_DISPOSITION(LYRICS, stg,           "lyrics");
+        PRINT_DISPOSITION(KARAOKE, stg,          "karaoke");
+        PRINT_DISPOSITION(FORCED, stg,           "forced");
+        PRINT_DISPOSITION(HEARING_IMPAIRED, stg, "hearing_impaired");
+        PRINT_DISPOSITION(VISUAL_IMPAIRED, stg,  "visual_impaired");
+        PRINT_DISPOSITION(CLEAN_EFFECTS, stg,    "clean_effects");
+        PRINT_DISPOSITION(ATTACHED_PIC, stg,     "attached_pic");
+        PRINT_DISPOSITION(TIMED_THUMBNAILS, stg, "timed_thumbnails");
+        PRINT_DISPOSITION(NON_DIEGETIC, stg,     "non_diegetic");
+        PRINT_DISPOSITION(CAPTIONS, stg,         "captions");
+        PRINT_DISPOSITION(DESCRIPTIONS, stg,     "descriptions");
+        PRINT_DISPOSITION(METADATA, stg,         "metadata");
+        PRINT_DISPOSITION(DEPENDENT, stg,        "dependent");
+        PRINT_DISPOSITION(STILL_IMAGE, stg,      "still_image");
+        writer_print_section_footer(w);
+    }
+
+    if (do_show_stream_group_tags)
+        ret = show_tags(w, stg->metadata, SECTION_ID_STREAM_GROUP_TAGS);
+    if (ret < 0)
+        goto end;
+
+    writer_print_section_header(w, NULL, SECTION_ID_STREAM_GROUP_STREAMS);
+    for (i = 0; i < stg->nb_streams; i++) {
+        if (selected_streams[stg->streams[i]->index]) {
+            ret = show_stream(w, fmt_ctx, stg->streams[i]->index, &ifile->streams[stg->streams[i]->index], 0, 1);
+            if (ret < 0)
+                break;
+        }
+    }
+    writer_print_section_footer(w);
+
+end:
+    av_bprint_finalize(&pbuf, NULL);
+    writer_print_section_footer(w);
+    return ret;
+}
+
+static int show_stream_groups(WriterContext *w, InputFile *ifile)
+{
+    AVFormatContext *fmt_ctx = ifile->fmt_ctx;
+    int i, ret = 0;
+
+    writer_print_section_header(w, NULL, SECTION_ID_STREAM_GROUPS);
+    for (i = 0; i < fmt_ctx->nb_stream_groups; i++) {
+        AVStreamGroup *stg = fmt_ctx->stream_groups[i];
+        if (!stg)
+            continue;
+        ret = show_stream_group(w, ifile, stg);
+        if (ret < 0)
+            break;
+    }
+    writer_print_section_footer(w);
+    return ret;
+}
+
 static int show_chapters(WriterContext *w, InputFile *ifile)
 {
     AVFormatContext *fmt_ctx = ifile->fmt_ctx;
@@ -3364,6 +3479,7 @@  static int show_format(WriterContext *w, InputFile *ifile)
     print_str_validate("filename", fmt_ctx->url);
     print_int("nb_streams",       fmt_ctx->nb_streams);
     print_int("nb_programs",      fmt_ctx->nb_programs);
+    print_int("nb_stream_groups", fmt_ctx->nb_stream_groups);
     print_str("format_name",      fmt_ctx->iformat->name);
     if (!do_bitexact) {
         if (fmt_ctx->iformat->long_name) print_str    ("format_long_name", fmt_ctx->iformat->long_name);
@@ -3589,6 +3705,11 @@  static int probe_file(WriterContext *wctx, const char *filename,
         CHECK_END;
     }
 
+    if (do_show_stream_groups) {
+        ret = show_stream_groups(wctx, &ifile);
+        CHECK_END;
+    }
+
     if (do_show_streams) {
         ret = show_streams(wctx, &ifile);
         CHECK_END;
@@ -4087,6 +4208,7 @@  DEFINE_OPT_SHOW_SECTION(pixel_formats,    PIXEL_FORMATS)
 DEFINE_OPT_SHOW_SECTION(program_version,  PROGRAM_VERSION)
 DEFINE_OPT_SHOW_SECTION(streams,          STREAMS)
 DEFINE_OPT_SHOW_SECTION(programs,         PROGRAMS)
+DEFINE_OPT_SHOW_SECTION(stream_groups,    STREAM_GROUPS)
 
 static const OptionDef real_options[] = {
     CMDUTILS_COMMON_OPTIONS
@@ -4117,6 +4239,7 @@  static const OptionDef real_options[] = {
 #endif
     { "show_packets",          OPT_TYPE_FUNC,        0, { .func_arg = &opt_show_packets }, "show packets info" },
     { "show_programs",         OPT_TYPE_FUNC,        0, { .func_arg = &opt_show_programs }, "show programs info" },
+    { "show_stream_groups",    OPT_TYPE_FUNC,        0, { .func_arg = &opt_show_stream_groups }, "show stream groups info" },
     { "show_streams",          OPT_TYPE_FUNC,        0, { .func_arg = &opt_show_streams }, "show streams info" },
     { "show_chapters",         OPT_TYPE_FUNC,        0, { .func_arg = &opt_show_chapters }, "show chapters info" },
     { "count_frames",          OPT_TYPE_BOOL,        0, { &do_count_frames }, "count the number of frames per stream" },
@@ -4201,15 +4324,20 @@  int main(int argc, char **argv)
     SET_DO_SHOW(PIXEL_FORMAT_COMPONENTS, pixel_format_components);
     SET_DO_SHOW(PROGRAM_VERSION, program_version);
     SET_DO_SHOW(PROGRAMS, programs);
+    SET_DO_SHOW(STREAM_GROUPS, stream_groups);
+    SET_DO_SHOW(STREAM_GROUP_DISPOSITION, stream_group_disposition);
     SET_DO_SHOW(STREAMS, streams);
     SET_DO_SHOW(STREAM_DISPOSITION, stream_disposition);
     SET_DO_SHOW(PROGRAM_STREAM_DISPOSITION, stream_disposition);
+    SET_DO_SHOW(STREAM_GROUP_STREAM_DISPOSITION, stream_disposition);
 
     SET_DO_SHOW(CHAPTER_TAGS, chapter_tags);
     SET_DO_SHOW(FORMAT_TAGS, format_tags);
     SET_DO_SHOW(FRAME_TAGS, frame_tags);
     SET_DO_SHOW(PROGRAM_TAGS, program_tags);
+    SET_DO_SHOW(STREAM_GROUP_TAGS, stream_group_tags);
     SET_DO_SHOW(STREAM_TAGS, stream_tags);
+    SET_DO_SHOW(STREAM_GROUP_STREAM_TAGS, stream_tags);
     SET_DO_SHOW(PROGRAM_STREAM_TAGS, stream_tags);
     SET_DO_SHOW(PACKET_TAGS, packet_tags);
 
@@ -4275,7 +4403,7 @@  int main(int argc, char **argv)
             ffprobe_show_pixel_formats(wctx);
 
         if (!input_filename &&
-            ((do_show_format || do_show_programs || do_show_streams || do_show_chapters || do_show_packets || do_show_error) ||
+            ((do_show_format || do_show_programs || do_show_stream_groups || do_show_streams || do_show_chapters || do_show_packets || do_show_error) ||
              (!do_show_program_version && !do_show_library_versions && !do_show_pixel_formats))) {
             show_usage();
             av_log(NULL, AV_LOG_ERROR, "You have to specify one input file.\n");