[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