[FFmpeg-devel] [PATCH] ffprobe: add show_entries option

Stefano Sabatini stefasab at gmail.com
Sat Sep 8 17:51:37 CEST 2012


Generalize show_format_entry option.
---
 doc/ffprobe.texi |   21 +++++++++
 ffprobe.c        |  129 ++++++++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 133 insertions(+), 17 deletions(-)

diff --git a/doc/ffprobe.texi b/doc/ffprobe.texi
index cbe48a7..4b693d7 100644
--- a/doc/ffprobe.texi
+++ b/doc/ffprobe.texi
@@ -118,6 +118,27 @@ Like @option{-show_format}, but only prints the specified entry of the
 container format information, rather than all. This option may be given more
 than once, then all specified entries will be shown.
 
+This option is deprecated, use @code{show_entries} instead.
+
+ at item -show_entries @var{entry_list}
+Set list of entries to show.
+
+Entries are specified according to the following syntax:
+ at example
+ at var{SECTION}  ::= @var{SECTION_NAME} "=" | "/" @var{ENTRY}[, at var{ENTRY}]
+ at var{SECTIONS} ::= @var{SECTION}[:@var{SECTIONS}]
+ at end example
+
+ at var{SECTION_NAME} specifies the name of the section where an entry has
+to be found, and @var{ENTRY} the name of the entry in that specific
+section.
+
+For example, to show only the index and type of each stream, and
+packet PTS time, duration time, and stream index, you can specify:
+ at example
+packet=pts_time,duration_time,stream_index : stream=index,codec_type"
+ at end example
+
 @item -show_packets
 Show information about each packet contained in the input multimedia
 stream.
diff --git a/ffprobe.c b/ffprobe.c
index fdff907..e360de8 100644
--- a/ffprobe.c
+++ b/ffprobe.c
@@ -51,13 +51,30 @@ static int do_read_packets = 0;
 static int do_show_error   = 0;
 static int do_show_format  = 0;
 static int do_show_frames  = 0;
-static AVDictionary *fmt_entries_to_show = NULL;
 static int do_show_packets = 0;
 static int do_show_streams = 0;
 static int do_show_data    = 0;
 static int do_show_program_version  = 0;
 static int do_show_library_versions = 0;
 
+struct section_dictionary_map_entry {
+    const char *section;
+    AVDictionary *dict;
+    int *do_show_section_ptr;
+};
+
+static struct section_dictionary_map_entry section_dictionary_map[] = {
+    { "data",             NULL, &do_show_data },
+    { "error",            NULL, &do_show_error },
+    { "format",           NULL, &do_show_format },
+    { "frame",            NULL, &do_show_frames },
+    { "library_version",  NULL, &do_show_library_versions },
+    { "packet",           NULL, &do_show_packets },
+    { "program_version",  NULL, &do_show_program_version },
+    { "stream",           NULL, &do_show_streams },
+    { NULL },
+};
+
 static int show_value_unit              = 0;
 static int use_value_prefix             = 0;
 static int use_byte_value_binary_prefix = 0;
@@ -84,7 +101,9 @@ static uint64_t *nb_streams_frames;
 
 void av_noreturn exit_program(int ret)
 {
-    av_dict_free(&fmt_entries_to_show);
+    struct section_dictionary_map_entry *e;
+    for (e = section_dictionary_map; e->dict; e++)
+        av_dict_free(&e->dict);
     exit(ret);
 }
 
@@ -186,8 +205,8 @@ struct WriterContext {
     unsigned int nb_chapter;        ///< number of the chapter, starting at 0
 
     int multiple_sections;          ///< tells if the current chapter can contain multiple sections
-    int is_fmt_chapter;             ///< tells if the current chapter is "format", required by the print_format_entry option
     int is_packets_and_frames;      ///< tells if the current section is "packets_and_frames"
+    AVDictionary *entries_to_show;  ///< tells which entries should be printed in the current section
 };
 
 static const char *writer_get_name(void *p)
