[FFmpeg-devel] [PATCH] ffprobe: add "-show sections" option.
Nicolas George
george at nsup.org
Sat Jan 11 12:50:58 CET 2014
This syntax is more concise than the various -show_* options
and furthermore allows to control the order of the sections.
Signed-off-by: Nicolas George <george at nsup.org>
---
doc/ffprobe.texi | 23 +++++++++
ffprobe.c | 154 ++++++++++++++++++++++++++++++++++++++++++-------------
2 files changed, 141 insertions(+), 36 deletions(-)
I have to reasons for proposing this patch:
* There is a project I have that that needs the format and streams sections
before the packets, and -show format,streams,packets instead of -show
packets,streams,format seems like a convenient enough way of allowing it.
* As a user, I have found the interaction between the various -show_*
options and the -show_entries option rather confusing. Merging everything
into a single option with a short name and a logical syntax looks like a
good idea. But this is nit yet done.
diff --git a/doc/ffprobe.texi b/doc/ffprobe.texi
index 8de8956..7cdec46 100644
--- a/doc/ffprobe.texi
+++ b/doc/ffprobe.texi
@@ -124,6 +124,29 @@ Show information about the error found when trying to probe the input.
The error information is printed within a section with name "ERROR".
+ at item -show @var{sections}
+Enable showing various informational sections about the file;
+ at var{sections} is a comma-separated list of section names chosen in the
+following list:
+ at code{format},
+ at code{programs},
+ at code{streams},
+ at code{chapters},
+ at code{packets},
+ at code{frames},
+ at code{packets_and_frames}.
+Section names can be abbreviated provided the prefix is unambiguous; since
+new sections can be added later, the prefixes are not guaranteed to stay
+unambiguous.
+
+The sections are printed in the given order. It can make a difference for
+files with streams reconfiguration: printing the format and streams sections
+before reading the packets or frame will show information about the
+beginning of the file while printing them after will show information about
+the end of the file. Sections can be printed several times, but will not
+cause the file to be re-read, so printing frames or packets twice will
+result mostly in empty output.
+
@item -show_format
Show information about the container format of the input multimedia
stream.
diff --git a/ffprobe.c b/ffprobe.c
index ef3bcc6..193c411 100644
--- a/ffprobe.c
+++ b/ffprobe.c
@@ -78,6 +78,8 @@ static int use_byte_value_binary_prefix = 0;
static int use_value_sexagesimal_format = 0;
static int show_private_data = 1;
+static char *opt_show;
+
static char *print_format;
static char *stream_specifier;
@@ -195,6 +197,9 @@ static uint64_t *nb_streams_packets;
static uint64_t *nb_streams_frames;
static int *selected_streams;
+static SectionID do_show[SECTION_MAX_NB_CHILDREN * 5];
+static unsigned do_show_nb = 0;
+
static void ffprobe_cleanup(int ret)
{
int i;
@@ -2351,14 +2356,34 @@ static void close_input_file(AVFormatContext **ctx_ptr)
avformat_close_input(ctx_ptr);
}
+static inline int check_section_show_entries(int section_id);
+static inline void mark_section_show_entries(SectionID section_id,
+ int show_all_entries, AVDictionary *entries);
+
+static int show_packets_and_frames(WriterContext *wctx, AVFormatContext *fmt_ctx,
+ SectionID section_id)
+{
+ int ret;
+
+ do_show_packets = section_id == SECTION_ID_PACKETS_AND_FRAMES || section_id == SECTION_ID_PACKETS;
+ do_show_frames = section_id == SECTION_ID_PACKETS_AND_FRAMES || section_id == SECTION_ID_FRAMES;
+ do_read_frames = do_show_frames || do_count_frames;
+ do_read_packets = do_show_packets || do_count_packets;
+
+ if (do_show_frames || do_show_packets)
+ writer_print_section_header(wctx, section_id);
+ ret = read_packets(wctx, fmt_ctx);
+ if (do_show_frames || do_show_packets)
+ writer_print_section_footer(wctx);
+ return ret;
+}
+
static int probe_file(WriterContext *wctx, const char *filename)
{
AVFormatContext *fmt_ctx;
int ret, i;
int section_id;
-
- do_read_frames = do_show_frames || do_count_frames;
- do_read_packets = do_show_packets || do_count_packets;
+ struct section *sec;
ret = open_input_file(&fmt_ctx, filename);
if (ret < 0)
@@ -2384,38 +2409,38 @@ static int probe_file(WriterContext *wctx, const char *filename)
}
}
- if (do_read_frames || do_read_packets) {
- if (do_show_frames && do_show_packets &&
- wctx->writer->flags & WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER)
- section_id = SECTION_ID_PACKETS_AND_FRAMES;
- else if (do_show_packets && !do_show_frames)
- section_id = SECTION_ID_PACKETS;
- else // (!do_show_packets && do_show_frames)
- section_id = SECTION_ID_FRAMES;
- if (do_show_frames || do_show_packets)
- writer_print_section_header(wctx, section_id);
- ret = read_packets(wctx, fmt_ctx);
- if (do_show_frames || do_show_packets)
- writer_print_section_footer(wctx);
- CHECK_END;
- }
-
- if (do_show_programs) {
- ret = show_programs(wctx, fmt_ctx);
- CHECK_END;
- }
-
- if (do_show_streams) {
- ret = show_streams(wctx, fmt_ctx);
- CHECK_END;
- }
- if (do_show_chapters) {
- ret = show_chapters(wctx, fmt_ctx);
- CHECK_END;
- }
- if (do_show_format) {
- ret = show_format(wctx, fmt_ctx);
- CHECK_END;
+ for (i = 0; i < do_show_nb; i++) {
+ section_id = do_show[i];
+ sec = §ions[section_id];
+ if (!check_section_show_entries(section_id))
+ mark_section_show_entries(section_id, 1, NULL);
+ switch (section_id) {
+ case SECTION_ID_FORMAT:
+ ret = show_format(wctx, fmt_ctx);
+ break;
+ case SECTION_ID_PROGRAMS:
+ ret = show_programs(wctx, fmt_ctx);
+ break;
+ case SECTION_ID_STREAMS:
+ ret = show_streams(wctx, fmt_ctx);
+ break;
+ case SECTION_ID_CHAPTERS:
+ ret = show_chapters(wctx, fmt_ctx);
+ break;
+ case SECTION_ID_PACKETS:
+ case SECTION_ID_FRAMES:
+ case SECTION_ID_PACKETS_AND_FRAMES:
+ case -SECTION_ID_PACKETS_AND_FRAMES:
+ ret = show_packets_and_frames(wctx, fmt_ctx, section_id);
+ break;
+ default:
+ av_log(NULL, AV_LOG_ERROR, "Unknown section to show: %s\n",
+ sec->name);
+ ret = AVERROR(EINVAL);
+ break;
+ }
+ if (ret < 0)
+ goto end;
}
end:
@@ -2834,6 +2859,7 @@ static const OptionDef real_options[] = {
{ "of", OPT_STRING | HAS_ARG, {(void*)&print_format}, "alias for -print_format", "format" },
{ "select_streams", OPT_STRING | HAS_ARG, {(void*)&stream_specifier}, "select the specified streams", "stream_specifier" },
{ "sections", OPT_EXIT, {.func_arg = opt_sections}, "print sections structure and section information, and exit" },
+ { "show", HAS_ARG | OPT_STRING, {(void *)&opt_show}, "select toplevel sections to show" },
{ "show_data", OPT_BOOL, {(void*)&do_show_data}, "show packets data" },
{ "show_error", 0, {(void*)&opt_show_error}, "show probing error" },
{ "show_format", 0, {(void*)&opt_show_format}, "show format/container info" },
@@ -2872,6 +2898,60 @@ static inline int check_section_show_entries(int section_id)
return 0;
}
+static void parse_do_show(void)
+{
+ char *cursor = opt_show, *section;
+ const struct section *const root = §ions[SECTION_ID_ROOT], *sec;
+ SectionID sid, sid_pfx;
+ unsigned sid_pfx_nb, i;
+
+ if (do_show_packets || do_show_frames || do_count_packets || do_count_frames)
+ do_show[do_show_nb++] =
+ do_show_packets && do_show_frames ? SECTION_ID_PACKETS_AND_FRAMES :
+ do_show_packets ? SECTION_ID_PACKETS :
+ do_show_frames ? SECTION_ID_FRAMES :
+ -SECTION_ID_PACKETS_AND_FRAMES;
+ if (do_show_programs)
+ do_show[do_show_nb++] = SECTION_ID_PROGRAMS;
+ if (do_show_streams)
+ do_show[do_show_nb++] = SECTION_ID_STREAMS;
+ if (do_show_format)
+ do_show[do_show_nb++] = SECTION_ID_FORMAT;
+
+ while (section = av_strtok(NULL, ",", &cursor)) {
+ sid = sid_pfx = SECTION_ID_NONE;
+ sid_pfx_nb = 0;
+ for (i = 0; root->children_ids[i] != SECTION_ID_NONE; i++) {
+ sec = §ions[root->children_ids[i]];
+ if (!strcmp(section, sec->name)) {
+ sid = root->children_ids[i];
+ } else if (av_strstart(sec->name, section, NULL)) {
+ sid_pfx = root->children_ids[i];
+ sid_pfx_nb++;
+ }
+ }
+ if (sid == SECTION_ID_NONE && sid_pfx_nb) {
+ if (sid_pfx_nb > 1) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Ambiguous section: '%s'\n", section);
+ exit_program(1);
+ }
+ sid = sid_pfx;
+ }
+ if (sid == SECTION_ID_NONE) {
+ av_log(NULL, AV_LOG_ERROR, "Unknown section: '%s'\n", section);
+ exit_program(1);
+ }
+ if (do_show_nb >= FF_ARRAY_ELEMS(do_show)) {
+ av_log(NULL, AV_LOG_ERROR, "Too many sections to show\n");
+ exit_program(1);
+ }
+ av_log(NULL, AV_LOG_VERBOSE, "Showing section %s\n",
+ sections[sid].name);
+ do_show[do_show_nb++] = sid;
+ }
+}
+
#define SET_DO_SHOW(id, varname) do { \
if (check_section_show_entries(SECTION_ID_##id)) \
do_show_##varname = 1; \
@@ -2919,6 +2999,8 @@ int main(int argc, char **argv)
SET_DO_SHOW(PROGRAM_TAGS, program_tags);
SET_DO_SHOW(STREAM_TAGS, stream_tags);
+ parse_do_show();
+
if (do_bitexact && (do_show_program_version || do_show_library_versions)) {
av_log(NULL, AV_LOG_ERROR,
"-bitexact and -show_program_version or -show_library_versions "
@@ -2958,7 +3040,7 @@ int main(int argc, char **argv)
ffprobe_show_library_versions(wctx);
if (!input_filename &&
- ((do_show_format || do_show_programs || do_show_streams || do_show_chapters || do_show_packets || do_show_error) ||
+ ((do_show_error || do_show_nb) ||
(!do_show_program_version && !do_show_library_versions))) {
show_usage();
av_log(NULL, AV_LOG_ERROR, "You have to specify one input file.\n");
--
1.8.5.2
More information about the ffmpeg-devel
mailing list