[FFmpeg-devel] [PATCH 3/6] ffprobe: add basic JSON output.

Clément Bœsch ubitux at gmail.com
Wed Aug 17 23:23:20 CEST 2011


On Wed, Aug 17, 2011 at 08:32:04PM +0200, Clément Bœsch wrote:
> ---
>  ffprobe.c |   23 ++++++++++++++++++-----
>  1 files changed, 18 insertions(+), 5 deletions(-)
> 
> diff --git a/ffprobe.c b/ffprobe.c

New patch attached. Note the patch is a bit bigger than the initial one
mainly because it's quite a pain not to add a trailing comma after the
last entry (JSON standard doesn't support it).

Also, following reindent patch is locally updated according to this one.

Last thing, the commit says "basic" because it doesn't handle escaping
special chars in strings for instance.

-- 
Clément B.
-------------- next part --------------
From 7e52e421acc09622566f3f608fbf669b2780a53f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cl=C3=A9ment=20B=C5=93sch?= <ubitux at gmail.com>
Date: Wed, 17 Aug 2011 23:12:24 +0200
Subject: [PATCH 3/5] ffprobe: add basic JSON output.

---
 ffprobe.c |   96 ++++++++++++++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 80 insertions(+), 16 deletions(-)

diff --git a/ffprobe.c b/ffprobe.c
index 5eebd45..d7d5167 100644
--- a/ffprobe.c
+++ b/ffprobe.c
@@ -36,6 +36,7 @@ static int do_show_format  = 0;
 static int do_show_packets = 0;
 static int do_show_streams = 0;
 
+static int json_output;
 static int show_value_unit              = 0;
 static int use_value_prefix             = 0;
 static int use_byte_value_binary_prefix = 0;
@@ -129,32 +130,38 @@ static const char *media_type_string(enum AVMediaType media_type)
 
 static void print_info_header(const char *section)
 {
-    printf("[%s]\n", section);
+    if (json_output) printf("{\n");
+    else             printf("[%s]\n", section);
 }
 
-static void print_info_item_fmt(const char *key, const char *fmt, ...)
+static void print_info_item_fmt0(const char *key, const char *fmt, ...)
 {
     va_list ap;
     va_start(ap, fmt);
-    printf("%s=", key);
+    printf(json_output ? "    \"%s\": \"" : "%s=", key);
     vprintf(fmt, ap);
-    printf("\n");
+    printf(json_output ? "\"" : "\n");
     va_end(ap);
 }
 
-static void print_info_item_str(const char *key, const char *value)
-{
-    print_info_item_fmt(key, "%s", value);
-}
+#define print_info_item_fmt(k, fmt, args...) do { \
+    if (json_output) printf(",\n");               \
+    print_info_item_fmt0(k, fmt, ##args);         \
+} while (0)
 
-static void print_info_item_int(const char *key, int value)
-{
-    printf("%s=%d\n", key, value);
-}
+#define print_info_item_str0(k, v) print_info_item_fmt0(k, "%s", v)
+#define print_info_item_str(k, v)  print_info_item_fmt(k, "%s", v)
+
+#define print_info_item_int0(k, v) printf(json_output ? "    \"%s\": %d" : "%s=%d\n", k, v);
+#define print_info_item_int(k, v) do { \
+    if (json_output) printf(",\n");    \
+    print_info_item_int0(k, v);        \
+} while (0)
 
 static void print_info_footer(const char *section)
 {
-    printf("[/%s]\n", section);
+    if (json_output) printf("\n  }");
+    else             printf("[/%s]\n", section);
 }
 
 static void show_packet(AVFormatContext *fmt_ctx, AVPacket *pkt)
@@ -163,7 +170,7 @@ static void show_packet(AVFormatContext *fmt_ctx, AVPacket *pkt)
     AVStream *st = fmt_ctx->streams[pkt->stream_index];
 
     print_info_header("PACKET");
-    print_info_item_str("codec_type",     media_type_string(st->codec->codec_type));
+    print_info_item_str0("codec_type",    media_type_string(st->codec->codec_type));
     print_info_item_int("stream_index",   pkt->stream_index);
     print_info_item_str("pts",            ts_value_string  (val_str, sizeof(val_str), pkt->pts));
     print_info_item_str("pts_time",       time_value_string(val_str, sizeof(val_str), pkt->pts, &st->time_base));
