|
@@ -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,
|
|
@@ -249,6 +260,12 @@ static const char *get_raw_string_type(const void *data)
|
|
|
return data;
|
|
|
}
|
|
|
|
|
|
+static const char *get_stream_group_type(const void *data)
|
|
|
+{
|
|
|
+ const AVStreamGroup *stg = (const AVStreamGroup *)data;
|
|
|
+ return av_x_if_null(avformat_stream_group_name(stg->type), "unknown");
|
|
|
+}
|
|
|
+
|
|
|
static struct section sections[] = {
|
|
|
[SECTION_ID_CHAPTERS] = { SECTION_ID_CHAPTERS, "chapters", SECTION_FLAG_IS_ARRAY, { SECTION_ID_CHAPTER, -1 } },
|
|
|
[SECTION_ID_CHAPTER] = { SECTION_ID_CHAPTER, "chapter", 0, { SECTION_ID_CHAPTER_TAGS, -1 } },
|
|
@@ -290,8 +307,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", SECTION_FLAG_HAS_TYPE, { SECTION_ID_STREAM_GROUP_TAGS, SECTION_ID_STREAM_GROUP_DISPOSITION, SECTION_ID_STREAM_GROUP_STREAMS, -1 }, .get_type = get_stream_group_type },
|
|
|
+ [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 } },
|
|
@@ -3071,7 +3096,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;
|
|
@@ -3081,12 +3109,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,
|
|
|
+ };
|
|
|
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);
|
|
|
|
|
@@ -3248,13 +3293,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);
|
|
@@ -3309,7 +3355,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;
|
|
|
}
|
|
@@ -3339,6 +3385,71 @@ static int show_programs(WriterContext *w, InputFile *ifile)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static void print_stream_group_params(WriterContext *w, AVStreamGroup *stg)
|
|
|
+{
|
|
|
+ const char *unknown = "unknown";
|
|
|
+ if (stg->type != AV_STREAM_GROUP_PARAMS_NONE)
|
|
|
+ print_str("type", av_x_if_null(avformat_stream_group_name(stg->type), unknown));
|
|
|
+ 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, stg, 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];
|
|
|
+
|
|
|
+ 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;
|
|
@@ -3375,6 +3486,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);
|
|
@@ -3600,6 +3712,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;
|
|
@@ -4098,6 +4215,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
|
|
@@ -4128,6 +4246,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" },
|
|
@@ -4212,16 +4331,21 @@ 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_GROUP_DISPOSITION, stream_group_disposition);
|
|
|
+ SET_DO_SHOW(STREAM_GROUPS, stream_groups);
|
|
|
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(PROGRAM_STREAM_TAGS, stream_tags);
|
|
|
+ SET_DO_SHOW(STREAM_GROUP_STREAM_TAGS, stream_tags);
|
|
|
SET_DO_SHOW(PACKET_TAGS, packet_tags);
|
|
|
|
|
|
if (do_bitexact && (do_show_program_version || do_show_library_versions)) {
|
|
@@ -4286,7 +4410,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");
|