FFmpeg
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
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/bprint.h"
29 #include "libavutil/error.h"
30 #include "libavutil/opt.h"
31 
32 
33 #define writer_w8(wctx_, b_) (wctx_)->writer->writer->writer_w8((wctx_)->writer, b_)
34 #define writer_put_str(wctx_, str_) (wctx_)->writer->writer->writer_put_str((wctx_)->writer, str_)
35 #define writer_printf(wctx_, fmt_, ...) (wctx_)->writer->writer->writer_printf((wctx_)->writer, fmt_, __VA_ARGS__)
36 
37 
38 #define DEFINE_FORMATTER_CLASS(name) \
39 static const char *name##_get_name(void *ctx) \
40 { \
41  return #name ; \
42 } \
43 static const AVClass name##_class = { \
44  .class_name = #name, \
45  .item_name = name##_get_name, \
46  .option = name##_options \
47 }
48 
49 
50 /* Compact output */
51 
52 /**
53  * Apply C-language-like string escaping.
54  */
55 static const char *c_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
56 {
57  const char *p;
58 
59  for (p = src; *p; p++) {
60  switch (*p) {
61  case '\b': av_bprintf(dst, "%s", "\\b"); break;
62  case '\f': av_bprintf(dst, "%s", "\\f"); break;
63  case '\n': av_bprintf(dst, "%s", "\\n"); break;
64  case '\r': av_bprintf(dst, "%s", "\\r"); break;
65  case '\\': av_bprintf(dst, "%s", "\\\\"); break;
66  default:
67  if (*p == sep)
68  av_bprint_chars(dst, '\\', 1);
69  av_bprint_chars(dst, *p, 1);
70  }
71  }
72  return dst->str;
73 }
74 
75 /**
76  * Quote fields containing special characters, check RFC4180.
77  */
78 static const char *csv_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
79 {
80  char meta_chars[] = { sep, '"', '\n', '\r', '\0' };
81  int needs_quoting = !!src[strcspn(src, meta_chars)];
82 
83  if (needs_quoting)
84  av_bprint_chars(dst, '"', 1);
85 
86  for (; *src; src++) {
87  if (*src == '"')
88  av_bprint_chars(dst, '"', 1);
89  av_bprint_chars(dst, *src, 1);
90  }
91  if (needs_quoting)
92  av_bprint_chars(dst, '"', 1);
93  return dst->str;
94 }
95 
96 static const char *none_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
97 {
98  return src;
99 }
100 
101 typedef struct CompactContext {
102  const AVClass *class;
104  char item_sep;
105  int nokey;
108  const char * (*escape_str)(AVBPrint *dst, const char *src, const char sep, void *log_ctx);
113 
114 #undef OFFSET
115 #define OFFSET(x) offsetof(CompactContext, x)
116 
117 static const AVOption compact_options[]= {
118  {"item_sep", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str="|"}, 0, 0 },
119  {"s", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str="|"}, 0, 0 },
120  {"nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
121  {"nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
122  {"escape", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="c"}, 0, 0 },
123  {"e", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="c"}, 0, 0 },
124  {"print_section", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
125  {"p", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
126  {NULL},
127 };
128 
129 DEFINE_FORMATTER_CLASS(compact);
130 
132 {
133  CompactContext *compact = wctx->priv;
134 
135  if (strlen(compact->item_sep_str) != 1) {
136  av_log(wctx, AV_LOG_ERROR, "Item separator '%s' specified, but must contain a single character\n",
137  compact->item_sep_str);
138  return AVERROR(EINVAL);
139  }
140  compact->item_sep = compact->item_sep_str[0];
141 
142  if (!strcmp(compact->escape_mode_str, "none")) compact->escape_str = none_escape_str;
143  else if (!strcmp(compact->escape_mode_str, "c" )) compact->escape_str = c_escape_str;
144  else if (!strcmp(compact->escape_mode_str, "csv" )) compact->escape_str = csv_escape_str;
145  else {
146  av_log(wctx, AV_LOG_ERROR, "Unknown escape mode '%s'\n", compact->escape_mode_str);
147  return AVERROR(EINVAL);
148  }
149 
150  return 0;
151 }
152 
154 {
155  CompactContext *compact = wctx->priv;
156  const struct AVTextFormatSection *section = wctx->section[wctx->level];
157  const struct AVTextFormatSection *parent_section = wctx->level ?
158  wctx->section[wctx->level-1] : NULL;
159  compact->terminate_line[wctx->level] = 1;
160  compact->has_nested_elems[wctx->level] = 0;
161 
162  av_bprint_clear(&wctx->section_pbuf[wctx->level]);
163  if (parent_section &&
167 
168  /* define a prefix for elements not contained in an array or
169  in a wrapper, or for array elements with a type */
170  const char *element_name = (char *)av_x_if_null(section->element_name, section->name);
171  AVBPrint *section_pbuf = &wctx->section_pbuf[wctx->level];
172 
173  compact->nested_section[wctx->level] = 1;
174  compact->has_nested_elems[wctx->level-1] = 1;
175 
176  av_bprintf(section_pbuf, "%s%s",
177  wctx->section_pbuf[wctx->level-1].str, element_name);
178 
180  // add /TYPE to prefix
181  av_bprint_chars(section_pbuf, '/', 1);
182 
183  // normalize section type, replace special characters and lower case
184  for (const char *p = section->get_type(data); *p; p++) {
185  char c =
186  (*p >= '0' && *p <= '9') ||
187  (*p >= 'a' && *p <= 'z') ||
188  (*p >= 'A' && *p <= 'Z') ? av_tolower(*p) : '_';
189  av_bprint_chars(section_pbuf, c, 1);
190  }
191  }
192  av_bprint_chars(section_pbuf, ':', 1);
193 
194  wctx->nb_item[wctx->level] = wctx->nb_item[wctx->level-1];
195  } else {
196  if (parent_section && !(parent_section->flags & (AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER|AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY)) &&
197  wctx->level && wctx->nb_item[wctx->level-1])
198  writer_w8(wctx, compact->item_sep);
199  if (compact->print_section &&
201  writer_printf(wctx, "%s%c", section->name, compact->item_sep);
202  }
203 }
204 
206 {
207  CompactContext *compact = wctx->priv;
208 
209  if (!compact->nested_section[wctx->level] &&
210  compact->terminate_line[wctx->level] &&
212  writer_w8(wctx, '\n');
213 }
214 
215 static void compact_print_str(AVTextFormatContext *wctx, const char *key, const char *value)
216 {
217  CompactContext *compact = wctx->priv;
218  AVBPrint buf;
219 
220  if (wctx->nb_item[wctx->level]) writer_w8(wctx, compact->item_sep);
221  if (!compact->nokey)
222  writer_printf(wctx, "%s%s=", wctx->section_pbuf[wctx->level].str, key);
224  writer_put_str(wctx, compact->escape_str(&buf, value, compact->item_sep, wctx));
225  av_bprint_finalize(&buf, NULL);
226 }
227 
228 static void compact_print_int(AVTextFormatContext *wctx, const char *key, int64_t value)
229 {
230  CompactContext *compact = wctx->priv;
231 
232  if (wctx->nb_item[wctx->level]) writer_w8(wctx, compact->item_sep);
233  if (!compact->nokey)
234  writer_printf(wctx, "%s%s=", wctx->section_pbuf[wctx->level].str, key);
235  writer_printf(wctx, "%"PRId64, value);
236 }
237 
239  .name = "compact",
240  .priv_size = sizeof(CompactContext),
241  .init = compact_init,
242  .print_section_header = compact_print_section_header,
243  .print_section_footer = compact_print_section_footer,
244  .print_integer = compact_print_int,
245  .print_string = compact_print_str,
247  .priv_class = &compact_class,
248 };
249 
250 /* CSV output */
251 
252 #undef OFFSET
253 #define OFFSET(x) offsetof(CompactContext, x)
254 
255 static const AVOption csv_options[] = {
256  {"item_sep", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str=","}, 0, 0 },
257  {"s", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str=","}, 0, 0 },
258  {"nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
259  {"nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
260  {"escape", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="csv"}, 0, 0 },
261  {"e", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="csv"}, 0, 0 },
262  {"print_section", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
263  {"p", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
264  {NULL},
265 };
266 
268 
270  .name = "csv",
271  .priv_size = sizeof(CompactContext),
272  .init = compact_init,
273  .print_section_header = compact_print_section_header,
274  .print_section_footer = compact_print_section_footer,
275  .print_integer = compact_print_int,
276  .print_string = compact_print_str,
278  .priv_class = &csv_class,
279 };
flags
const SwsFlags flags[]
Definition: swscale.c:61
csv_options
static const AVOption csv_options[]
Definition: tf_compact.c:255
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:215
CompactContext::print_section
int print_section
Definition: tf_compact.c:106
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:238
CompactContext
Definition: tf_compact.c:101
compact_print_section_header
static void compact_print_section_header(AVTextFormatContext *wctx, const void *data)
Definition: tf_compact.c:153
AVTextFormatContext::level
int level
current level, starting from 0
Definition: avtextformat.h:99
AVTextFormatSection::name
const char * name
Definition: avtextformat.h:39
DEFINE_FORMATTER_CLASS
#define DEFINE_FORMATTER_CLASS(name)
Definition: tf_compact.c:38
AVTextFormatSection::flags
int flags
Definition: avtextformat.h:48
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:210
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:104
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:109
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:76
NULL
#define NULL
Definition: coverity.c:32
compact_options
static const AVOption compact_options[]
Definition: tf_compact.c:117
compact_print_section_footer
static void compact_print_section_footer(AVTextFormatContext *wctx)
Definition: tf_compact.c:205
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:33
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:55
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:131
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:108
writer_put_str
#define writer_put_str(wctx_, str_)
Definition: tf_compact.c:34
none_escape_str
static const char * none_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
Definition: tf_compact.c:96
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:105
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:78
CompactContext::item_sep_str
char * item_sep_str
Definition: tf_compact.c:103
CompactContext::escape_mode_str
char * escape_mode_str
Definition: tf_compact.c:107
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:110
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:228
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
OFFSET
#define OFFSET(x)
Definition: tf_compact.c:253
writer_printf
#define writer_printf(wctx_, fmt_,...)
Definition: tf_compact.c:35
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:269
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:111
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