FFmpeg
tf_xml.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 <stdint.h>
22 #include <string.h>
23 
24 #include "avtextformat.h"
25 #include "libavutil/bprint.h"
26 #include "libavutil/error.h"
27 #include "libavutil/opt.h"
28 #include "tf_internal.h"
29 
30 /* XML output */
31 
32 typedef struct XMLContext {
33  const AVClass *class;
38 } XMLContext;
39 
40 #undef OFFSET
41 #define OFFSET(x) offsetof(XMLContext, x)
42 
43 static const AVOption xml_options[] = {
44  { "fully_qualified", "specify if the output should be fully qualified", OFFSET(fully_qualified), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1 },
45  { "q", "specify if the output should be fully qualified", OFFSET(fully_qualified), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1 },
46  { "xsd_strict", "ensure that the output is XSD compliant", OFFSET(xsd_strict), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1 },
47  { "x", "ensure that the output is XSD compliant", OFFSET(xsd_strict), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1 },
48  { NULL },
49 };
50 
52 
54 {
55  XMLContext *xml = wctx->priv;
56 
57  if (xml->xsd_strict) {
58  xml->fully_qualified = 1;
59 #define CHECK_COMPLIANCE(opt, opt_name) \
60  if (opt) { \
61  av_log(wctx, AV_LOG_ERROR, \
62  "XSD-compliant output selected but option '%s' was selected, XML output may be non-compliant.\n" \
63  "You need to disable such option with '-no%s'\n", opt_name, opt_name); \
64  return AVERROR(EINVAL); \
65  }
66  ////CHECK_COMPLIANCE(show_private_data, "private");
67  CHECK_COMPLIANCE(wctx->show_value_unit, "unit");
68  CHECK_COMPLIANCE(wctx->use_value_prefix, "prefix");
69  }
70 
71  return 0;
72 }
73 
74 #define XML_INDENT() writer_printf(wctx, "%*c", xml->indent_level * 4, ' ')
75 
76 static void xml_print_section_header(AVTextFormatContext *wctx, const void *data)
77 {
78  XMLContext *xml = wctx->priv;
79  const AVTextFormatSection *section = tf_get_section(wctx, wctx->level);
80  const AVTextFormatSection *parent_section = tf_get_parent_section(wctx, wctx->level);
81 
82  if (!section)
83  return;
84 
85  if (wctx->level == 0) {
86  const char *qual = " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
87  "xmlns:ffprobe=\"http://www.ffmpeg.org/schema/ffprobe\" "
88  "xsi:schemaLocation=\"http://www.ffmpeg.org/schema/ffprobe ffprobe.xsd\"";
89 
90  writer_put_str(wctx, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
91  writer_printf(wctx, "<%sffprobe%s>\n",
92  xml->fully_qualified ? "ffprobe:" : "",
93  xml->fully_qualified ? qual : "");
94  return;
95  }
96 
97  if (xml->within_tag) {
98  xml->within_tag = 0;
99  writer_put_str(wctx, ">\n");
100  }
101 
102  if (parent_section && (parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER) &&
103  wctx->level && wctx->nb_item[wctx->level - 1])
104  writer_w8(wctx, '\n');
105  xml->indent_level++;
106 
108  XML_INDENT();
109  writer_printf(wctx, "<%s", section->name);
110 
112  AVBPrint buf;
114  av_bprint_escape(&buf, section->get_type(data), NULL,
116  writer_printf(wctx, " type=\"%s\"", buf.str);
117  }
118  writer_printf(wctx, ">\n", section->name);
119  } else {
120  XML_INDENT();
121  writer_printf(wctx, "<%s ", section->name);
122  xml->within_tag = 1;
123  }
124 }
125 
127 {
128  XMLContext *xml = wctx->priv;
129  const AVTextFormatSection *section = tf_get_section(wctx, wctx->level);
130 
131  if (!section)
132  return;
133 
134  if (wctx->level == 0) {
135  writer_printf(wctx, "</%sffprobe>\n", xml->fully_qualified ? "ffprobe:" : "");
136  } else if (xml->within_tag) {
137  xml->within_tag = 0;
138  writer_put_str(wctx, "/>\n");
139  xml->indent_level--;
140  } else {
141  XML_INDENT();
142  writer_printf(wctx, "</%s>\n", section->name);
143  xml->indent_level--;
144  }
145 }
146 
147 static void xml_print_value(AVTextFormatContext *wctx, const char *key,
148  const char *str, int64_t num, const int is_int)
149 {
150  AVBPrint buf;
151  XMLContext *xml = wctx->priv;
152  const AVTextFormatSection *section = tf_get_section(wctx, wctx->level);
153 
154  if (!section)
155  return;
156 
158 
160  xml->indent_level++;
161  XML_INDENT();
162  av_bprint_escape(&buf, key, NULL,
164  writer_printf(wctx, "<%s key=\"%s\"",
165  section->element_name, buf.str);
166  av_bprint_clear(&buf);
167 
168  if (is_int) {
169  writer_printf(wctx, " value=\"%"PRId64"\"/>\n", num);
170  } else {
171  av_bprint_escape(&buf, str, NULL,
173  writer_printf(wctx, " value=\"%s\"/>\n", buf.str);
174  }
175  xml->indent_level--;
176  } else {
177  if (wctx->nb_item[wctx->level])
178  writer_w8(wctx, ' ');
179 
180  if (is_int) {
181  writer_printf(wctx, "%s=\"%"PRId64"\"", key, num);
182  } else {
183  av_bprint_escape(&buf, str, NULL,
185  writer_printf(wctx, "%s=\"%s\"", key, buf.str);
186  }
187  }
188 
189  av_bprint_finalize(&buf, NULL);
190 }
191 
192 static inline void xml_print_str(AVTextFormatContext *wctx, const char *key, const char *value)
193 {
194  xml_print_value(wctx, key, value, 0, 0);
195 }
196 
197 static void xml_print_int(AVTextFormatContext *wctx, const char *key, int64_t value)
198 {
199  xml_print_value(wctx, key, NULL, value, 1);
200 }
201 
203  .name = "xml",
204  .priv_size = sizeof(XMLContext),
205  .init = xml_init,
206  .print_section_header = xml_print_section_header,
207  .print_section_footer = xml_print_section_footer,
208  .print_integer = xml_print_int,
209  .print_string = xml_print_str,
211  .priv_class = &xml_class,
212 };
flags
const SwsFlags flags[]
Definition: swscale.c:61
AV_BPRINT_SIZE_UNLIMITED
#define AV_BPRINT_SIZE_UNLIMITED
opt.h
av_bprint_init
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
avtextformatter_xml
const AVTextFormatter avtextformatter_xml
Definition: tf_xml.c:202
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
AVTextFormatContext::show_value_unit
int show_value_unit
Definition: avtextformat.h:135
avtextformat.h
AVTextFormatContext
Definition: avtextformat.h:112
XMLContext::within_tag
int within_tag
Definition: tf_xml.c:34
AVTextFormatContext::level
int level
current level, starting from 0
Definition: avtextformat.h:123
AVTextFormatSection::name
const char * name
Definition: avtextformat.h:43
xml_print_section_header
static void xml_print_section_header(AVTextFormatContext *wctx, const void *data)
Definition: tf_xml.c:76
AVTextFormatSection::flags
int flags
Definition: avtextformat.h:56
av_cold
#define av_cold
Definition: attributes.h:90
AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES
#define AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES
Within AV_ESCAPE_MODE_XML, additionally escape double quotes for double quoted attributes.
Definition: avstring.h:348
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
AVTextFormatContext::priv
void * priv
private data for use by the filter
Definition: avtextformat.h:118
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
av_bprint_escape
void av_bprint_escape(AVBPrint *dstbuf, const char *src, const char *special_chars, enum AVEscapeMode mode, int flags)
Escape the content in src and append it to dstbuf.
Definition: bprint.c:268
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
xml_print_value
static void xml_print_value(AVTextFormatContext *wctx, const char *key, const char *str, int64_t num, const int is_int)
Definition: tf_xml.c:147
XML_INDENT
#define XML_INDENT()
Definition: tf_xml.c:74
xml_options
static const AVOption xml_options[]
Definition: tf_xml.c:43
error.h
xml_print_int
static void xml_print_int(AVTextFormatContext *wctx, const char *key, int64_t value)
Definition: tf_xml.c:197
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
AVTextFormatter::name
const char * name
Definition: avtextformat.h:97
XMLContext::fully_qualified
int fully_qualified
Definition: tf_xml.c:36
AV_ESCAPE_MODE_XML
@ AV_ESCAPE_MODE_XML
Use XML non-markup character data escaping.
Definition: avstring.h:318
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
xml_init
static av_cold int xml_init(AVTextFormatContext *wctx)
Definition: tf_xml.c:53
writer_put_str
static void writer_put_str(AVTextFormatContext *wctx, const char *str)
Definition: tf_internal.h:68
bprint.h
xml_print_str
static void xml_print_str(AVTextFormatContext *wctx, const char *key, const char *value)
Definition: tf_xml.c:192
AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS
#define AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS
the section may contain a variable number of fields with variable keys.
Definition: avtextformat.h:47
XMLContext::xsd_strict
int xsd_strict
Definition: tf_xml.c:37
xml_print_section_footer
static void xml_print_section_footer(AVTextFormatContext *wctx)
Definition: tf_xml.c:126
CHECK_COMPLIANCE
#define CHECK_COMPLIANCE(opt, opt_name)
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:72
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_bprint_clear
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
Definition: bprint.c:232
AVTextFormatContext::use_value_prefix
int use_value_prefix
Definition: avtextformat.h:136
XMLContext
Definition: tf_xml.c:32
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
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
XMLContext::indent_level
int indent_level
Definition: tf_xml.c:35
OFFSET
#define OFFSET(x)
Definition: tf_xml.c:41
DEFINE_FORMATTER_CLASS
DEFINE_FORMATTER_CLASS(xml)
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