[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 = &sections[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 = &sections[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 = &sections[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