ffprobe: force display of missing fields, depending on writer.flags
authorStefano Sabatini <stefasab@gmail.com>
Sun, 23 Oct 2011 23:23:22 +0000 (01:23 +0200)
committerStefano Sabatini <stefasab@gmail.com>
Tue, 15 Nov 2011 23:30:35 +0000 (00:30 +0100)
Add flags field to Writer, and define the
WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS flag which forces the display of
optional fields, for example non-available or invalid fields.

Also set the flag in the default writer.

This change is required as for some writers it is preferable to show all
fields (for example for avoiding a variable number of fields in CSV
output), while for other formats (e.g. JSON, XML) it is better to leave
invalid/unavailable fields unspecified and thus simplify the parsing
stage on the deserializer side.

ffprobe.c

index e512f00..a8c2ff0 100644 (file)
--- a/ffprobe.c
+++ b/ffprobe.c
@@ -121,33 +121,12 @@ static char *value_string(char *buf, int buf_size, struct unit_value uv)
     return buf;
 }
 
-static char *time_value_string(char *buf, int buf_size, int64_t val, const AVRational *time_base)
-{
-    if (val == AV_NOPTS_VALUE) {
-        snprintf(buf, buf_size, "N/A");
-    } else {
-        double d = val * av_q2d(*time_base);
-        value_string(buf, buf_size, (struct unit_value){.val.d=d, .unit=unit_second_str});
-    }
-
-    return buf;
-}
-
-static char *ts_value_string (char *buf, int buf_size, int64_t ts)
-{
-    if (ts == AV_NOPTS_VALUE) {
-        snprintf(buf, buf_size, "N/A");
-    } else {
-        snprintf(buf, buf_size, "%"PRId64, ts);
-    }
-
-    return buf;
-}
-
 /* WRITERS API */
 
 typedef struct WriterContext WriterContext;
 
+#define WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS 1
+
 typedef struct Writer {
     int priv_size;                  ///< private size for the writer context
     const char *name;
@@ -165,6 +144,7 @@ typedef struct Writer {
     void (*print_integer)       (WriterContext *wctx, const char *, int);
     void (*print_string)        (WriterContext *wctx, const char *, const char *);
     void (*show_tags)           (WriterContext *wctx, AVDictionary *dict);
+    int flags;                  ///< a combination or WRITER_FLAG_*
 } Writer;
 
 struct WriterContext {
@@ -281,12 +261,40 @@ static inline void writer_print_integer(WriterContext *wctx,
 }
 
 static inline void writer_print_string(WriterContext *wctx,
-                                       const char *key, const char *val)
+                                       const char *key, const char *val, int opt)
 {
+    if (opt && !(wctx->writer->flags & WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS))
+        return;
     wctx->writer->print_string(wctx, key, val);
     wctx->nb_item++;
 }
 
+static void writer_print_time(WriterContext *wctx, const char *key,
+                              int64_t ts, const AVRational *time_base)
+{
+    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);
+    }
+}
+
+static void writer_print_ts(WriterContext *wctx, const char *key, int64_t ts)
+{
+    char buf[128];
+
+    if (ts == AV_NOPTS_VALUE) {
+        writer_print_string(wctx, key, "N/A", 1);
+    } else {
+        snprintf(buf, sizeof(buf), "%"PRId64, ts);
+        writer_print_string(wctx, key, buf, 0);
+    }
+}
+
 static inline void writer_show_tags(WriterContext *wctx, AVDictionary *dict)
 {
     wctx->writer->show_tags(wctx, dict);
@@ -438,7 +446,7 @@ 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:");
-        writer_print_string(wctx, tag->key, tag->value);
+        writer_print_string(wctx, tag->key, tag->value, 0);
     }
 }
 
@@ -450,7 +458,8 @@ static Writer default_writer = {
     .print_section_footer  = default_print_section_footer,
     .print_integer         = default_print_int,
     .print_string          = default_print_str,
-    .show_tags             = default_show_tags
+    .show_tags             = default_show_tags,
+    .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS,
 };
 
 /* JSON output */
