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 
31 #define writer_w8(wctx_, b_) (wctx_)->writer->writer->writer_w8((wctx_)->writer, b_)
32 #define writer_put_str(wctx_, str_) (wctx_)->writer->writer->writer_put_str((wctx_)->writer, str_)
33 #define writer_printf(wctx_, fmt_, ...) (wctx_)->writer->writer->writer_printf((wctx_)->writer, fmt_, __VA_ARGS__)
34 
35 #define DEFINE_FORMATTER_CLASS(name) \
36 static const char *name##_get_name(void *ctx) \
37 { \
38  return #name ; \
39 } \
40 static const AVClass name##_class = { \
41  .class_name = #name, \
42  .item_name = name##_get_name, \
43  .option = name##_options \
44 }
45 
46 
47 /* JSON output */
48 
49 typedef struct JSONContext {
50  const AVClass *class;
52  int compact;
53  const char *item_sep, *item_start_end;
54 } JSONContext;
55 
56 #undef OFFSET
57 #define OFFSET(x) offsetof(JSONContext, x)
58 
59 static const AVOption json_options[]= {
60  { "compact", "enable compact output", OFFSET(compact), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
61  { "c", "enable compact output", OFFSET(compact), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
62  { NULL }
63 };
64 
66 
68 {
69  JSONContext *json = wctx->priv;
70 
71  json->item_sep = json->compact ? ", " : ",\n";
72  json->item_start_end = json->compact ? " " : "\n";
73 
74  return 0;
75 }
76 
77 static const char *json_escape_str(AVBPrint *dst, const char *src, void *log_ctx)
78 {
79  static const char json_escape[] = {'"', '\\', '\b', '\f', '\n', '\r', '\t', 0};
80  static const char json_subst[] = {'"', '\\', 'b', 'f', 'n', 'r', 't', 0};
81  const char *p;
82 
83  for (p = src; *p; p++) {
84  char *s = strchr(json_escape, *p);
85  if (s) {
86  av_bprint_chars(dst, '\\', 1);
87  av_bprint_chars(dst, json_subst[s - json_escape], 1);
88  } else if ((unsigned char)*p < 32) {
89  av_bprintf(dst, "\\u00%02x", *p & 0xff);
90  } else {
91  av_bprint_chars(dst, *p, 1);
92  }
93  }
94  return dst->str;
95 }
96 
97 #define JSON_INDENT() writer_printf(wctx, "%*c", json->indent_level * 4, ' ')
98 
99 static void json_print_section_header(AVTextFormatContext *wctx, const void *data)
100 {
101  JSONContext *json = wctx->priv;
102  AVBPrint buf;
103  const struct AVTextFormatSection *section = wctx->section[wctx->level];
104  const struct AVTextFormatSection *parent_section = wctx->level ?
105  wctx->section[wctx->level-1] : NULL;
106 
107  if (wctx->level && wctx->nb_item[wctx->level-1])
108  writer_put_str(wctx, ",\n");
109 
111  writer_put_str(wctx, "{\n");
112  json->indent_level++;
113  } else {
115  json_escape_str(&buf, section->name, wctx);
116  JSON_INDENT();
117 
118  json->indent_level++;
120  writer_printf(wctx, "\"%s\": [\n", buf.str);
121  } else if (parent_section && !(parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY)) {
122  writer_printf(wctx, "\"%s\": {%s", buf.str, json->item_start_end);
123  } else {
124  writer_printf(wctx, "{%s", json->item_start_end);
125 
126  /* this is required so the parser can distinguish between packets and frames */
127  if (parent_section && parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_NUMBERING_BY_TYPE) {
128  if (!json->compact)
129  JSON_INDENT();
130  writer_printf(wctx, "\"type\": \"%s\"", section->name);
131  wctx->nb_item[wctx->level]++;
132  }
133  }
134  av_bprint_finalize(&buf, NULL);
135  }
136 }
137 
139 {
140  JSONContext *json = wctx->priv;
141  const struct AVTextFormatSection *section = wctx->section[wctx->level];
142 
143  if (wctx->level == 0) {
144  json->indent_level--;
145  writer_put_str(wctx, "\n}\n");
146  } else if (section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY) {
147  writer_w8(wctx, '\n');
148  json->indent_level--;
149  JSON_INDENT();
150  writer_w8(wctx, ']');
151  } else {
152  writer_put_str(wctx, json->item_start_end);
153  json->indent_level--;
154  if (!json->compact)
155  JSON_INDENT();
156  writer_w8(wctx, '}');
157  }
158 }
159 
160 static inline void json_print_item_str(AVTextFormatContext *wctx,
161  const char *key, const char *value)
162 {
163  AVBPrint buf;
164 
166  writer_printf(wctx, "\"%s\":", json_escape_str(&buf, key, wctx));
167  av_bprint_clear(&buf);
168  writer_printf(wctx, " \"%s\"", json_escape_str(&buf, value, wctx));
169  av_bprint_finalize(&buf, NULL);
170 }
171 
172 static void json_print_str(AVTextFormatContext *wctx, const char *key, const char *value)
173 {
174  JSONContext *json = wctx->priv;
175  const struct AVTextFormatSection *parent_section = wctx->level ?
176  wctx->section[wctx->level-1] : NULL;
177 
178  if (wctx->nb_item[wctx->level] || (parent_section && parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_NUMBERING_BY_TYPE))
179  writer_put_str(wctx, json->item_sep);
180  if (!json->compact)
181  JSON_INDENT();
182  json_print_item_str(wctx, key, value);
183 }
184 
185 static void json_print_int(AVTextFormatContext *wctx, const char *key, int64_t value)
186 {
187  JSONContext *json = wctx->priv;
188  const struct AVTextFormatSection *parent_section = wctx->level ?
189  wctx->section[wctx->level-1] : NULL;
190  AVBPrint buf;
191 
192  if (wctx->nb_item[wctx->level] || (parent_section && parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_NUMBERING_BY_TYPE))
193  writer_put_str(wctx, json->item_sep);
194  if (!json->compact)
195  JSON_INDENT();
196 
198  writer_printf(wctx, "\"%s\": %"PRId64, json_escape_str(&buf, key, wctx), value);
199  av_bprint_finalize(&buf, NULL);
200 }
201 
203  .name = "json",
204  .priv_size = sizeof(JSONContext),
205  .init = json_init,
206  .print_section_header = json_print_section_header,
207  .print_section_footer = json_print_section_footer,
208  .print_integer = json_print_int,
209  .print_string = json_print_str,
211  .priv_class = &json_class,
212 };
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:77
AV_BPRINT_SIZE_UNLIMITED
#define AV_BPRINT_SIZE_UNLIMITED
json_options
static const AVOption json_options[]
Definition: tf_json.c:59
opt.h
AVTextFormatContext::section
const struct AVTextFormatSection * section[SECTION_MAX_NB_LEVELS]
section per each level
Definition: avtextformat.h:106
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:97
int64_t
long long int64_t
Definition: coverity.c:34
AVOption
AVOption.
Definition: opt.h:429
data
const char data[16]
Definition: mxf.c:149
avtextformat.h
AVTextFormatContext
Definition: avtextformat.h:88
json_print_int
static void json_print_int(AVTextFormatContext *wctx, const char *key, int64_t value)
Definition: tf_json.c:185
AVTextFormatContext::level
int level
current level, starting from 0
Definition: avtextformat.h:99
AVTextFormatSection::name
const char * name
Definition: avtextformat.h:39
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:46
writer_put_str
#define writer_put_str(wctx_, str_)
Definition: tf_json.c:32
AVTextFormatSection::flags
int flags
Definition: avtextformat.h:48
av_cold
#define av_cold
Definition: attributes.h:90
s
#define s(width, name)
Definition: cbs_vp9.c:198
AVTextFormatter
Definition: avtextformat.h:69
AVTextFormatSection
Definition: avtextformat.h:37
json_init
static av_cold int json_init(AVTextFormatContext *wctx)
Definition: tf_json.c:67
limits.h
AVTextFormatContext::priv
void * priv
private data for use by the filter
Definition: avtextformat.h:94
key
const char * key
Definition: hwcontext_opencl.c:189
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:75
NULL
#define NULL
Definition: coverity.c:32
DEFINE_FORMATTER_CLASS
#define DEFINE_FORMATTER_CLASS(name)
Definition: tf_json.c:35
avtextformatter_json
const AVTextFormatter avtextformatter_json
Definition: tf_json.c:202
init
int(* init)(AVBSFContext *ctx)
Definition: dts2pts.c:368
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:83
AVTextFormatter::name
const char * name
Definition: avtextformat.h:72
json_print_str
static void json_print_str(AVTextFormatContext *wctx, const char *key, const char *value)
Definition: tf_json.c:172
json_print_section_header
static void json_print_section_header(AVTextFormatContext *wctx, const void *data)
Definition: tf_json.c:99
JSONContext::indent_level
int indent_level
Definition: tf_json.c:51
bprint.h
OFFSET
#define OFFSET(x)
Definition: tf_json.c:57
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:60
writer_printf
#define writer_printf(wctx_, fmt_,...)
Definition: tf_json.c:33
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:41
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:53
av_bprint_clear
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
Definition: bprint.c:232
writer_w8
#define writer_w8(wctx_, b_)
Definition: tf_json.c:31
json_print_section_footer
static void json_print_section_footer(AVTextFormatContext *wctx)
Definition: tf_json.c:138
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:102
JSONContext::item_start_end
const char * item_start_end
Definition: tf_json.c:53
AV_OPT_TYPE_BOOL
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
Definition: opt.h:327
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:160
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:42
src
#define src
Definition: vp8dsp.c:248
JSONContext::compact
int compact
Definition: tf_json.c:52
JSONContext
Definition: tf_json.c:49