FFmpeg
Loading...
Searching...
No Matches
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 <inttypes.h>
22#include <limits.h>
23#include <stdarg.h>
24#include <string.h>
25
26#include "avtextformat.h"
27#include "libavutil/bprint.h"
28#include "libavutil/opt.h"
29#include "tf_internal.h"
30
31/* JSON output */
32
33typedef struct JSONContext {
34 const AVClass *class;
37 const char *item_sep, *item_start_end;
39
40#undef OFFSET
41#define OFFSET(x) offsetof(JSONContext, x)
42
43static const AVOption json_options[] = {
44 { "compact", "enable compact output", OFFSET(compact), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1 },
45 { "c", "enable compact output", OFFSET(compact), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1 },
46 { NULL }
47};
48
50
52{
53 JSONContext *json = wctx->priv;
54
55 json->item_sep = json->compact ? ", " : ",\n";
56 json->item_start_end = json->compact ? " " : "\n";
57
58 return 0;
59}
60
61static const char *json_escape_str(AVBPrint *dst, const char *src, void *log_ctx)
62{
63 static const char json_escape[] = { '"', '\\', '\b', '\f', '\n', '\r', '\t', 0 };
64 static const char json_subst[] = { '"', '\\', 'b', 'f', 'n', 'r', 't', 0 };
65 const char *p;
66
67 if (!src) {
68 av_log(log_ctx, AV_LOG_WARNING, "Cannot escape NULL string, returning NULL\n");
69 return NULL;
70 }
71
72 for (p = src; *p; p++) {
73 const char *s = strchr(json_escape, *p);
74 if (s) {
75 av_bprint_chars(dst, '\\', 1);
76 av_bprint_chars(dst, json_subst[s - json_escape], 1);
77 } else if ((unsigned char)*p < 32) {
78 av_bprintf(dst, "\\u00%02x", (unsigned char)*p);
79 } else {
80 av_bprint_chars(dst, *p, 1);
81 }
82 }
83 return dst->str;
84}
85
86#define JSON_INDENT() writer_printf(wctx, "%*c", json->indent_level * 4, ' ')
87
88static void json_print_section_header(AVTextFormatContext *wctx, const void *data)
89{
90 const AVTextFormatSection *section = tf_get_section(wctx, wctx->level);
91 const AVTextFormatSection *parent_section = tf_get_parent_section(wctx, wctx->level);
92 JSONContext *json = wctx->priv;
93 AVBPrint buf;
94
95 if (!section)
96 return;
97
98 if (wctx->level && wctx->nb_item[wctx->level - 1])
99 writer_put_str(wctx, ",\n");
100
102 writer_put_str(wctx, "{\n");
103 json->indent_level++;
104 } else {
106 json_escape_str(&buf, section->name, wctx);
107 JSON_INDENT();
108
109 json->indent_level++;
111 writer_printf(wctx, "\"%s\": [\n", buf.str);
112 } else if (parent_section && !(parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY)) {
113 writer_printf(wctx, "\"%s\": {%s", buf.str, json->item_start_end);
114 } else {
115 writer_printf(wctx, "{%s", json->item_start_end);
116
117 /* this is required so the parser can distinguish between packets and frames */
118 if (parent_section && parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_NUMBERING_BY_TYPE) {
119 if (!json->compact)
120 JSON_INDENT();
121 writer_printf(wctx, "\"type\": \"%s\"", section->name);
122 wctx->nb_item[wctx->level]++;
123 }
124 }
126 }
127}
128
130{
131 const AVTextFormatSection *section = tf_get_section(wctx, wctx->level);
132 JSONContext *json = wctx->priv;
133
134 if (!section)
135 return;
136
137 if (wctx->level == 0) {
138 json->indent_level--;
139 writer_put_str(wctx, "\n}\n");
140 } else if (section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY) {
141 writer_w8(wctx, '\n');
142 json->indent_level--;
143 JSON_INDENT();
144 writer_w8(wctx, ']');
145 } else {
146 writer_put_str(wctx, json->item_start_end);
147 json->indent_level--;
148 if (!json->compact)
149 JSON_INDENT();
150 writer_w8(wctx, '}');
151 }
152}
153
155 const char *key, const char *value)
156{
157 AVBPrint buf;
158
160 writer_printf(wctx, "\"%s\":", json_escape_str(&buf, key, wctx));
161 av_bprint_clear(&buf);
162 writer_printf(wctx, " \"%s\"", json_escape_str(&buf, value, wctx));
164}
165
166static void json_print_str(AVTextFormatContext *wctx, const char *key, const char *value)
167{
168 const AVTextFormatSection *section = tf_get_section(wctx, wctx->level);
169 const AVTextFormatSection *parent_section = tf_get_parent_section(wctx, wctx->level);
170 JSONContext *json = wctx->priv;
171
172 if (!section)
173 return;
174
175 if (wctx->nb_item[wctx->level] || (parent_section && parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_NUMBERING_BY_TYPE))
176 writer_put_str(wctx, json->item_sep);
177 if (!json->compact)
178 JSON_INDENT();
180}
181
182static void json_print_int(AVTextFormatContext *wctx, const char *key, int64_t value)
183{
184 const AVTextFormatSection *section = tf_get_section(wctx, wctx->level);
185 const AVTextFormatSection *parent_section = tf_get_parent_section(wctx, wctx->level);
186 JSONContext *json = wctx->priv;
187 AVBPrint buf;
188
189 if (!section)
190 return;
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);
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};
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition dsp.h:87
#define AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER
the section only contains other sections, but has no data at its own level
#define AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY
the section contains an array of elements of the same type
const AVTextFormatter avtextformatter_json
Definition tf_json.c:202
#define AV_TEXTFORMAT_FLAG_SUPPORTS_MIXED_ARRAY_CONTENT
#define AV_TEXTFORMAT_SECTION_FLAG_NUMBERING_BY_TYPE
the items in this array section should be numbered individually by type
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition bprint.c:122
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition bprint.c:69
AVBPrint public header.
#define AV_BPRINT_SIZE_UNLIMITED
#define flags(name, subs,...)
Definition cbs_h264.c:74
#define s(width, name)
Definition cbs_vp9.c:198
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
int(* init)(AVBSFContext *ctx)
Definition dts2pts.c:608
double value
Definition eval.c:102
const char * key
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
Definition opt.h:326
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition bprint.c:235
void av_bprint_chars(AVBPrint *buf, char c, unsigned n)
Append char c n times to a print buffer.
Definition bprint.c:130
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
Definition bprint.c:227
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition log.h:216
#define av_cold
Definition attributes.h:117
const char data[16]
Definition mxf.c:149
AVOptions.
Describe the class of an AVClass context structure.
Definition log.h:76
AVOption.
Definition opt.h:428
void * priv
private data for use by the filter
int level
current level, starting from 0
unsigned int nb_item[SECTION_MAX_NB_LEVELS]
number of the item printed in the given section, starting from 0
const char * name
int compact
Definition tf_json.c:36
const char * item_sep
Definition tf_json.c:37
int indent_level
Definition tf_json.c:35
const char * item_start_end
Definition tf_json.c:37
#define av_log(a,...)
#define src
Definition vp8dsp.c:248
Internal utilities for text formatters.
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
static const AVTextFormatSection * tf_get_parent_section(AVTextFormatContext *tfc, int level)
Safely access the parent section.
Definition tf_internal.h:55
#define DEFINE_FORMATTER_CLASS(name)
Definition tf_internal.h:31
static void writer_w8(AVTextFormatContext *wctx, int b)
Definition tf_internal.h:63
static void writer_printf(AVTextFormatContext *wctx, const char *fmt,...)
Definition tf_internal.h:73
static void writer_put_str(AVTextFormatContext *wctx, const char *str)
Definition tf_internal.h:68
static void json_print_section_header(AVTextFormatContext *wctx, const void *data)
Definition tf_json.c:88
static av_cold int json_init(AVTextFormatContext *wctx)
Definition tf_json.c:51
static void json_print_str(AVTextFormatContext *wctx, const char *key, const char *value)
Definition tf_json.c:166
static void json_print_int(AVTextFormatContext *wctx, const char *key, int64_t value)
Definition tf_json.c:182
static const char * json_escape_str(AVBPrint *dst, const char *src, void *log_ctx)
Definition tf_json.c:61
static void json_print_section_footer(AVTextFormatContext *wctx)
Definition tf_json.c:129
static void json_print_item_str(AVTextFormatContext *wctx, const char *key, const char *value)
Definition tf_json.c:154
static const AVOption json_options[]
Definition tf_json.c:43
#define OFFSET(x)
Definition tf_json.c:41
#define JSON_INDENT()
Definition tf_json.c:86