[FFmpeg-devel] [PATCH] ffprobe: add show_entries option
Clément Bœsch
ubitux at gmail.com
Tue Nov 20 21:07:55 CET 2012
On Tue, Nov 20, 2012 at 12:21:02AM +0100, Stefano Sabatini wrote:
> On date Thursday 2012-09-13 22:53:56 +0200, Stefano Sabatini encoded:
[...]
> Simplified with the use of unique names.
> --
> FFmpeg = Free & Friendly Moronic Power Elegant God
> From 2654af4fd2a971af9dec1e5e3824b05a2f75a852 Mon Sep 17 00:00:00 2001
> From: Stefano Sabatini <stefasab at gmail.com>
> Date: Mon, 17 Sep 2012 21:08:09 +0200
> Subject: [PATCH] ffprobe: implement subsection field selection
>
> ---
> doc/ffprobe.texi | 42 ++++++++++
> ffprobe.c | 227 +++++++++++++++++++++++++++++++++++++++++++-----------
> 2 files changed, 224 insertions(+), 45 deletions(-)
>
> diff --git a/doc/ffprobe.texi b/doc/ffprobe.texi
> index 7b47fba..39322cd 100644
> --- a/doc/ffprobe.texi
> +++ b/doc/ffprobe.texi
> @@ -133,6 +133,48 @@ 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{section_entries}
> +Set list of entries to show.
> +
> +Entries are specified according to the following
> +syntax. @var{section_entries} contains a list of section entries
> +separated by @code{:}. Each section entry is composed by a section
> +name (or unique name), optionally followed by a list of entries local
> +to that section, separated by @code{,}.
> +
> +If section name is specified but is followed by no @code{=}, all
> +entries are printed to output, together with all the contained
> +sections. Otherwise only the entries specified in the local section
> +entries list are printed. In particular, if @code{=} is specified but
> +the list of local entries is empty, then no entries will be shown for
> +that section.
> +
> +Note that the order of specification of the local section entries is
> +not honored in the output, and the usual display order will be
> +reatained.
> +
retained?
> +The formal syntax is given by:
> + at example
> + at var{LOCAL_SECTION_ENTRIES} ::= @var{SECTION_ENTRY_NAME}[, at var{LOCAL_SECTION_ENTRIES}]
> + at var{SECTION_ENTRY} ::= @var{SECTION_NAME}[=[@var{LOCAL_SECTION_ENTRIES}]]
> + at var{SECTION_ENTRIES} ::= @var{SECTION_ENTRY}[:@var{SECTION_ENTRIES}]
> + at end example
> +
> +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
> +the argument:
> + at example
> +"packet=pts_time,duration_time,stream_index : stream=index,codec_type"
> + at end example
> +
> +To show all the entries in the section "format", but only the codec
> +type in the section "stream", specify the argument:
> + at example
> +"format : stream=codec_type"
> + at end example
> +
Can we use that for tags/metadata?
> @item -show_packets
> Show information about each packet contained in the input multimedia
> stream.
> diff --git a/ffprobe.c b/ffprobe.c
> index 748a4b9..5c3a47c 100644
> --- a/ffprobe.c
> +++ b/ffprobe.c
> @@ -55,7 +55,6 @@ 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;
> @@ -73,16 +72,22 @@ static char *stream_specifier;
>
> /* section structure definition */
>
> +#define SECTION_MAX_NB_PARENTS 2
> +#define SECTION_MAX_NB_CHILDREN 10
> +
> struct section {
> int id; ///< unique id indentifying a section
> const char *name;
> -
> #define SECTION_FLAG_IS_WRAPPER 1 ///< the section only contains other sections, but has no data at its own level
> #define SECTION_FLAG_IS_ARRAY 2 ///< the section contains an array of elements of the same type
> #define SECTION_FLAG_HAS_VARIABLE_FIELDS 4 ///< the section may contain a variable number of fields with variable keys.
> /// For these sections the element_name field is mandatory.
> int flags;
> + int children_ids[SECTION_MAX_NB_CHILDREN+1]; ///< list of children section IDS, terminated by -1
> const char *element_name; ///< name of the contained element, if provided
> + const char *unique_name; ///< unique section name, in case the name is ambiguous
> + AVDictionary *entries_to_show;
> + int show_all_entries;
> };
>
> typedef enum {
> @@ -103,27 +108,29 @@ typedef enum {
> SECTION_ID_STREAM,
> SECTION_ID_STREAM_DISPOSITION,
> SECTION_ID_STREAMS,
> - SECTION_ID_STREAM_TAGS
> + SECTION_ID_STREAM_TAGS,
> } SectionID;
>
> -static const struct section sections[] = {
> - [SECTION_ID_ERROR] = { SECTION_ID_ERROR, "error" },
> - [SECTION_ID_FORMAT] = { SECTION_ID_FORMAT, "format" },
> - [SECTION_ID_FORMAT_TAGS] = { SECTION_ID_FORMAT_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, .element_name = "tag" },
> - [SECTION_ID_FRAME] = { SECTION_ID_FRAME, "frame" },
> - [SECTION_ID_FRAMES] = { SECTION_ID_FRAMES, "frames", SECTION_FLAG_IS_ARRAY },
> - [SECTION_ID_FRAME_TAGS] = { SECTION_ID_FRAME_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, .element_name = "tag" },
> - [SECTION_ID_LIBRARY_VERSION] = { SECTION_ID_LIBRARY_VERSION, "library_version" },
> - [SECTION_ID_LIBRARY_VERSIONS] = { SECTION_ID_LIBRARY_VERSIONS, "library_versions", SECTION_FLAG_IS_ARRAY },
> - [SECTION_ID_PACKET] = { SECTION_ID_PACKET, "packet" },
> - [SECTION_ID_PACKETS] = { SECTION_ID_PACKETS, "packets", SECTION_FLAG_IS_ARRAY },
> - [SECTION_ID_PACKETS_AND_FRAMES] = { SECTION_ID_PACKETS_AND_FRAMES, "packets_and_frames", SECTION_FLAG_IS_ARRAY },
> - [SECTION_ID_PROGRAM_VERSION] = { SECTION_ID_PROGRAM_VERSION, "program_version" },
> - [SECTION_ID_ROOT] = { SECTION_ID_ROOT, "root", SECTION_FLAG_IS_WRAPPER },
> - [SECTION_ID_STREAM] = { SECTION_ID_STREAM, "stream" },
> - [SECTION_ID_STREAM_DISPOSITION] = { SECTION_ID_STREAM_DISPOSITION, "disposition" },
> - [SECTION_ID_STREAMS] = { SECTION_ID_STREAMS, "streams", SECTION_FLAG_IS_ARRAY },
> - [SECTION_ID_STREAM_TAGS] = { SECTION_ID_STREAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, .element_name = "tag" },
> +static struct section sections[] = {
> + [SECTION_ID_ERROR] = { SECTION_ID_ERROR, "error", 0, { -1 } },
> + [SECTION_ID_FORMAT] = { SECTION_ID_FORMAT, "format", 0, { SECTION_ID_FORMAT_TAGS, -1 } },
> + [SECTION_ID_FORMAT_TAGS] = { SECTION_ID_FORMAT_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "format_tags" },
> + [SECTION_ID_FRAMES] = { SECTION_ID_FRAMES, "frames", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME, -1 } },
> + [SECTION_ID_FRAME] = { SECTION_ID_FRAME, "frame", 0, { SECTION_ID_FRAME_TAGS, -1 } },
> + [SECTION_ID_FRAME_TAGS] = { SECTION_ID_FRAME_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "frame_tags" },
> + [SECTION_ID_LIBRARY_VERSIONS] = { SECTION_ID_LIBRARY_VERSIONS, "library_versions", SECTION_FLAG_IS_ARRAY, { SECTION_ID_LIBRARY_VERSION, -1 } },
> + [SECTION_ID_LIBRARY_VERSION] = { SECTION_ID_LIBRARY_VERSION, "library_version", 0, { -1 } },
> + [SECTION_ID_PACKETS] = { SECTION_ID_PACKETS, "packets", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET, -1} },
> + [SECTION_ID_PACKETS_AND_FRAMES] = { SECTION_ID_PACKETS_AND_FRAMES, "packets_and_frames", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET, -1} },
> + [SECTION_ID_PACKET] = { SECTION_ID_PACKET, "packet", 0, { -1 } },
> + [SECTION_ID_PROGRAM_VERSION] = { SECTION_ID_PROGRAM_VERSION, "program_version", 0, { -1 } },
> + [SECTION_ID_ROOT] = { SECTION_ID_ROOT, "root", SECTION_FLAG_IS_WRAPPER,
> + { SECTION_ID_FORMAT, SECTION_ID_FRAMES, SECTION_ID_STREAMS, SECTION_ID_PACKETS,
> + SECTION_ID_ERROR, SECTION_ID_PROGRAM_VERSION, SECTION_ID_LIBRARY_VERSIONS, -1} },
> + [SECTION_ID_STREAMS] = { SECTION_ID_STREAMS, "streams", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM, -1 } },
> + [SECTION_ID_STREAM] = { SECTION_ID_STREAM, "stream", 0, { SECTION_ID_STREAM_DISPOSITION, SECTION_ID_STREAM_TAGS, -1 } },
> + [SECTION_ID_STREAM_DISPOSITION] = { SECTION_ID_STREAM, "disposition", 0, { -1 }, .unique_name = "stream_disposition" },
> + [SECTION_ID_STREAM_TAGS] = { SECTION_ID_STREAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "stream_tags" },
> };
>
> static const OptionDef *options;
> @@ -146,7 +153,6 @@ static int *selected_streams;
>
> static void exit_program(void)
> {
> - av_dict_free(&fmt_entries_to_show);
> }
>
> struct unit_value {
> @@ -237,7 +243,7 @@ struct WriterContext {
> char *name; ///< name of this writer instance
> void *priv; ///< private data for use by the filter
>
> - const struct section *sections; ///< array containing all sections
> + struct section *sections; ///< array containing all sections
> int nb_sections; ///< number of sections
>
> int level; ///< current level, starting from 0
> @@ -246,10 +252,9 @@ struct WriterContext {
> unsigned int nb_item[SECTION_MAX_NB_LEVELS];
>
> /** section per each level */
> - const struct section *section[SECTION_MAX_NB_LEVELS];
> + struct section *section[SECTION_MAX_NB_LEVELS];
> AVBPrint section_pbuf[SECTION_MAX_NB_LEVELS]; ///< generic print buffer dedicated to each section,
> /// used by various writers
> -
> unsigned int nb_section_packet; ///< number of the packet section in case we are in "packets_and_frames" section
> unsigned int nb_section_frame; ///< number of the frame section in case we are in "packets_and_frames" section
> unsigned int nb_section_packet_frame; ///< nb_section_packet or nb_section_frame according if is_packets_and_frames
> @@ -286,7 +291,7 @@ static void writer_close(WriterContext **wctx)
> }
>
> static int writer_open(WriterContext **wctx, const Writer *writer, const char *args,
> - const struct section *sections, int nb_sections)
> + struct section *sections, int nb_sections)
> {
> int i, ret = 0;
>
> @@ -375,9 +380,9 @@ 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->section[wctx->level]->id != SECTION_ID_FORMAT
> - && wctx->section[wctx->level]->id != SECTION_ID_FORMAT_TAGS) ||
> - !fmt_entries_to_show || av_dict_get(fmt_entries_to_show, key, NULL, 0)) {
> + struct section *section = wctx->section[wctx->level];
> +
looks like it can be const
> + if (section->show_all_entries || av_dict_get(section->entries_to_show, key, NULL, 0)) {
> wctx->writer->print_integer(wctx, key, val);
> wctx->nb_item[wctx->level]++;
> }
> @@ -386,11 +391,12 @@ static inline void writer_print_integer(WriterContext *wctx,
> static inline void writer_print_string(WriterContext *wctx,
> const char *key, const char *val, int opt)
> {
> + struct section *section = wctx->section[wctx->level];
> +
here as well
> if (opt && !(wctx->writer->flags & WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS))
> return;
> - if ((wctx->section[wctx->level]->id != SECTION_ID_FORMAT
> - && wctx->section[wctx->level]->id != SECTION_ID_FORMAT_TAGS) ||
> - !fmt_entries_to_show || av_dict_get(fmt_entries_to_show, key, NULL, 0)) {
> +
> + if (section->show_all_entries || av_dict_get(section->entries_to_show, key, NULL, 0)) {
> wctx->writer->print_string(wctx, key, val);
> wctx->nb_item[wctx->level]++;
> }
> @@ -1958,11 +1964,100 @@ static int opt_format(void *optctx, const char *opt, const char *arg)
> return 0;
> }
>
> +static inline void mark_section_show_entries(SectionID section_id,
> + int show_all_entries, AVDictionary *entries)
> +{
> + struct section *section = §ions[section_id];
> +
> + section->show_all_entries = show_all_entries;
> + if (show_all_entries) {
> + SectionID *id;
> + for (id = section->children_ids; *id != -1; id++)
> + mark_section_show_entries(*id, show_all_entries, entries);
> + } else {
> + av_dict_copy(§ion->entries_to_show, entries, 0);
> + }
> +}
> +
> +static int match_section(const char *section_name,
> + int show_all_entries, AVDictionary *entries)
> +{
> + int i, ret = 0;
> +
> + for (i = 0; i < FF_ARRAY_ELEMS(sections); i++) {
> + struct section *section = §ions[i];
ditto
[...]
Anyway, LGTM, nice work, thanks.
--
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/20121120/3c3649e8/attachment.asc>
More information about the ffmpeg-devel
mailing list