[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