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

Clément Bœsch ubitux at gmail.com
Sun Sep 9 12:06:36 CEST 2012


On Sat, Sep 08, 2012 at 05:51:37PM +0200, Stefano Sabatini wrote:
> 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:

Maybe easier to parse for a human mind that way?:

    For example, to show only the index and type of each stream, and the
    PTS time, duration time, and stream index of the packets, 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);

nit: you could merge those two lines

> +            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);

Might be simpler to rely on av_asprintf() like we did in some ffmpeg
options.

> +    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();

Looks OK but I didn't test it. Nice feature.

Note: wouldn't FATE needs some update to avoid the deprecated message?

-- 
Clément B.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 490 bytes
Desc: not available
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20120909/da2b73cf/attachment.asc>


More information about the ffmpeg-devel mailing list