@@ -626,15 +635,21 @@ static void writer_register_all(void)
 
 #define print_fmt(k, f, ...) do {              \
     if (fast_asprintf(&pbuf, f, __VA_ARGS__))  \
-        writer_print_string(w, k, pbuf.s);     \
+        writer_print_string(w, k, pbuf.s, 0);  \
+} while (0)
+
+#define print_fmt_opt(k, f, ...) do {          \
+    if (fast_asprintf(&pbuf, f, __VA_ARGS__))  \
+        writer_print_string(w, k, pbuf.s, 1);  \
 } while (0)
 
 #define print_int(k, v)         writer_print_integer(w, k, v)
-#define print_str(k, v)         writer_print_string(w, k, v)
-#define print_ts(k, v)          writer_print_string(w, k, ts_value_string  (val_str, sizeof(val_str), v))
-#define print_time(k, v, tb)    writer_print_string(w, k, time_value_string(val_str, sizeof(val_str), v, tb))
-#define print_val(k, v, u)      writer_print_string(w, k, value_string     (val_str, sizeof(val_str), \
-                                                    (struct unit_value){.val.i = v, .unit=u}))
+#define print_str(k, v)         writer_print_string(w, k, v, 0)
+#define print_str_opt(k, v)     writer_print_string(w, k, v, 1)
+#define print_time(k, v, tb)    writer_print_time(w, k, v, tb)
+#define print_ts(k, v)          writer_print_ts(w, k, v)
+#define print_val(k, v, u)      writer_print_string(w, k, \
+    value_string(val_str, sizeof(val_str), (struct unit_value){.val.i = v, .unit=u}), 1)
 #define print_section_header(s) writer_print_section_header(w, s)
 #define print_section_footer(s) writer_print_section_footer(w, s)
 #define show_tags(metadata)     writer_show_tags(w, metadata)
@@ -644,9 +659,12 @@ static void show_packet(WriterContext *w, AVFormatContext *fmt_ctx, AVPacket *pk
     char val_str[128];
     AVStream *st = fmt_ctx->streams[pkt->stream_index];
     struct print_buf pbuf = {.s = NULL};
+    const char *s;
 
     print_section_header("packet");
-    print_str("codec_type",       av_x_if_null(av_get_media_type_string(st->codec->codec_type), "unknown"));
+    s = av_get_media_type_string(st->codec->codec_type);
+    if (s) print_str    ("codec_type", s);
+    else   print_str_opt("codec_type", "unknown");
     print_int("stream_index",     pkt->stream_index);
     print_ts  ("pts",             pkt->pts);
     print_time("pts_time",        pkt->pts, &st->time_base);
@@ -655,7 +673,8 @@ static void show_packet(WriterContext *w, AVFormatContext *fmt_ctx, AVPacket *pk
     print_ts  ("duration",        pkt->duration);
     print_time("duration_time",   pkt->duration, &st->time_base);
     print_val("size",             pkt->size, unit_byte_str);
-    print_fmt("pos",   "%"PRId64, pkt->pos);
+    if (pkt->pos != -1) print_fmt    ("pos", "%"PRId64, pkt->pos);
+    else                print_str_opt("pos", "N/A");
     print_fmt("flags", "%c",      pkt->flags & AV_PKT_FLAG_KEY ? 'K' : '_');
     print_section_footer("packet");
 
@@ -680,6 +699,7 @@ static void show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_i
     AVCodecContext *dec_ctx;
     AVCodec *dec;
     char val_str[128];
+    const char *s;
     AVRational display_aspect_ratio;
     struct print_buf pbuf = {.s = NULL};
 
@@ -692,10 +712,13 @@ static void show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_i
             print_str("codec_name",      dec->name);
             print_str("codec_long_name", dec->long_name);
         } else {
-            print_str("codec_name",      "unknown");
+            print_str_opt("codec_name",      "unknown");
+            print_str_opt("codec_long_name", "unknown");
         }
 
-        print_str("codec_type", av_x_if_null(av_get_media_type_string(dec_ctx->codec_type), "unknown"));
+        s = av_get_media_type_string(dec_ctx->codec_type);
+        if (s) print_str    ("codec_type", s);
+        else   print_str_opt("codec_type", "unknown");
         print_fmt("codec_time_base", "%d/%d", dec_ctx->time_base.num, dec_ctx->time_base.den);
 
         /* print AVI/FourCC tag */
@@ -719,21 +742,27 @@ static void show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_i
                 print_fmt("display_aspect_ratio", "%d:%d",
                           display_aspect_ratio.num,
                           display_aspect_ratio.den);
+            } else {
+                print_str_opt("sample_aspect_ratio", "N/A");
+                print_str_opt("display_aspect_ratio", "N/A");
             }