@@ -266,8 +285,6 @@ static inline void writer_print_chapter_header(WriterContext *wctx,
     wctx->multiple_sections = !strcmp(chapter, "packets") || !strcmp(chapter, "frames" ) ||
                               wctx->is_packets_and_frames ||
                               !strcmp(chapter, "streams") || !strcmp(chapter, "library_versions");
-    wctx->is_fmt_chapter = !strcmp(chapter, "format");
-
     if (wctx->writer->print_chapter_header)
         wctx->writer->print_chapter_header(wctx, chapter);
 }
@@ -283,11 +300,19 @@ static inline void writer_print_chapter_footer(WriterContext *wctx,
 static inline void writer_print_section_header(WriterContext *wctx,
                                                const char *section)
 {
+    struct section_dictionary_map_entry *e = NULL;
+
     if (wctx->is_packets_and_frames)
         wctx->nb_section_packet_frame = !strcmp(section, "packet") ? wctx->nb_section_packet
                                                                    : wctx->nb_section_frame;
     if (wctx->writer->print_section_header)
         wctx->writer->print_section_header(wctx, section);
+
+    for (e = section_dictionary_map; e->section; e++)
+        if (!strcmp(section, e->section))
+            break;
+    wctx->entries_to_show = e->dict;
+
     wctx->nb_item = 0;
 }
 
@@ -306,7 +331,7 @@ static inline void writer_print_section_footer(WriterContext *wctx,
 static inline void writer_print_integer(WriterContext *wctx,
                                         const char *key, long long int val)
 {
-    if (!wctx->is_fmt_chapter || !fmt_entries_to_show || av_dict_get(fmt_entries_to_show, key, NULL, 0)) {
+    if (!wctx->entries_to_show || av_dict_get(wctx->entries_to_show, key, NULL, 0)) {
         wctx->writer->print_integer(wctx, key, val);
         wctx->nb_item++;
     }
@@ -316,10 +341,13 @@ static inline void writer_print_rational(WriterContext *wctx,
                                          const char *key, AVRational q, char sep)
 {
     AVBPrint buf;
-    av_bprint_init(&buf, 0, AV_BPRINT_SIZE_AUTOMATIC);
-    av_bprintf(&buf, "%d%c%d", q.num, sep, q.den);
-    wctx->writer->print_string(wctx, key, buf.str);
-    wctx->nb_item++;
+
+    if (!wctx->entries_to_show || av_dict_get(wctx->entries_to_show, key, NULL, 0)) {
+        av_bprint_init(&buf, 0, AV_BPRINT_SIZE_AUTOMATIC);
+        av_bprintf(&buf, "%d%c%d", q.num, sep, q.den);
+        wctx->writer->print_string(wctx, key, buf.str);
+        wctx->nb_item++;
+    }
 }
 
 static inline void writer_print_string(WriterContext *wctx,
@@ -327,7 +355,7 @@ static inline void writer_print_string(WriterContext *wctx,
 {
     if (opt && !(wctx->writer->flags & WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS))
         return;
-    if (!wctx->is_fmt_chapter || !fmt_entries_to_show || av_dict_get(fmt_entries_to_show, key, NULL, 0)) {
+    if (!wctx->entries_to_show || av_dict_get(wctx->entries_to_show, key, NULL, 0)) {
         wctx->writer->print_string(wctx, key, val);
         wctx->nb_item++;
     }
@@ -338,7 +366,7 @@ static void writer_print_time(WriterContext *wctx, const char *key,
 {
     char buf[128];
 
-    if (!wctx->is_fmt_chapter || !fmt_entries_to_show || av_dict_get(fmt_entries_to_show, key, NULL, 0)) {
+    if (!wctx->entries_to_show || av_dict_get(wctx->entries_to_show, key, NULL, 0)) {
         if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0)) {
             writer_print_string(wctx, key, "N/A", 1);
         } else {
@@ -531,7 +559,7 @@ static void default_show_tags(WriterContext *wctx, AVDictionary *dict)
 {
     AVDictionaryEntry *tag = NULL;
     while ((tag = av_dict_get(dict, "", tag, AV_DICT_IGNORE_SUFFIX))) {
-        if (!fmt_entries_to_show || (tag->key && av_dict_get(fmt_entries_to_show, tag->key, NULL, 0)))
+        if (!wctx->entries_to_show || (tag->key && av_dict_get(wctx->entries_to_show, tag->key, NULL, 0)))
             printf("TAG:");
         writer_print_string(wctx, tag->key, tag->value, 0);
     }
@@ -2054,13 +2082,76 @@ static int opt_format(void *optctx, const char *opt, const char *arg)
     return 0;
 }
 
-static int opt_show_format_entry(void *optctx, const char *opt, const char *arg)
+static int opt_show_entries(void *optctx, const char *opt, const char *arg)
 {
-    do_show_format = 1;
-    av_dict_set(&fmt_entries_to_show, arg, "", 0);
+    struct section_dictionary_map_entry *e;
+    const char *p = arg;
+
+    while (*p) {
+        char *section = av_get_token(&p, "/=");
+
+        if (!section) {
+            av_log(NULL, AV_LOG_ERROR,
+                   "Missing section to specify for option '%s'\n",
+                   opt);
+            return AVERROR(EINVAL);
+        }
+
+        for (e = section_dictionary_map; e->section; e++)
+            if (!strcmp(section, e->section)) {
+                *e->do_show_section_ptr = 1;
+                break;
+            }
+
+        if (!e->section) {
+            av_log(NULL, AV_LOG_ERROR,
+                   "Unknown specified section '%s' in argument '%s' for option '%s'\n",
+                   section, arg, opt);
+            av_free(section);
+            return AVERROR(EINVAL);
+        }
+        if (*p)
+            p++; /* skip separator */
+
+#define SKIPSET " \f\t\n\r"
+        while (*p) {
+            char *entry;
+
+            entry = av_get_token(&p, ",:");
+            if (!entry)
+                break;
+            av_dict_set(&e->dict, entry, "", AV_DICT_DONT_STRDUP_KEY);
+            if (*p == ':')
+                break;
+            if (*p)
+                p++;
+        }
+
+        av_free(section);
+
+        if (*p)
+            p++;
+    }
+
     return 0;
 }
 
+static int opt_show_format_entry(void *optctx, const char *opt, const char *arg)
+{
+    AVBPrint buf;
+    int ret;
+
+    av_log(NULL, AV_LOG_WARNING,
+           "Option '%s' is deprecated, use '-show_entries format=%s' instead.\n",
+           opt, arg);
+    av_bprint_init(&buf, 0, AV_BPRINT_SIZE_AUTOMATIC);
+    av_bprintf(&buf, "format=%s", arg);
+
+    ret = opt_show_entries(optctx, opt, buf.str);
+    av_bprint_finalize(&buf, NULL);
+    return ret;
+}
+
 static void opt_input_file(void *optctx, const char *arg)
 {
     if (input_filename) {
@@ -2126,6 +2217,8 @@ static const OptionDef real_options[] = {
     { "show_frames",  OPT_BOOL, {(void*)&do_show_frames} , "show frames info" },
     { "show_format_entry", HAS_ARG, {.func_arg = opt_show_format_entry},
       "show a particular entry from the format/container info", "entry" },
+    { "show_entries", HAS_ARG, {.func_arg = opt_show_entries},
+      "show a set of specified entries", "entry_list" },
     { "show_packets", OPT_BOOL, {&do_show_packets}, "show packets info" },
     { "show_streams", OPT_BOOL, {&do_show_streams}, "show streams info" },
     { "count_frames", OPT_BOOL, {(void*)&do_count_frames}, "count the number of frames per stream" },
@@ -2147,6 +2240,7 @@ int main(int argc, char **argv)
     char *buf;
     char *w_name = NULL, *w_args = NULL;
     int ret;
+    struct section_dictionary_map_entry *e;
 
     av_log_set_flags(AV_LOG_SKIP_REPEATED);
     options = real_options;
@@ -2204,7 +2298,8 @@ end:
     av_freep(&print_format);
 
     uninit_opts();
-    av_dict_free(&fmt_entries_to_show);
+    for (e = section_dictionary_map; e->dict; e++)
+        av_dict_free(&e->dict);
 
     avformat_network_deinit();
 
-- 
1.7.5.4



More information about the ffmpeg-devel mailing list