FFmpeg
tf_compact.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/mem.h>
29 #include <libavutil/avassert.h>
30 #include <libavutil/bprint.h>
31 #include <libavutil/error.h>
32 #include <libavutil/macros.h>
33 #include <libavutil/opt.h>
34 
35 
36 #define writer_w8(wctx_, b_) (wctx_)->writer->writer->writer_w8((wctx_)->writer, b_)
37 #define writer_put_str(wctx_, str_) (wctx_)->writer->writer->writer_put_str((wctx_)->writer, str_)
38 #define writer_printf(wctx_, fmt_, ...) (wctx_)->writer->writer->writer_printf((wctx_)->writer, fmt_, __VA_ARGS__)
39 
40 
41 #define DEFINE_FORMATTER_CLASS(name) \
42 static const char *name##_get_name(void *ctx) \
43 { \
44  return #name ; \
45 } \
46 static const AVClass name##_class = { \
47  .class_name = #name, \
48  .item_name = name##_get_name, \
49  .option = name##_options \
50 }
51 
52 
53 /* Compact output */
54 
55 /**
56  * Apply C-language-like string escaping.
57  */
58 static const char *c_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
59 {
60  const char *p;
61 
62  for (p = src; *p; p++) {
63  switch (*p) {
64  case '\b': av_bprintf(dst, "%s", "\\b"); break;
65  case '\f': av_bprintf(dst, "%s", "\\f"); break;
66  case '\n': av_bprintf(dst, "%s", "\\n"); break;
67  case '\r': av_bprintf(dst, "%s", "\\r"); break;
68  case '\\': av_bprintf(dst, "%s", "\\\\"); break;
69  default:
70  if (*p == sep)
71  av_bprint_chars(dst, '\\', 1);
72  av_bprint_chars(dst, *p, 1);
73  }
74  }
75  return dst->str;
76 }
77 
78 /**
79  * Quote fields containing special characters, check RFC4180.
80  */
81 static const char *csv_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
82 {
83  char meta_chars[] = { sep, '"', '\n', '\r', '\0' };
84  int needs_quoting = !!src[strcspn(src, meta_chars)];
85 
86  if (needs_quoting)
87  av_bprint_chars(dst, '"', 1);
88 
89  for (; *src; src++) {
90  if (*src == '"')
91  av_bprint_chars(dst, '"', 1);
92  av_bprint_chars(dst, *src, 1);
93  }
94  if (needs_quoting)
95  av_bprint_chars(dst, '"', 1);
96  return dst->str;
97 }
98 
99 static const char *none_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
100 {
101  return src;
102 }
103 
104 typedef struct CompactContext {
105  const AVClass *class;
107  char item_sep;
108  int nokey;
111  const char * (*escape_str)(AVBPrint *dst, const char *src, const char sep, void *log_ctx);
116 
117 #undef OFFSET
118 #define OFFSET(x) offsetof(CompactContext, x)
119 
120 static const AVOption compact_options[]= {
121  {"item_sep", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str="|"}, 0, 0 },
122  {"s", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str="|"}, 0, 0 },
123  {"nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
124  {"nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
125  {"escape", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="c"}, 0, 0 },
126  {"e", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="c"}, 0, 0 },
127  {"print_section", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
128  {"p", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
129  {NULL},
130 };
131 
132 DEFINE_FORMATTER_CLASS(compact);
133 
135 {
136  CompactContext *compact = wctx->priv;
137 
138  if (strlen(compact->item_sep_str) != 1) {
139  av_log(wctx, AV_LOG_ERROR, "Item separator '%s' specified, but must contain a single character\n",
140  compact->item_sep_str);
141  return AVERROR(EINVAL);
142  }
143  compact->item_sep = compact->item_sep_str[0];
144 
145  if (!strcmp(compact->escape_mode_str, "none")) compact->escape_str = none_escape_str;
146  else if (!strcmp(compact->escape_mode_str, "c" )) compact->escape_str = c_escape_str;
147  else if (!strcmp(compact->escape_mode_str, "csv" )) compact->escape_str = csv_escape_str;
148  else {
149  av_log(wctx, AV_LOG_ERROR, "Unknown escape mode '%s'\n", compact->escape_mode_str);
150  return AVERROR(EINVAL);
151  }
152 
153  return 0;
154 }
155 
157 {
158  CompactContext *compact = wctx->priv;
159  const struct AVTextFormatSection *section = wctx->section[wctx->level];
160  const struct AVTextFormatSection *parent_section = wctx->level ?
161  wctx->section[wctx->level-1] : NULL;
162  compact->terminate_line[wctx->level] = 1;
163  compact->has_nested_elems[wctx->level] = 0;
164 
165  av_bprint_clear(&wctx->section_pbuf[wctx->level]);
166  if (parent_section &&
170 
171  /* define a prefix for elements not contained in an array or
172  in a wrapper, or for array elements with a type */
173  const char *element_name = (char *)av_x_if_null(section->element_name, section->name);
174  AVBPrint *section_pbuf = &wctx->section_pbuf[wctx->level];
175 
176  compact->nested_section[wctx->level] = 1;
177  compact->has_nested_elems[wctx->level-1] = 1;
178 
179  av_bprintf(section_pbuf, "%s%s",
180  wctx->section_pbuf[wctx->level-1].str, element_name);
181 
183  // add /TYPE to prefix
184  av_bprint_chars(section_pbuf, '/', 1);
185 
186  // normalize section type, replace special characters and lower case
187  for (const char *p = section->get_type(data); *p; p++) {
188  char c =
189  (*p >= '0' && *p <= '9') ||
190  (*p >= 'a' && *p <= 'z') ||
191  (*p >= 'A' && *p <= 'Z') ? av_tolower(*p) : '_';
192  av_bprint_chars(section_pbuf, c, 1);
193  }
194  }
195  av_bprint_chars(section_pbuf, ':', 1);
196 
197  wctx->nb_item[wctx->level] = wctx->nb_item[wctx->level-1];
198  } else {
199  if (parent_section && !(parent_section->flags & (AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER|AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY)) &&
200  wctx->level && wctx->nb_item[wctx->level-1])
201  writer_w8(wctx, compact->item_sep);
202  if (compact->print_section &&
204  writer_printf(wctx, "%s%c", section->name, compact->item_sep);
205  }
206 }
207 
209 {
210  CompactContext *compact = wctx->priv;
211 
212  if (!compact->nested_section[wctx->level] &&
213  compact->terminate_line[wctx->level] &&
215  writer_w8(wctx, '\n');
216 }
217 
218 static void compact_print_str(AVTextFormatContext *wctx, const char *key, const char *value)
219 {
220  CompactContext *compact = wctx->priv;
221  AVBPrint buf;
222 
223  if (wctx->nb_item[wctx->level]) writer_w8(wctx, compact->item_sep);
224  if (!compact->nokey)
225  writer_printf(wctx, "%s%s=", wctx->section_pbuf[wctx->level].str, key);
227  writer_put_str(wctx, compact->escape_str(&buf, value, compact->item_sep, wctx));
228  av_bprint_finalize(&buf, NULL);
229 }
230 
231 static void compact_print_int(AVTextFormatContext *wctx, const char *key, int64_t value)
232 {
233  CompactContext *compact = wctx->priv;
234 
235  if (wctx->nb_item[wctx->level]) writer_w8(wctx, compact->item_sep);
236  if (!compact->nokey)
237  writer_printf(wctx, "%s%s=", wctx->section_pbuf[wctx->level].str, key);
238  writer_printf(wctx, "%"PRId64, value);
239 }
240 
242  .name = "compact",
243  .priv_size = sizeof(CompactContext),
244  .init = compact_init,
245  .print_section_header = compact_print_section_header,
246  .print_section_footer = compact_print_section_footer,
247  .print_integer = compact_print_int,
248  .print_string = compact_print_str,
250  .priv_class = &compact_class,
251 };
252 
253 /* CSV output */
254 
255 #undef OFFSET
256 #define OFFSET(x) offsetof(CompactContext, x)
257 
258 static const AVOption csv_options[] = {
259  {"item_sep", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str=","}, 0, 0 },
260  {"s", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str=","}, 0, 0 },
261  {"nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
262  {"nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
263  {"escape", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="csv"}, 0, 0 },
264  {"e", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="csv"}, 0, 0 },
265  {"print_section", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
266  {"p", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
267  {NULL},
268 };
269 
271 
273  .name = "csv",
274  .priv_size = sizeof(CompactContext),
275  .init = compact_init,
276  .print_section_header = compact_print_section_header,
277  .print_section_footer = compact_print_section_footer,
278  .print_integer = compact_print_int,
279  .print_string = compact_print_str,
281  .priv_class = &csv_class,
282 };
flags
const SwsFlags flags[]
Definition: swscale.c:61
csv_options
static const AVOption csv_options[]
Definition: tf_compact.c:258
AV_BPRINT_SIZE_UNLIMITED
#define AV_BPRINT_SIZE_UNLIMITED
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
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
compact_print_str
static void compact_print_str(AVTextFormatContext *wctx, const char *key, const char *value)
Definition: tf_compact.c:218
CompactContext::print_section
int print_section
Definition: tf_compact.c:109
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
print_section
static void print_section(SectionID id, int level)
Definition: ffprobe.c:2948
avtextformatter_compact
const AVTextFormatter avtextformatter_compact
Definition: tf_compact.c:241
CompactContext
Definition: tf_compact.c:104
compact_print_section_header
static void compact_print_section_header(AVTextFormatContext *wctx, const void *data)
Definition: tf_compact.c:156
AVTextFormatContext::level
int level
current level, starting from 0
Definition: avtextformat.h:99
AVTextFormatSection::name
const char * name
Definition: avtextformat.h:39
macros.h
DEFINE_FORMATTER_CLASS
#define DEFINE_FORMATTER_CLASS(name)
Definition: tf_compact.c:41
AVTextFormatSection::flags
int flags
Definition: avtextformat.h:48
avassert.h
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:209
av_cold
#define av_cold
Definition: attributes.h:90
AVTextFormatSection::element_name
const char * element_name
name of the contained element, if provided
Definition: avtextformat.h:50
AVTextFormatter
Definition: avtextformat.h:69
AVTextFormatSection
Definition: avtextformat.h:37
CompactContext::item_sep
char item_sep
Definition: tf_compact.c:107
limits.h
AVTextFormatContext::priv
void * priv
private data for use by the filter
Definition: avtextformat.h:94
CompactContext::nested_section
int nested_section[SECTION_MAX_NB_LEVELS]
Definition: tf_compact.c:112
key
const char * key
Definition: hwcontext_opencl.c:189
AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE
#define AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE
For these sections the element_name field is mandatory.
Definition: avtextformat.h:45
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:75
NULL
#define NULL
Definition: coverity.c:32
compact_options
static const AVOption compact_options[]
Definition: tf_compact.c:120
compact_print_section_footer
static void compact_print_section_footer(AVTextFormatContext *wctx)
Definition: tf_compact.c:208
c
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
SECTION_MAX_NB_LEVELS
#define SECTION_MAX_NB_LEVELS
Definition: avtextformat.h:85
error.h
writer_w8
#define writer_w8(wctx_, b_)
Definition: tf_compact.c:36
c_escape_str
static const char * c_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
Apply C-language-like string escaping.
Definition: tf_compact.c:58
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
csv
int csv
Definition: checkasm.c:409
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
AVTextFormatContext::section_pbuf
AVBPrint section_pbuf[SECTION_MAX_NB_LEVELS]
generic print buffer dedicated to each section, used by various formatters
Definition: avtextformat.h:107
AVTextFormatSection::get_type
const char *(* get_type)(const void *data)
function returning a type if defined, must be defined when SECTION_FLAG_HAS_TYPE is defined
Definition: avtextformat.h:53
bprint.h
compact_init
static av_cold int compact_init(AVTextFormatContext *wctx)
Definition: tf_compact.c:134
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
CompactContext::escape_str
const char *(* escape_str)(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
Definition: tf_compact.c:111
writer_put_str
#define writer_put_str(wctx_, str_)
Definition: tf_compact.c:37
none_escape_str
static const char * none_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
Definition: tf_compact.c:99
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
CompactContext::nokey
int nokey
Definition: tf_compact.c:108
av_bprint_clear
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
Definition: bprint.c:232
csv_escape_str
static const char * csv_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
Quote fields containing special characters, check RFC4180.
Definition: tf_compact.c:81
mem.h
CompactContext::item_sep_str
char * item_sep_str
Definition: tf_compact.c:106
CompactContext::escape_mode_str
char * escape_mode_str
Definition: tf_compact.c:110
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
CompactContext::has_nested_elems
int has_nested_elems[SECTION_MAX_NB_LEVELS]
Definition: tf_compact.c:113
AV_OPT_TYPE_BOOL
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
Definition: opt.h:327
compact_print_int
static void compact_print_int(AVTextFormatContext *wctx, const char *key, int64_t value)
Definition: tf_compact.c:231
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
OFFSET
#define OFFSET(x)
Definition: tf_compact.c:256
writer_printf
#define writer_printf(wctx_, fmt_,...)
Definition: tf_compact.c:38
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
avtextformatter_csv
const AVTextFormatter avtextformatter_csv
Definition: tf_compact.c:272
AV_TEXTFORMAT_FLAG_SUPPORTS_OPTIONAL_FIELDS
#define AV_TEXTFORMAT_FLAG_SUPPORTS_OPTIONAL_FIELDS
Definition: avtextformat.h:59
AV_OPT_TYPE_STRING
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
Definition: opt.h:276
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
av_tolower
static av_const int av_tolower(int c)
Locale-independent conversion of ASCII characters to lowercase.
Definition: avstring.h:237
CompactContext::terminate_line
int terminate_line[SECTION_MAX_NB_LEVELS]
Definition: tf_compact.c:114
src
#define src
Definition: vp8dsp.c:248
av_x_if_null
static void * av_x_if_null(const void *p, const void *x)
Return x default pointer in case p is NULL.
Definition: avutil.h:312