-            print_str("pix_fmt", av_x_if_null(av_get_pix_fmt_name(dec_ctx->pix_fmt), "unknown"));
+            s = av_get_pix_fmt_name(dec_ctx->pix_fmt);
+            if (s) print_str    ("pix_fmt", s);
+            else   print_str_opt("pix_fmt", "unknown");
             print_int("level",   dec_ctx->level);
             break;
 
         case AVMEDIA_TYPE_AUDIO:
-            print_str("sample_fmt",
-                      av_x_if_null(av_get_sample_fmt_name(dec_ctx->sample_fmt), "unknown"));
+            s = av_get_sample_fmt_name(dec_ctx->sample_fmt);
+            if (s) print_str    ("sample_fmt", s);
+            else   print_str_opt("sample_fmt", "unknown");
             print_val("sample_rate",     dec_ctx->sample_rate, unit_hertz_str);
             print_int("channels",        dec_ctx->channels);
             print_int("bits_per_sample", av_get_bits_per_sample(dec_ctx->codec_id));
             break;
         }
     } else {
-        print_str("codec_type", "unknown");
+        print_str_opt("codec_type", "unknown");
     }
     if (dec_ctx->codec && dec_ctx->codec->priv_class) {
         const AVOption *opt = NULL;
@@ -747,16 +776,15 @@ static void show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_i
         }
     }
 
-    if (fmt_ctx->iformat->flags & AVFMT_SHOW_IDS)
-        print_fmt("id", "0x%x", stream->id);
+    if (fmt_ctx->iformat->flags & AVFMT_SHOW_IDS) print_fmt    ("id", "0x%x", stream->id);
+    else                                          print_str_opt("id", "N/A");
     print_fmt("r_frame_rate",   "%d/%d", stream->r_frame_rate.num,   stream->r_frame_rate.den);
     print_fmt("avg_frame_rate", "%d/%d", stream->avg_frame_rate.num, stream->avg_frame_rate.den);
     print_fmt("time_base",      "%d/%d", stream->time_base.num,      stream->time_base.den);
     print_time("start_time",    stream->start_time, &stream->time_base);
     print_time("duration",      stream->duration,   &stream->time_base);
-    if (stream->nb_frames)
-        print_fmt("nb_frames", "%"PRId64, stream->nb_frames);
-
+    if (stream->nb_frames) print_fmt    ("nb_frames", "%"PRId64, stream->nb_frames);
+    else                   print_str_opt("nb_frames", "N/A");
     show_tags(stream->metadata);
 
     print_section_footer("stream");
@@ -784,9 +812,10 @@ static void show_format(WriterContext *w, AVFormatContext *fmt_ctx)
     print_str("format_long_name", fmt_ctx->iformat->long_name);
     print_time("start_time",      fmt_ctx->start_time, &AV_TIME_BASE_Q);
     print_time("duration",        fmt_ctx->duration,   &AV_TIME_BASE_Q);
-    if (size >= 0)
-        print_val("size",         size, unit_byte_str);
-    print_val("bit_rate",         fmt_ctx->bit_rate, unit_bit_per_second_str);
+    if (size >= 0) print_val    ("size", size, unit_byte_str);
+    else           print_str_opt("size", "N/A");
+    if (fmt_ctx->bit_rate > 0) print_val    ("bit_rate", fmt_ctx->bit_rate, unit_bit_per_second_str);
+    else                       print_str_opt("bit_rate", "N/A");
     show_tags(fmt_ctx->metadata);
     print_section_footer("format");
     av_free(pbuf.s);