From: Stefano Sabatini <stefasab@gmail.com> To: FFmpeg development discussions and patches <ffmpeg-devel@ffmpeg.org> Subject: Re: [FFmpeg-devel] [PATCH 1/8 v2] fftools/ffprobe: add support for Stream Groups Date: Mon, 4 Mar 2024 11:34:12 +0100 Message-ID: <ZeWjpMOTgPfSoruF@mariano> (raw) In-Reply-To: <20240303180929.56930-1-jamrial@gmail.com> On date Sunday 2024-03-03 15:09:19 -0300, James Almer wrote: > Signed-off-by: James Almer <jamrial@gmail.com> > --- > doc/ffprobe.xsd | 1 + > fftools/ffprobe.c | 145 ++++++++++++++++-- > tests/ref/fate/cavs-demux | 2 +- > tests/ref/fate/ffprobe_compact | 2 +- > tests/ref/fate/ffprobe_csv | 2 +- > tests/ref/fate/ffprobe_default | 1 + > tests/ref/fate/ffprobe_flat | 1 + > tests/ref/fate/ffprobe_ini | 1 + > tests/ref/fate/ffprobe_json | 1 + > tests/ref/fate/ffprobe_xml | 2 +- > tests/ref/fate/ffprobe_xsd | 2 +- > tests/ref/fate/flv-demux | 2 +- > tests/ref/fate/gapless-mp3-side-data | 2 +- > .../ref/fate/mov-mp4-disposition-mpegts-remux | 3 + > tests/ref/fate/mov-mp4-ttml-dfxp | 3 + > tests/ref/fate/mov-mp4-ttml-stpp | 3 + > tests/ref/fate/oggopus-demux | 2 +- > tests/ref/fate/ts-demux | 2 +- > tests/ref/fate/ts-opus-demux | 2 +- > tests/ref/fate/ts-small-demux | 2 +- > tests/ref/fate/ts-timed-id3-demux | 2 +- > 21 files changed, 160 insertions(+), 23 deletions(-) > > diff --git a/doc/ffprobe.xsd b/doc/ffprobe.xsd > index 23d97ed11a..08f2909c02 100644 > --- a/doc/ffprobe.xsd > +++ b/doc/ffprobe.xsd > @@ -305,6 +305,7 @@ > <xsd:attribute name="filename" type="xsd:string" use="required"/> > <xsd:attribute name="nb_streams" type="xsd:int" use="required"/> > <xsd:attribute name="nb_programs" type="xsd:int" use="required"/> > + <xsd:attribute name="nb_stream_groups" type="xsd:int" use="required"/> > <xsd:attribute name="format_name" type="xsd:string" use="required"/> > <xsd:attribute name="format_long_name" type="xsd:string"/> > <xsd:attribute name="start_time" type="xsd:float"/> do we also need to add a new type for the stream group? > diff --git a/fftools/ffprobe.c b/fftools/ffprobe.c > index ac6b92f5d6..548c5e0948 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, > @@ -203,6 +206,14 @@ typedef enum { > SECTION_ID_PROGRAM_TAGS, > SECTION_ID_PROGRAM_VERSION, > SECTION_ID_PROGRAMS, > + 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_ROOT, > SECTION_ID_STREAM, > SECTION_ID_STREAM_DISPOSITION, > @@ -285,8 +296,16 @@ static struct section sections[] = { > [SECTION_ID_PROGRAM_TAGS] = { SECTION_ID_PROGRAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "program_tags" }, > [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_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_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 } }, > @@ -3051,7 +3070,10 @@ static void print_dispositions(WriterContext *w, uint32_t disposition, SectionID > writer_print_section_footer(w); > } > > -static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_idx, InputStream *ist, int in_program) > +#define IN_PROGRAM 1 > +#define IN_STREAM_GROUP 2 > + > +static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_idx, InputStream *ist, int container) > { > AVStream *stream = ist->st; > AVCodecParameters *par; > @@ -3061,12 +3083,29 @@ static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_id > AVRational sar, dar; > AVBPrint pbuf; > const AVCodecDescriptor *cd; > + const SectionID section_header[] = { > + SECTION_ID_STREAM, > + SECTION_ID_PROGRAM_STREAM, > + SECTION_ID_STREAM_GROUP_STREAM, > + }; > + const SectionID section_disposition[] = { > + SECTION_ID_STREAM_DISPOSITION, > + SECTION_ID_PROGRAM_STREAM_DISPOSITION, > + SECTION_ID_STREAM_GROUP_STREAM_DISPOSITION, > + }; > + const SectionID section_tags[] = { > + SECTION_ID_STREAM_TAGS, > + SECTION_ID_PROGRAM_STREAM_TAGS, > + SECTION_ID_STREAM_GROUP_STREAM_TAGS, > + }; what about something as: typedef struct { SectionID stream; SectionID disposition; SectionID tags; } StreamContainerSectionsIds; static const StreamContainerSectionsIds stream_container_sections_ids = { SECTION_ID_STREAM, SECTION_ID_STREAM_DISPOSITION, SECTION_ID_STREAM_TAGS }; static const StreamContainerSectionsIds program_stream_container_sections_ids = { SECTION_ID_PROGRAM_STREAM, SECTION_ID_PROGRAM_STREAM_DISPOSITION, SECTION_ID_PROGRAM_STREAM_TAGS }; static const StreamContainerSectionsIds stream_group_container_sections_ids = { SECTION_ID_STREAM_GROUP_STREAM, SECTION_ID_STREAM_GROUP_STREAM_DISPOSITION, SECTION_ID_STREAM_GROUP_STREAM_TAGS }; static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, stream_idx, InputStream *ist, StreamContainerSectionsIds *sections_ids) ... this is probably a bit longer but should be more robust > int ret = 0; > const char *profile = NULL; > > + av_assert0(container < FF_ARRAY_ELEMS(section_header)); > + > 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[container]); > > print_int("index", stream->index); > > @@ -3228,13 +3267,14 @@ static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_id > > /* Print disposition information */ > if (do_show_stream_disposition) { > - print_dispositions(w, stream->disposition, > - in_program ? SECTION_ID_PROGRAM_STREAM_DISPOSITION > - : SECTION_ID_STREAM_DISPOSITION); > + av_assert0(container < FF_ARRAY_ELEMS(section_disposition)); > + print_dispositions(w, stream->disposition, section_disposition[container]); > } > > - if (do_show_stream_tags) > - ret = show_tags(w, stream->metadata, in_program ? SECTION_ID_PROGRAM_STREAM_TAGS : SECTION_ID_STREAM_TAGS); > + if (do_show_stream_tags) { > + av_assert0(container < FF_ARRAY_ELEMS(section_tags)); > + ret = show_tags(w, stream->metadata, section_tags[container]); > + } > > if (stream->codecpar->nb_coded_side_data) { > writer_print_section_header(w, NULL, SECTION_ID_STREAM_SIDE_DATA_LIST); > @@ -3289,7 +3329,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]], IN_PROGRAM); > if (ret < 0) > break; > } > @@ -3319,6 +3359,76 @@ static int show_programs(WriterContext *w, InputFile *ifile) > return ret; > } > > + nit++: drop double empty line > +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"); nit: you can factorize type to avoid multiple print_str() > +} > + > +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); > + > + /* Print disposition information */ > + if (do_show_stream_group_disposition) > + print_dispositions(w, stg->disposition, SECTION_ID_STREAM_GROUP_DISPOSITION); > + > + 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], IN_STREAM_GROUP); > + 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; > @@ -3355,6 +3465,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); > @@ -3580,6 +3691,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; > @@ -4078,6 +4194,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 > @@ -4108,6 +4225,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" }, Missing documentation update, also probably we want to advertise the new option in the Changelog. Thanks. _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
prev parent reply other threads:[~2024-03-04 10:34 UTC|newest] Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top 2024-03-03 18:09 James Almer 2024-03-03 18:09 ` [FFmpeg-devel] [PATCH 2/8] fftools/ffprobe: print some basic Tile Grid Stream Group parameters James Almer 2024-03-03 18:09 ` [FFmpeg-devel] [PATCH 3/8] fate/iamf: print stream group information James Almer 2024-03-03 18:09 ` [FFmpeg-devel] [PATCH 4/8] avformat/mov: fix setting disposition for the first iamf stream James Almer 2024-03-03 18:09 ` [FFmpeg-devel] [PATCH 5/8] fate/mov: print stream group information for iamf tests James Almer 2024-03-03 18:09 ` [FFmpeg-devel] [PATCH 6/8] avformat/mov: don't mark an item referenced by a grid as dependent if it's the primary item James Almer 2024-03-03 18:09 ` [FFmpeg-devel] [PATCH 7/8] fate/mov: print stream group information for avif/heic tests James Almer 2024-03-03 20:13 ` [FFmpeg-devel] [PATCH 7/8 v2] " James Almer 2024-03-03 18:09 ` [FFmpeg-devel] [PATCH 8/8] fate/mov: use framecrc for the remaining " James Almer 2024-03-04 10:34 ` Stefano Sabatini [this message]
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=ZeWjpMOTgPfSoruF@mariano \ --to=stefasab@gmail.com \ --cc=ffmpeg-devel@ffmpeg.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel This inbox may be cloned and mirrored by anyone: git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git # If you have public-inbox 1.1+ installed, you may # initialize and index your mirror using the following commands: public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \ ffmpegdev@gitmailbox.com public-inbox-index ffmpegdev Example config snippet for mirrors. AGPL code for this site: git clone https://public-inbox.org/public-inbox.git