mpeg1enc: check input dimensions
[ffmpeg.git] / ffprobe.c
index 80eace9..84f7d82 100644 (file)
--- a/ffprobe.c
+++ b/ffprobe.c
@@ -29,6 +29,7 @@
 #include "libavformat/avformat.h"
 #include "libavcodec/avcodec.h"
 #include "libavutil/avstring.h"
+#include "libavutil/bprint.h"
 #include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
 #include "libavutil/dict.h"
@@ -49,6 +50,7 @@ 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_program_version  = 0;
@@ -80,6 +82,7 @@ static uint64_t *nb_streams_frames;
 
 void av_noreturn exit_program(int ret)
 {
+    av_dict_free(&fmt_entries_to_show);
     exit(ret);
 }
 
@@ -262,24 +265,30 @@ static inline void writer_print_chapter_footer(WriterContext *wctx,
 static inline void writer_print_section_header(WriterContext *wctx,
                                                const char *section)
 {
-    if (wctx->writer->print_section_header)
-        wctx->writer->print_section_header(wctx, section);
-    wctx->nb_item = 0;
+    if (!fmt_entries_to_show || (section && av_dict_get(fmt_entries_to_show, section, NULL, 0))) {
+        if (wctx->writer->print_section_header)
+            wctx->writer->print_section_header(wctx, section);
+        wctx->nb_item = 0;
+    }
 }
 
 static inline void writer_print_section_footer(WriterContext *wctx,
                                                const char *section)
 {
-    if (wctx->writer->print_section_footer)
-        wctx->writer->print_section_footer(wctx, section);
-    wctx->nb_section++;
+    if (!fmt_entries_to_show || (section && av_dict_get(fmt_entries_to_show, section, NULL, 0))) {
+        if (wctx->writer->print_section_footer)
+            wctx->writer->print_section_footer(wctx, section);
+        wctx->nb_section++;
+    }
 }
 
 static inline void writer_print_integer(WriterContext *wctx,
                                         const char *key, long long int val)
 {
-    wctx->writer->print_integer(wctx, key, val);
-    wctx->nb_item++;
+    if (!fmt_entries_to_show || (key && av_dict_get(fmt_entries_to_show, key, NULL, 0))) {
+        wctx->writer->print_integer(wctx, key, val);
+        wctx->nb_item++;
+    }
 }
 
 static inline void writer_print_string(WriterContext *wctx,
@@ -287,8 +296,10 @@ static inline void writer_print_string(WriterContext *wctx,
 {
     if (opt && !(wctx->writer->flags & WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS))
         return;
-    wctx->writer->print_string(wctx, key, val);
-    wctx->nb_item++;
+    if (!fmt_entries_to_show || (key && av_dict_get(fmt_entries_to_show, key, NULL, 0))) {
+        wctx->writer->print_string(wctx, key, val);
+        wctx->nb_item++;
+    }
 }
 
 static void writer_print_time(WriterContext *wctx, const char *key,
@@ -296,12 +307,14 @@ static void writer_print_time(WriterContext *wctx, const char *key,
 {
     char buf[128];
 
-    if (ts == AV_NOPTS_VALUE) {
-        writer_print_string(wctx, key, "N/A", 1);
-    } else {
-        double d = ts * av_q2d(*time_base);
-        value_string(buf, sizeof(buf), (struct unit_value){.val.d=d, .unit=unit_second_str});
-        writer_print_string(wctx, key, buf, 0);
+    if (!fmt_entries_to_show || (key && av_dict_get(fmt_entries_to_show, key, NULL, 0))) {
+        if (ts == AV_NOPTS_VALUE) {
+            writer_print_string(wctx, key, "N/A", 1);
+        } else {
+            double d = ts * av_q2d(*time_base);
+            value_string(buf, sizeof(buf), (struct unit_value){.val.d=d, .unit=unit_second_str});
+            writer_print_string(wctx, key, buf, 0);
+        }
     }
 }
 
@@ -384,31 +397,6 @@ fail:
     return NULL;
 }
 
-#define ESCAPE_INIT_BUF_SIZE 256
-
-#define ESCAPE_CHECK_SIZE(src, size, max_size)                          \
-    if (size > max_size) {                                              \
-        char buf[64];                                                   \
-        snprintf(buf, sizeof(buf), "%s", src);                          \
-        av_log(log_ctx, AV_LOG_WARNING,                                 \
-               "String '%s...' is too big\n", buf);                     \
-        return "FFPROBE_TOO_BIG_STRING";                                \
-    }
-
-#define ESCAPE_REALLOC_BUF(dst_size_p, dst_p, src, size)                \
-    if (*dst_size_p < size) {                                           \
-        char *q = av_realloc(*dst_p, size);                             \
-        if (!q) {                                                       \
-            char buf[64];                                               \
-            snprintf(buf, sizeof(buf), "%s", src);                      \
-            av_log(log_ctx, AV_LOG_WARNING,                             \
-                   "String '%s...' could not be escaped\n", buf);       \
-            return "FFPROBE_THIS_STRING_COULD_NOT_BE_ESCAPED";          \
-        }                                                               \
-        *dst_size_p = size;                                             \
-        *dst = q;                                                       \
-    }
-
 /* WRITERS */
 
 /* Default output */
@@ -464,7 +452,8 @@ static void default_show_tags(WriterContext *wctx, AVDictionary *dict)
 {
     AVDictionaryEntry *tag = NULL;
     while ((tag = av_dict_get(dict, "", tag, AV_DICT_IGNORE_SUFFIX))) {
-        printf("TAG:");
+        if (!fmt_entries_to_show || (tag->key && av_dict_get(fmt_entries_to_show, tag->key, NULL, 0)))
+            printf("TAG:");
         writer_print_string(wctx, tag->key, tag->value, 0);
     }
 }
@@ -487,81 +476,51 @@ static const Writer default_writer = {
  * Escape \n, \r, \\ and sep characters contained in s, and print the
  * resulting string.
  */
-static const char *c_escape_str(char **dst, size_t *dst_size,
-                                const char *src, const char sep, void *log_ctx)
+static const char *c_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
 {
     const char *p;
-    char *q;
-    size_t size = 1;
-
-    /* precompute size */
-    for (p = src; *p; p++, size++) {
-        ESCAPE_CHECK_SIZE(src, size, SIZE_MAX-2);
-        if (*p == '\n' || *p == '\r' || *p == '\\')
-            size++;
-    }
-
-    ESCAPE_REALLOC_BUF(dst_size, dst, src, size);
 
-    q = *dst;
     for (p = src; *p; p++) {
         switch (*src) {
-        case '\n': *q++ = '\\'; *q++ = 'n';  break;
-        case '\r': *q++ = '\\'; *q++ = 'r';  break;
-        case '\\': *q++ = '\\'; *q++ = '\\'; break;
+        case '\n': av_bprintf(dst, "%s", "\\n");  break;
+        case '\r': av_bprintf(dst, "%s", "\\r");  break;
+        case '\\': av_bprintf(dst, "%s", "\\\\"); break;
         default:
             if (*p == sep)
-                *q++ = '\\';
-            *q++ = *p;
+                av_bprint_chars(dst, '\\', 1);
+            av_bprint_chars(dst, *p, 1);
         }
     }
-    *q = 0;
-    return *dst;
+    return dst->str;
 }
 
 /**
  * Quote fields containing special characters, check RFC4180.
  */
-static const char *csv_escape_str(char **dst, size_t *dst_size,
-                                  const char *src, const char sep, void *log_ctx)
+static const char *csv_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
 {
     const char *p;
-    char *q;
-    size_t size = 1;
     int quote = 0;
 
-    /* precompute size */
-    for (p = src; *p; p++, size++) {
-        ESCAPE_CHECK_SIZE(src, size, SIZE_MAX-4);
+    /* check if input needs quoting */
+    for (p = src; *p; p++)
         if (*p == '"' || *p == sep || *p == '\n' || *p == '\r')
-            if (!quote) {
-                quote = 1;
-                size += 2;
-            }
-        if (*p == '"')
-            size++;
-    }
+            quote = 1;
 
-    ESCAPE_REALLOC_BUF(dst_size, dst, src, size);
-
-    q = *dst;
-    p = src;
     if (quote)
-        *q++ = '\"';
-    while (*p) {
+        av_bprint_chars(dst, '\"', 1);
+
+    for (p = src; *p; p++) {
         if (*p == '"')
-            *q++ = '\"';
-        *q++ = *p++;
+            av_bprint_chars(dst, '\"', 1);
+        av_bprint_chars(dst, *p, 1);
     }
     if (quote)
-        *q++ = '\"';
-    *q = 0;
-
-    return *dst;
+        av_bprint_chars(dst, '\"', 1);
+    return dst->str;
 }
 
-static const char *none_escape_str(char **dst, size_t *dst_size,
-                                   const char *src, const char sep, void *log_ctx)
+static const char *none_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
 {
     return src;
 }
@@ -571,11 +530,8 @@ typedef struct CompactContext {
     char *item_sep_str;
     char item_sep;
     int nokey;
-    char  *buf;
-    size_t buf_size;
     char *escape_mode_str;
-    const char * (*escape_str)(char **dst, size_t *dst_size,
-                               const char *src, const char sep, void *log_ctx);
+    const char * (*escape_str)(AVBPrint *dst, const char *src, const char sep, void *log_ctx);
 } CompactContext;
 
 #define OFFSET(x) offsetof(CompactContext, x)
@@ -621,10 +577,6 @@ static av_cold int compact_init(WriterContext *wctx, const char *args, void *opa
     }
     compact->item_sep = compact->item_sep_str[0];
 
-    compact->buf_size = ESCAPE_INIT_BUF_SIZE;
-    if (!(compact->buf = av_malloc(compact->buf_size)))
-        return AVERROR(ENOMEM);
-
     if      (!strcmp(compact->escape_mode_str, "none")) compact->escape_str = none_escape_str;
     else if (!strcmp(compact->escape_mode_str, "c"   )) compact->escape_str = c_escape_str;
     else if (!strcmp(compact->escape_mode_str, "csv" )) compact->escape_str = csv_escape_str;
@@ -641,7 +593,6 @@ static av_cold void compact_uninit(WriterContext *wctx)
     CompactContext *compact = wctx->priv;
 
     av_freep(&compact->item_sep_str);
-    av_freep(&compact->buf);
     av_freep(&compact->escape_mode_str);
 }
 
@@ -660,12 +611,14 @@ static void compact_print_section_footer(WriterContext *wctx, const char *sectio
 static void compact_print_str(WriterContext *wctx, const char *key, const char *value)
 {
     CompactContext *compact = wctx->priv;
+    AVBPrint buf;
 
     if (wctx->nb_item) printf("%c", compact->item_sep);
     if (!compact->nokey)
         printf("%s=", key);
-    printf("%s", compact->escape_str(&compact->buf, &compact->buf_size,
-                                     value, compact->item_sep, wctx));
+    av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
+    printf("%s", compact->escape_str(&buf, value, compact->item_sep, wctx));
+    av_bprint_finalize(&buf, NULL);
 }
 
 static void compact_print_int(WriterContext *wctx, const char *key, long long int value)
@@ -682,14 +635,20 @@ static void compact_show_tags(WriterContext *wctx, AVDictionary *dict)
 {
     CompactContext *compact = wctx->priv;
     AVDictionaryEntry *tag = NULL;
+    AVBPrint buf;
 
     while ((tag = av_dict_get(dict, "", tag, AV_DICT_IGNORE_SUFFIX))) {
         if (wctx->nb_item) printf("%c", compact->item_sep);
-        if (!compact->nokey)
-            printf("tag:%s=", compact->escape_str(&compact->buf, &compact->buf_size,
-                                                  tag->key, compact->item_sep, wctx));
-        printf("%s", compact->escape_str(&compact->buf, &compact->buf_size,
-                                         tag->value, compact->item_sep, wctx));
+
+        if (!compact->nokey) {
+            av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
+            printf("tag:%s=", compact->escape_str(&buf, tag->key, compact->item_sep, wctx));
+            av_bprint_finalize(&buf, NULL);
+        }
+
+        av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
+        printf("%s", compact->escape_str(&buf, tag->value, compact->item_sep, wctx));
+        av_bprint_finalize(&buf, NULL);
     }
 }
 
@@ -731,8 +690,6 @@ static const Writer csv_writer = {
 typedef struct {
     const AVClass *class;
     int multiple_entries; ///< tells if the given chapter requires multiple entries
-    char *buf;
-    size_t buf_size;
     int print_packets_and_frames;
     int indent_level;
     int compact;
@@ -776,52 +733,27 @@ static av_cold int json_init(WriterContext *wctx, const char *args, void *opaque
     json->item_sep       = json->compact ? ", " : ",\n";
     json->item_start_end = json->compact ? " "  : "\n";
 
-    json->buf_size = ESCAPE_INIT_BUF_SIZE;
-    if (!(json->buf = av_malloc(json->buf_size)))
-        return AVERROR(ENOMEM);
-
     return 0;
 }
 
-static av_cold void json_uninit(WriterContext *wctx)
-{
-    JSONContext *json = wctx->priv;
-    av_freep(&json->buf);
-}
-
-static const char *json_escape_str(char **dst, size_t *dst_size, const char *src,
-                                   void *log_ctx)
+static const char *json_escape_str(AVBPrint *dst, const char *src, void *log_ctx)
 {
     static const char json_escape[] = {'"', '\\', '\b', '\f', '\n', '\r', '\t', 0};
     static const char json_subst[]  = {'"', '\\',  'b',  'f',  'n',  'r',  't', 0};
     const char *p;
-    char *q;
-    size_t size = 1;
-
-    // compute the length of the escaped string
-    for (p = src; *p; p++) {
-        ESCAPE_CHECK_SIZE(src, size, SIZE_MAX-6);
-        if (strchr(json_escape, *p))     size += 2; // simple escape
-        else if ((unsigned char)*p < 32) size += 6; // handle non-printable chars
-        else                             size += 1; // char copy
-    }
-    ESCAPE_REALLOC_BUF(dst_size, dst, src, size);
 
-    q = *dst;
     for (p = src; *p; p++) {
         char *s = strchr(json_escape, *p);
         if (s) {
-            *q++ = '\\';
-            *q++ = json_subst[s - json_escape];
+            av_bprint_chars(dst, '\\', 1);
+            av_bprint_chars(dst, json_subst[s - json_escape], 1);
         } else if ((unsigned char)*p < 32) {
-            snprintf(q, 7, "\\u00%02x", *p & 0xff);
-            q += 6;
+            av_bprintf(dst, "\\u00%02x", *p & 0xff);
         } else {
-            *q++ = *p;
+            av_bprint_chars(dst, *p, 1);
         }
     }
-    *q = 0;
-    return *dst;
+    return dst->str;
 }
 
 static void json_print_header(WriterContext *wctx)
@@ -843,6 +775,7 @@ static void json_print_footer(WriterContext *wctx)
 static void json_print_chapter_header(WriterContext *wctx, const char *chapter)
 {
     JSONContext *json = wctx->priv;
+    AVBPrint buf;
 
     if (wctx->nb_chapter)
         printf(",");
@@ -852,7 +785,9 @@ static void json_print_chapter_header(WriterContext *wctx, const char *chapter)
                              !strcmp(chapter, "streams") || !strcmp(chapter, "library_versions");
     if (json->multiple_entries) {
         JSON_INDENT();
-        printf("\"%s\": [\n", json_escape_str(&json->buf, &json->buf_size, chapter, wctx));
+        av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
+        printf("\"%s\": [\n", json_escape_str(&buf, chapter, wctx));
+        av_bprint_finalize(&buf, NULL);
         json->print_packets_and_frames = !strcmp(chapter, "packets_and_frames");
         json->indent_level++;
     }
@@ -903,10 +838,15 @@ static void json_print_section_footer(WriterContext *wctx, const char *section)
 static inline void json_print_item_str(WriterContext *wctx,
                                        const char *key, const char *value)
 {
-    JSONContext *json = wctx->priv;
+    AVBPrint buf;
+
+    av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
+    printf("\"%s\":", json_escape_str(&buf, key,   wctx));
+    av_bprint_finalize(&buf, NULL);
 
-    printf("\"%s\":", json_escape_str(&json->buf, &json->buf_size, key,   wctx));
-    printf(" \"%s\"", json_escape_str(&json->buf, &json->buf_size, value, wctx));
+    av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
+    printf(" \"%s\"", json_escape_str(&buf, value, wctx));
+    av_bprint_finalize(&buf, NULL);
 }
 
 static void json_print_str(WriterContext *wctx, const char *key, const char *value)
@@ -922,12 +862,15 @@ static void json_print_str(WriterContext *wctx, const char *key, const char *val
 static void json_print_int(WriterContext *wctx, const char *key, long long int value)
 {
     JSONContext *json = wctx->priv;
+    AVBPrint buf;
 
     if (wctx->nb_item) printf("%s", json->item_sep);
     if (!json->compact)
         JSON_INDENT();
-    printf("\"%s\": %lld",
-           json_escape_str(&json->buf, &json->buf_size, key, wctx), value);
+
+    av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
+    printf("\"%s\": %lld", json_escape_str(&buf, key, wctx), value);
+    av_bprint_finalize(&buf, NULL);
 }
 
 static void json_show_tags(WriterContext *wctx, AVDictionary *dict)
@@ -960,7 +903,6 @@ static const Writer json_writer = {
     .name                 = "json",
     .priv_size            = sizeof(JSONContext),
     .init                 = json_init,
-    .uninit               = json_uninit,
     .print_header         = json_print_header,
     .print_footer         = json_print_footer,
     .print_chapter_header = json_print_chapter_header,
@@ -982,8 +924,6 @@ typedef struct {
     int indent_level;
     int fully_qualified;
     int xsd_strict;
-    char *buf;
-    size_t buf_size;
 } XMLContext;
 
 #undef OFFSET
@@ -1043,61 +983,25 @@ static av_cold int xml_init(WriterContext *wctx, const char *args, void *opaque)
         }
     }
 
-    xml->buf_size = ESCAPE_INIT_BUF_SIZE;
-    if (!(xml->buf = av_malloc(xml->buf_size)))
-        return AVERROR(ENOMEM);
     return 0;
 }
 
-static av_cold void xml_uninit(WriterContext *wctx)
-{
-    XMLContext *xml = wctx->priv;
-    av_freep(&xml->buf);
-}
-
-static const char *xml_escape_str(char **dst, size_t *dst_size, const char *src,
-                                  void *log_ctx)
+static const char *xml_escape_str(AVBPrint *dst, const char *src, void *log_ctx)
 {
     const char *p;
-    char *q;
-    size_t size = 1;
-
-    /* precompute size */
-    for (p = src; *p; p++, size++) {
-        ESCAPE_CHECK_SIZE(src, size, SIZE_MAX-10);
-        switch (*p) {
-        case '&' : size += strlen("&amp;");  break;
-        case '<' : size += strlen("&lt;");   break;
-        case '>' : size += strlen("&gt;");   break;
-        case '\"': size += strlen("&quot;"); break;
-        case '\'': size += strlen("&apos;"); break;
-        default: size++;
-        }
-    }
-    ESCAPE_REALLOC_BUF(dst_size, dst, src, size);
-
-#define COPY_STR(str) {      \
-        const char *s = str; \
-        while (*s)           \
-            *q++ = *s++;     \
-    }
 
-    p = src;
-    q = *dst;
-    while (*p) {
+    for (p = src; *p; p++) {
         switch (*p) {
-        case '&' : COPY_STR("&amp;");  break;
-        case '<' : COPY_STR("&lt;");   break;
-        case '>' : COPY_STR("&gt;");   break;
-        case '\"': COPY_STR("&quot;"); break;
-        case '\'': COPY_STR("&apos;"); break;
-        default: *q++ = *p;
+        case '&' : av_bprintf(dst, "%s", "&amp;");  break;
+        case '<' : av_bprintf(dst, "%s", "&lt;");   break;
+        case '>' : av_bprintf(dst, "%s", "&gt;");   break;
+        case '\"': av_bprintf(dst, "%s", "&quot;"); break;
+        case '\'': av_bprintf(dst, "%s", "&apos;"); break;
+        default: av_bprint_chars(dst, *p, 1);
         }
-        p++;
     }
-    *q = 0;
 
-    return *dst;
+    return dst->str;
 }
 
 static void xml_print_header(WriterContext *wctx)
@@ -1172,11 +1076,13 @@ static void xml_print_section_footer(WriterContext *wctx, const char *section)
 
 static void xml_print_str(WriterContext *wctx, const char *key, const char *value)
 {
-    XMLContext *xml = wctx->priv;
+    AVBPrint buf;
 
     if (wctx->nb_item)
         printf(" ");
-    printf("%s=\"%s\"", key, xml_escape_str(&xml->buf, &xml->buf_size, value, wctx));
+    av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
+    printf("%s=\"%s\"", key, xml_escape_str(&buf, value, wctx));
+    av_bprint_finalize(&buf, NULL);
 }
 
 static void xml_print_int(WriterContext *wctx, const char *key, long long int value)
@@ -1191,6 +1097,7 @@ static void xml_show_tags(WriterContext *wctx, AVDictionary *dict)
     XMLContext *xml = wctx->priv;
     AVDictionaryEntry *tag = NULL;
     int is_first = 1;
+    AVBPrint buf;
 
     xml->indent_level++;
     while ((tag = av_dict_get(dict, "", tag, AV_DICT_IGNORE_SUFFIX))) {
@@ -1201,10 +1108,14 @@ static void xml_show_tags(WriterContext *wctx, AVDictionary *dict)
             is_first = 0;
         }
         XML_INDENT();
-        printf("<tag key=\"%s\"",
-               xml_escape_str(&xml->buf, &xml->buf_size, tag->key,   wctx));
-        printf(" value=\"%s\"/>\n",
-               xml_escape_str(&xml->buf, &xml->buf_size, tag->value, wctx));
+
+        av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
+        printf("<tag key=\"%s\"", xml_escape_str(&buf, tag->key, wctx));
+        av_bprint_finalize(&buf, NULL);
+
+        av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
+        printf(" value=\"%s\"/>\n", xml_escape_str(&buf, tag->value, wctx));
+        av_bprint_finalize(&buf, NULL);
     }
     xml->indent_level--;
 }
@@ -1213,7 +1124,6 @@ static Writer xml_writer = {
     .name                 = "xml",
     .priv_size            = sizeof(XMLContext),
     .init                 = xml_init,
-    .uninit               = xml_uninit,
     .print_header         = xml_print_header,
     .print_footer         = xml_print_footer,
     .print_chapter_header = xml_print_chapter_header,
@@ -1382,7 +1292,7 @@ static void read_packets(WriterContext *w, AVFormatContext *fmt_ctx)
         }
         if (do_read_frames) {
             pkt1 = pkt;
-            while (1) {
+            while (pkt1.size) {
                 avcodec_get_frame_defaults(&frame);
                 ret = get_decoded_frame(fmt_ctx, &frame, &got_frame, &pkt1);
                 if (ret < 0 || !got_frame)
@@ -1531,6 +1441,20 @@ static void show_streams(WriterContext *w, AVFormatContext *fmt_ctx)
         show_stream(w, fmt_ctx, i);
 }
 
+static void print_format_entry(const char *tag,
+                               const char *val)
+{
+    if (!fmt_entries_to_show) {
+        if (tag) {
+            printf("%s=%s\n", tag, val);
+        } else {
+            printf("%s\n", val);
+        }
+    } else if (tag && av_dict_get(fmt_entries_to_show, tag, NULL, 0)) {
+        printf("%s=%s\n", tag, val);
+    }
+}
+
 static void show_format(WriterContext *w, AVFormatContext *fmt_ctx)
 {
     char val_str[128];
@@ -1724,6 +1648,13 @@ static int opt_format(const char *opt, const char *arg)
     return 0;
 }
 
+static int opt_show_format_entry(const char *opt, const char *arg)
+{
+    do_show_format = 1;
+    av_dict_set(&fmt_entries_to_show, arg, "", 0);
+    return 0;
+}
+
 static void opt_input_file(void *optctx, const char *arg)
 {
     if (input_filename) {
@@ -1781,6 +1712,8 @@ static const OptionDef options[] = {
     { "show_error",   OPT_BOOL, {(void*)&do_show_error} ,  "show probing error" },
     { "show_format",  OPT_BOOL, {(void*)&do_show_format} , "show format/container info" },
     { "show_frames",  OPT_BOOL, {(void*)&do_show_frames} , "show frames info" },
+    { "show_format_entry", HAS_ARG, {(void*)opt_show_format_entry},
+      "show a particular entry from the format/container info", "entry" },
     { "show_packets", OPT_BOOL, {(void*)&do_show_packets}, "show packets info" },
     { "show_streams", OPT_BOOL, {(void*)&do_show_streams}, "show streams info" },
     { "count_frames", OPT_BOOL, {(void*)&do_count_frames}, "count the number of frames per stream" },