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