FFmpeg
tf_json.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) The FFmpeg developers
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #include <limits.h>
22 #include <stdarg.h>
23 #include <stdint.h>
24 #include <stdio.h>
25 #include <string.h>
26 
27 #include "avtextformat.h"
28 #include "libavutil/bprint.h"
29 #include "libavutil/opt.h"
30 #include "tf_internal.h"
31 
32 /* JSON output */
33 
34 typedef struct JSONContext {
35  const AVClass *class;
37  int compact;
38  const char *item_sep, *item_start_end;
39 } JSONContext;
40 
41 #undef OFFSET
42 #define OFFSET(x) offsetof(JSONContext, x)
43 
44 static const AVOption json_options[] = {
45  { "compact", "enable compact output", OFFSET(compact), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1 },
46  { "c", "enable compact output", OFFSET(compact), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1 },
47  { NULL }
48 };
49 
51 
53 {
54  JSONContext *json = wctx->priv;
55 
56  json->item_sep = json->compact ? ", " : ",\n";
57  json->item_start_end = json->compact ? " " : "\n";
58 
59  return 0;
60 }
61 
62 static const char *json_escape_str(AVBPrint *dst, const char *src, void *log_ctx)
63 {
64  static const char json_escape[] = { '"', '\\', '\b', '\f', '\n', '\r', '\t', 0 };
65  static const char json_subst[] = { '"', '\\', 'b', 'f', 'n', 'r', 't', 0 };
66  const char *p;
67 
68  if (!src) {
69  av_log(log_ctx, AV_LOG_WARNING, "Cannot escape NULL string, returning NULL\n");
70  return NULL;
71  }
72 
73  for (p = src; *p; p++) {
74  char *s = strchr(json_escape, *p);
75  if (s) {
76  av_bprint_chars(dst, '\\', 1);
77  av_bprint_chars(dst, json_subst[s - json_escape], 1);
78  } else if ((unsigned char)*p < 32) {
79  av_bprintf(dst, "\\u00%02x", (unsigned char)*p);
80  } else {
81  av_bprint_chars(dst, *p, 1);
82  }
83  }
84  return dst->str;
85 }
86 
87 #define JSON_INDENT() writer_printf(wctx, "%*c", json->indent_level * 4, ' ')
88 
89 static void json_print_section_header(AVTextFormatContext *wctx, const void *data)
90 {
91  const AVTextFormatSection *section = tf_get_section(wctx, wctx->level);
92  const AVTextFormatSection *parent_section = tf_get_parent_section(wctx, wctx->level);
93  JSONContext *json = wctx->priv;
94  AVBPrint buf;
95 
96  if (!section)
97  return;
98 
99  if (wctx->level && wctx->nb_item[wctx->level - 1])
100  writer_put_str(wctx, ",\n");
101 
103  writer_put_str(wctx, "{\n");
104  json->indent_level++;
105  } else {
107  json_escape_str(&buf, section->name, wctx);
108  JSON_INDENT();
109 
110  json->indent_level++;
112  writer_printf(wctx, "\"%s\": [\n", buf.str);
113  } else if (parent_section && !(parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY)) {
114  writer_printf(wctx, "\"%s\": {%s", buf.str, json->item_start_end);
115  } else {
116  writer_printf(wctx, "{%s", json->item_start_end);
117 
118  /* this is required so the parser can distinguish between packets and frames */
119  if (parent_section && parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_NUMBERING_BY_TYPE) {
120  if (!json->compact)
121  JSON_INDENT();
122  writer_printf(wctx, "\"type\": \"%s\"", section->name);
123  wctx->nb_item[wctx->level]++;
124  }
125  }
126  av_bprint_finalize(&buf, NULL);
127  }
128 }
129 
131 {
132  const AVTextFormatSection *section = tf_get_section(wctx, wctx->level);
133  JSONContext *json = wctx->priv;
134 
135  if (!section)
136  return;
137 
138  if (wctx->level == 0) {
139  json->indent_level--;
140  writer_put_str(wctx, "\n}\n");
141  } else if (section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY) {
142  writer_w8(wctx, '\n');
143  json->indent_level--;
144  JSON_INDENT();
145  writer_w8(wctx, ']');
146  } else {
147  writer_put_str(wctx, json->item_start_end);
148  json->indent_level--;
149  if (!json->compact)
150  JSON_INDENT();
151  writer_w8(wctx, '}');
152  }
153 }
154 
155 static inline void json_print_item_str(AVTextFormatContext *wctx,
156  const char *key, const char *value)
157 {
158  AVBPrint buf;
159 
161  writer_printf(wctx, "\"%s\":", json_escape_str(&buf, key, wctx));
162  av_bprint_clear(&buf);
163  writer_printf(wctx, " \"%s\"", json_escape_str(&buf, value, wctx));
164  av_bprint_finalize(&buf, NULL);
165 }
166 
167 static void json_print_str(AVTextFormatContext *wctx, const char *key, const char *value)
168 {
169  const AVTextFormatSection *section = tf_get_section(wctx, wctx->level);
170  const AVTextFormatSection *parent_section = tf_get_parent_section(wctx, wctx->level);
171  JSONContext *json = wctx->priv;
172 
173  if (!section)
174  return;
175 
176  if (wctx->nb_item[wctx->level] || (parent_section && parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_NUMBERING_BY_TYPE))
177  writer_put_str(wctx, json->item_sep);
178  if (!json->compact)
179  JSON_INDENT();
180  json_print_item_str(wctx, key, value);
181 }
182 
183 static void json_print_int(AVTextFormatContext *wctx, const char *key, int64_t value)
184 {
185  const AVTextFormatSection *section = tf_get_section(wctx, wctx->level);
186  const AVTextFormatSection *parent_section = tf_get_parent_section(wctx, wctx->level);
187  JSONContext *json = wctx->priv;
188  AVBPrint buf;
189 
190  if (!section)
191  return;
192 
193  if (wctx->nb_item[wctx->level] || (parent_section && parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_NUMBERING_BY_TYPE))
194  writer_put_str(wctx, json->item_sep);
195  if (!json->compact)
196  JSON_INDENT();
197 
199  writer_printf(wctx, "\"%s\": %"PRId64, json_escape_str(&buf, key, wctx), value);
200  av_bprint_finalize(&buf, NULL);
201 }
202 
204  .name = "json",
205  .priv_size = sizeof(JSONContext),
206  .init = json_init,
207  .print_section_header = json_print_section_header,
208  .print_section_footer = json_print_section_footer,
209  .print_integer = json_print_int,
210  .print_string = json_print_str,
212  .priv_class = &json_class,
213 };
flags
const SwsFlags flags[]
Definition: swscale.c:61
json_escape_str
static const char * json_escape_str(AVBPrint *dst, const char *src, void *log_ctx)
Definition: tf_json.c:62
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:216
AV_BPRINT_SIZE_UNLIMITED
#define AV_BPRINT_SIZE_UNLIMITED
json_options
static const AVOption json_options[]
Definition: tf_json.c:44
opt.h
av_bprint_init
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
JSON_INDENT
#define JSON_INDENT()
Definition: tf_json.c:87
int64_t
long long int64_t
Definition: coverity.c:34
writer_printf
static void writer_printf(AVTextFormatContext *wctx, const char *fmt,...)
Definition: tf_internal.h:73
AVOption
AVOption.
Definition: opt.h:429
data
const char data[16]
Definition: mxf.c:149
avtextformat.h
AVTextFormatContext
Definition: avtextformat.h:112
json_print_int
static void json_print_int(AVTextFormatContext *wctx, const char *key, int64_t value)
Definition: tf_json.c:183
AVTextFormatContext::level
int level
current level, starting from 0
Definition: avtextformat.h:123
AVTextFormatSection::name
const char * name
Definition: avtextformat.h:43
AV_TEXTFORMAT_SECTION_FLAG_NUMBERING_BY_TYPE
#define AV_TEXTFORMAT_SECTION_FLAG_NUMBERING_BY_TYPE
the items in this array section should be numbered individually by type
Definition: avtextformat.h:50
AVTextFormatSection::flags
int flags
Definition: avtextformat.h:56
av_cold
#define av_cold
Definition: attributes.h:90
s
#define s(width, name)
Definition: cbs_vp9.c:198
AVTextFormatter
Definition: avtextformat.h:94
AVTextFormatSection
Definition: avtextformat.h:41
json_init
static av_cold int json_init(AVTextFormatContext *wctx)
Definition: tf_json.c:52
limits.h
AVTextFormatContext::priv
void * priv
private data for use by the filter
Definition: avtextformat.h:118
key
const char * key
Definition: hwcontext_opencl.c:189
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:76
NULL
#define NULL
Definition: coverity.c:32
writer_w8
static void writer_w8(AVTextFormatContext *wctx, int b)
Definition: tf_internal.h:63
tf_get_parent_section
static const AVTextFormatSection * tf_get_parent_section(AVTextFormatContext *tfc, int level)
Safely access the parent section.
Definition: tf_internal.h:55
avtextformatter_json
const AVTextFormatter avtextformatter_json
Definition: tf_json.c:203
init
int(* init)(AVBSFContext *ctx)
Definition: dts2pts.c:368
DEFINE_FORMATTER_CLASS
DEFINE_FORMATTER_CLASS(json)
av_bprint_finalize
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:240
dst
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition: dsp.h:87
AVTextFormatter::name
const char * name
Definition: avtextformat.h:97
tf_internal.h
json_print_str
static void json_print_str(AVTextFormatContext *wctx, const char *key, const char *value)
Definition: tf_json.c:167
json_print_section_header
static void json_print_section_header(AVTextFormatContext *wctx, const void *data)
Definition: tf_json.c:89
JSONContext::indent_level
int indent_level
Definition: tf_json.c:36
writer_put_str
static void writer_put_str(AVTextFormatContext *wctx, const char *str)
Definition: tf_internal.h:68
bprint.h
OFFSET
#define OFFSET(x)
Definition: tf_json.c:42
value
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default value
Definition: writing_filters.txt:86
AV_TEXTFORMAT_FLAG_SUPPORTS_MIXED_ARRAY_CONTENT
#define AV_TEXTFORMAT_FLAG_SUPPORTS_MIXED_ARRAY_CONTENT
Definition: avtextformat.h:72
AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER
#define AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER
the section only contains other sections, but has no data at its own level
Definition: avtextformat.h:45
av_bprintf
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:99
JSONContext::item_sep
const char * item_sep
Definition: tf_json.c:38
av_bprint_clear
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
Definition: bprint.c:232
json_print_section_footer
static void json_print_section_footer(AVTextFormatContext *wctx)
Definition: tf_json.c:130
AVTextFormatContext::nb_item
unsigned int nb_item[SECTION_MAX_NB_LEVELS]
number of the item printed in the given section, starting from 0
Definition: avtextformat.h:126
JSONContext::item_start_end
const char * item_start_end
Definition: tf_json.c:38
AV_OPT_TYPE_BOOL
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
Definition: opt.h:327
tf_get_section
static const AVTextFormatSection * tf_get_section(AVTextFormatContext *tfc, int level)
Safely validate and access a section at a given level.
Definition: tf_internal.h:42
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
av_bprint_chars
void av_bprint_chars(AVBPrint *buf, char c, unsigned n)
Append char c n times to a print buffer.
Definition: bprint.c:145
json_print_item_str
static void json_print_item_str(AVTextFormatContext *wctx, const char *key, const char *value)
Definition: tf_json.c:155
AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY
#define AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY
the section contains an array of elements of the same type
Definition: avtextformat.h:46
src
#define src
Definition: vp8dsp.c:248
JSONContext::compact
int compact
Definition: tf_json.c:37
JSONContext
Definition: tf_json.c:34