@@ -181,20 +188,46 @@ static void show_packet(AVFormatContext *fmt_ctx, AVPacket *pkt)
 static void show_packets(AVFormatContext *fmt_ctx)
 {
     AVPacket pkt;
+    int first = 1;
 
     av_init_packet(&pkt);
 
+    if (json_output) {
+        while (!av_read_frame(fmt_ctx, &pkt)) {
+            if (first) first = 0;
+            else       printf(", ");
+            show_packet(fmt_ctx, &pkt);
+        }
+    } else {
     while (!av_read_frame(fmt_ctx, &pkt))
         show_packet(fmt_ctx, &pkt);
+    }
 }
 
 static void show_avdict(AVDictionary *dict)
 {
     AVDictionaryEntry *tag = NULL;
+    if (json_output) {
+        int first = 1;
+        if (!dict)
+            return;
+        printf(",\n    \"tags\": {\n");
+        while ((tag = av_dict_get(dict, "", tag, AV_DICT_IGNORE_SUFFIX))) {
+            if (first) {
+                print_info_item_str0(tag->key, tag->value);
+                first = 0;
+            } else {
+                printf("  ");
+                print_info_item_str (tag->key, tag->value);
+            }
+        }
+        printf("\n    }");
+    } else {
     while ((tag = av_dict_get(dict, "", tag, AV_DICT_IGNORE_SUFFIX))) {
         printf("TAG:");
         print_info_item_str(tag->key, tag->value);
     }
+    }
 }
 
 static void show_stream(AVFormatContext *fmt_ctx, int stream_idx)
@@ -207,7 +240,7 @@ static void show_stream(AVFormatContext *fmt_ctx, int stream_idx)
 
     print_info_header("STREAM");
 
-    print_info_item_int("index", stream->index);
+    print_info_item_int0("index", stream->index);
 
     if ((dec_ctx = stream->codec)) {
         if ((dec = dec_ctx->codec)) {
@@ -278,7 +311,7 @@ static void show_format(AVFormatContext *fmt_ctx)
 
     print_info_header("FORMAT");
 
-    print_info_item_str("filename",         fmt_ctx->filename);
+    print_info_item_str0("filename",        fmt_ctx->filename);
     print_info_item_int("nb_streams",       fmt_ctx->nb_streams);
     print_info_item_str("format_name",      fmt_ctx->iformat->name);
     print_info_item_str("format_long_name", fmt_ctx->iformat->long_name);
@@ -343,6 +376,34 @@ static int probe_file(const char *filename)
     if ((ret = open_input_file(&fmt_ctx, filename)))
         return ret;
 
+    if (json_output) {
+        printf("{");
+
+        if (do_show_packets) {
+            printf("\n  \"packets\": [");
+            show_packets(fmt_ctx);
+            printf((do_show_streams || do_show_format) ? "]," : "]");
+        }
+
+        if (do_show_streams) {
+            printf("\n  \"streams\": [");
+            for (i = 0; i < fmt_ctx->nb_streams; i++) {
+                if (i)
+                    printf(",");
+                show_stream(fmt_ctx, i);
+            }
+            printf(do_show_format ? "]," : "]");
+        }
+
+        if (do_show_format) {
+            printf("\n  \"format\": ");
+            show_format(fmt_ctx);
+        }
+
+        printf("\n}\n");
+
+    } else {
+
     if (do_show_packets)
         show_packets(fmt_ctx);
 
@@ -353,6 +414,8 @@ static int probe_file(const char *filename)
     if (do_show_format)
         show_format(fmt_ctx);
 
+    }
+
     av_close_input_file(fmt_ctx);
     return 0;
 }
@@ -418,6 +481,7 @@ static const OptionDef options[] = {
       "use sexagesimal format HOURS:MM:SS.MICROSECONDS for time units" },
     { "pretty", 0, {(void*)&opt_pretty},
       "prettify the format of displayed values, make it more human readable" },
+    { "json", OPT_BOOL, {(void*)&json_output}, "output data in JSON" },
     { "show_format",  OPT_BOOL, {(void*)&do_show_format} , "show format/container info" },
     { "show_packets", OPT_BOOL, {(void*)&do_show_packets}, "show packets info" },
     { "show_streams", OPT_BOOL, {(void*)&do_show_streams}, "show streams info" },
-- 
1.7.6

-------------- 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/20110817/25bf8ae2/attachment.asc>


More information about the ffmpeg-devel mailing list