Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
F
ffmpeg.wasm-core
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Linshizhi
ffmpeg.wasm-core
Commits
20ac5849
Commit
20ac5849
authored
Oct 08, 2011
by
Stefano Sabatini
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ffprobe: add XML writer
parent
f1a4182e
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
375 additions
and
2 deletions
+375
-2
Changelog
Changelog
+1
-0
Makefile
Makefile
+1
-1
ffprobe.texi
doc/ffprobe.texi
+33
-0
ffprobe.xsd
doc/ffprobe.xsd
+96
-0
ffprobe.c
ffprobe.c
+244
-1
No files found.
Changelog
View file @
20ac5849
...
...
@@ -9,6 +9,7 @@ version next:
- SMJPEG demuxer
- dv: add timecode to metadata
- thumbnail video filter
- XML output in ffprobe
version 0.9:
...
...
Makefile
View file @
20ac5849
...
...
@@ -39,7 +39,7 @@ FFLIBS-$(CONFIG_SWSCALE) += swscale
FFLIBS
:=
avutil
DATA_FILES
:=
$
(
wildcard
$(SRC_PATH)
/presets/
*
.ffpreset
)
DATA_FILES
:=
$
(
wildcard
$(SRC_PATH)
/presets/
*
.ffpreset
)
doc/ffprobe.xsd
SKIPHEADERS
=
cmdutils_common_opts.h
...
...
doc/ffprobe.texi
View file @
20ac5849
...
...
@@ -218,6 +218,39 @@ Each section is printed using JSON notation.
For more information about JSON, see @url
{
http://www.json.org/
}
.
@section xml
XML based format.
The XML output is described in the XML schema description file
@file
{
ffprobe.xsd
}
installed in the FFmpeg datadir.
Note that the output issued will be compliant to the
@file
{
ffprobe.xsd
}
schema only when no special global output options
(@option
{
unit
}
, @option
{
prefix
}
, @option
{
byte
_
binary
_
prefix
}
,
@option
{
sexagesimal
}
etc.) are specified.
This writer accepts options as a list of @var
{
key
}
=@var
{
value
}
pairs,
separated by ":".
The description of the accepted options follows.
@table @option
@item fully
_
qualified, q
If set to 1 specify if the output should be fully qualified. Default
value is 0.
This is required for generating an XML file which can be validated
through an XSD file.
@item xsd
_
compliant, x
If set to 1 perform more checks for ensuring that the output is XSD
compliant. Default value is 0.
This option automatically sets @option
{
fully
_
qualified
}
to 1.
@end table
For more information about the XML format, see
@url
{
http://www.w3.org/XML/
}
.
@c man end WRITERS
@include decoders.texi
...
...
doc/ffprobe.xsd
0 → 100644
View file @
20ac5849
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema
xmlns:xsd=
"http://www.w3.org/2001/XMLSchema"
targetNamespace=
"http://www.ffmpeg.org/schema/ffprobe"
xmlns:ffprobe=
"http://www.ffmpeg.org/schema/ffprobe"
>
<xsd:element
name=
"ffprobe"
type=
"ffprobe:ffprobeType"
/>
<xsd:complexType
name=
"ffprobeType"
>
<xsd:sequence>
<xsd:element
name=
"packets"
type=
"ffprobe:packetsType"
minOccurs=
"0"
maxOccurs=
"1"
/>
<xsd:element
name=
"streams"
type=
"ffprobe:streamsType"
minOccurs=
"0"
maxOccurs=
"1"
/>
<xsd:element
name=
"format"
type=
"ffprobe:formatType"
minOccurs=
"0"
maxOccurs=
"1"
/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType
name=
"packetsType"
>
<xsd:sequence>
<xsd:element
name=
"packet"
type=
"ffprobe:packetType"
minOccurs=
"0"
maxOccurs=
"unbounded"
/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType
name=
"packetType"
>
<xsd:attribute
name=
"codec_type"
type=
"xsd:string"
use=
"required"
/>
<xsd:attribute
name=
"stream_index"
type=
"xsd:int"
use=
"required"
/>
<xsd:attribute
name=
"pts"
type=
"xsd:long"
/>
<xsd:attribute
name=
"pts_time"
type=
"xsd:float"
/>
<xsd:attribute
name=
"dts"
type=
"xsd:long"
/>
<xsd:attribute
name=
"dts_time"
type=
"xsd:float"
/>
<xsd:attribute
name=
"duration"
type=
"xsd:long"
/>
<xsd:attribute
name=
"duration_time"
type=
"xsd:float"
/>
<xsd:attribute
name=
"size"
type=
"xsd:long"
use=
"required"
/>
<xsd:attribute
name=
"pos"
type=
"xsd:long"
/>
<xsd:attribute
name=
"flags"
type=
"xsd:string"
use=
"required"
/>
</xsd:complexType>
<xsd:complexType
name=
"streamsType"
>
<xsd:sequence>
<xsd:element
name=
"stream"
type=
"ffprobe:streamType"
minOccurs=
"0"
maxOccurs=
"unbounded"
/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType
name=
"streamType"
>
<xsd:attribute
name=
"index"
type=
"xsd:int"
use=
"required"
/>
<xsd:attribute
name=
"codec_name"
type=
"xsd:string"
/>
<xsd:attribute
name=
"codec_long_name"
type=
"xsd:string"
/>
<xsd:attribute
name=
"codec_type"
type=
"xsd:string"
/>
<xsd:attribute
name=
"codec_time_base"
type=
"xsd:string"
use=
"required"
/>
<xsd:attribute
name=
"codec_tag"
type=
"xsd:string"
use=
"required"
/>
<xsd:attribute
name=
"codec_tag_string"
type=
"xsd:string"
use=
"required"
/>
<!-- video attributes -->
<xsd:attribute
name=
"width"
type=
"xsd:int"
/>
<xsd:attribute
name=
"height"
type=
"xsd:int"
/>
<xsd:attribute
name=
"has_b_frames"
type=
"xsd:int"
/>
<xsd:attribute
name=
"sample_aspect_ratio"
type=
"xsd:string"
/>
<xsd:attribute
name=
"display_aspect_ratio"
type=
"xsd:string"
/>
<xsd:attribute
name=
"pix_fmt"
type=
"xsd:string"
/>
<xsd:attribute
name=
"level"
type=
"xsd:int"
/>
<xsd:attribute
name=
"timecode"
type=
"xsd:string"
/>
<!-- audio attributes -->
<xsd:attribute
name=
"sample_fmt"
type=
"xsd:string"
/>
<xsd:attribute
name=
"sample_rate"
type=
"xsd:int"
/>
<xsd:attribute
name=
"channels"
type=
"xsd:int"
/>
<xsd:attribute
name=
"bits_per_sample"
type=
"xsd:int"
/>
<xsd:attribute
name=
"id"
type=
"xsd:string"
/>
<xsd:attribute
name=
"r_frame_rate"
type=
"xsd:string"
use=
"required"
/>
<xsd:attribute
name=
"avg_frame_rate"
type=
"xsd:string"
use=
"required"
/>
<xsd:attribute
name=
"time_base"
type=
"xsd:string"
use=
"required"
/>
<xsd:attribute
name=
"start_time"
type=
"xsd:float"
/>
<xsd:attribute
name=
"duration"
type=
"xsd:float"
/>
<xsd:attribute
name=
"nb_frames"
type=
"xsd:int"
/>
</xsd:complexType>
<xsd:complexType
name=
"formatType"
>
<xsd:sequence>
<xsd:element
name=
"tag"
type=
"ffprobe:tagType"
minOccurs=
"0"
maxOccurs=
"unbounded"
/>
</xsd:sequence>
<xsd:attribute
name=
"filename"
type=
"xsd:string"
use=
"required"
/>
<xsd:attribute
name=
"nb_streams"
type=
"xsd:int"
use=
"required"
/>
<xsd:attribute
name=
"format_name"
type=
"xsd:string"
use=
"required"
/>
<xsd:attribute
name=
"format_long_name"
type=
"xsd:string"
use=
"required"
/>
<xsd:attribute
name=
"start_time"
type=
"xsd:float"
/>
<xsd:attribute
name=
"duration"
type=
"xsd:float"
/>
<xsd:attribute
name=
"size"
type=
"xsd:long"
/>
<xsd:attribute
name=
"bit_rate"
type=
"xsd:long"
/>
</xsd:complexType>
<xsd:complexType
name=
"tagType"
>
<xsd:attribute
name=
"key"
type=
"xsd:string"
use=
"required"
/>
<xsd:attribute
name=
"value"
type=
"xsd:string"
use=
"required"
/>
</xsd:complexType>
</xsd:schema>
ffprobe.c
View file @
20ac5849
...
...
@@ -867,6 +867,248 @@ static const Writer json_writer = {
.
show_tags
=
json_show_tags
,
};
/* XML output */
typedef
struct
{
const
AVClass
*
class
;
int
within_tag
;
int
multiple_entries
;
///< tells if the given chapter requires multiple entries
int
indent_level
;
int
fully_qualified
;
int
xsd_strict
;
char
*
buf
;
size_t
buf_size
;
}
XMLContext
;
#undef OFFSET
#define OFFSET(x) offsetof(XMLContext, x)
static
const
AVOption
xml_options
[]
=
{
{
"fully_qualified"
,
"specify if the output should be fully qualified"
,
OFFSET
(
fully_qualified
),
AV_OPT_TYPE_INT
,
{.
dbl
=
0
},
0
,
1
},
{
"q"
,
"specify if the output should be fully qualified"
,
OFFSET
(
fully_qualified
),
AV_OPT_TYPE_INT
,
{.
dbl
=
0
},
0
,
1
},
{
"xsd_strict"
,
"ensure that the output is XSD compliant"
,
OFFSET
(
xsd_strict
),
AV_OPT_TYPE_INT
,
{.
dbl
=
0
},
0
,
1
},
{
"x"
,
"ensure that the output is XSD compliant"
,
OFFSET
(
xsd_strict
),
AV_OPT_TYPE_INT
,
{.
dbl
=
0
},
0
,
1
},
{
NULL
},
};
static
const
char
*
xml_get_name
(
void
*
ctx
)
{
return
"xml"
;
}
static
const
AVClass
xml_class
=
{
"XMLContext"
,
xml_get_name
,
xml_options
};
static
av_cold
int
xml_init
(
WriterContext
*
wctx
,
const
char
*
args
,
void
*
opaque
)
{
XMLContext
*
xml
=
wctx
->
priv
;
int
err
;
xml
->
class
=
&
xml_class
;
av_opt_set_defaults
(
xml
);
if
(
args
&&
(
err
=
(
av_set_options_string
(
xml
,
args
,
"="
,
":"
)))
<
0
)
{
av_log
(
wctx
,
AV_LOG_ERROR
,
"Error parsing options string: '%s'
\n
"
,
args
);
return
err
;
}
if
(
xml
->
xsd_strict
)
{
xml
->
fully_qualified
=
1
;
#define CHECK_COMPLIANCE(opt, opt_name) \
if (opt) { \
av_log(wctx, AV_LOG_ERROR, \
"XSD-compliant output selected but option '%s' was selected, XML output may be non-compliant.\n" \
"You need to disable such option with '-no%s'\n", opt_name, opt_name); \
}
CHECK_COMPLIANCE
(
show_private_data
,
"private"
);
CHECK_COMPLIANCE
(
show_value_unit
,
"unit"
);
CHECK_COMPLIANCE
(
use_value_prefix
,
"prefix"
);
}
xml
->
buf_size
=
ESCAPE_INIT_BUF_SIZE
;
if
(
!
(
xml
->
buf
=
av_malloc
(
xml
->
buf_size
)))
return
AVERROR
(
ENOMEM
);
return
0
;
}
static
av_cold
void
xml_uninit
(
WriterContext
*
wctx
)
{
XMLContext
*
xml
=
wctx
->
priv
;
av_freep
(
&
xml
->
buf
);
}
static
const
char
*
xml_escape_str
(
char
**
dst
,
size_t
*
dst_size
,
const
char
*
src
,
void
*
log_ctx
)
{
const
char
*
p
;
char
*
q
;
size_t
size
=
1
;
/* precompute size */
for
(
p
=
src
;
*
p
;
p
++
,
size
++
)
{
ESCAPE_CHECK_SIZE
(
src
,
size
,
SIZE_MAX
-
10
);
switch
(
*
p
)
{
case
'&'
:
size
+=
strlen
(
"&"
);
break
;
case
'<'
:
size
+=
strlen
(
"<"
);
break
;
case
'>'
:
size
+=
strlen
(
">"
);
break
;
case
'\"'
:
size
+=
strlen
(
"""
);
break
;
case
'\''
:
size
+=
strlen
(
"'"
);
break
;
default:
size
++
;
}
}
ESCAPE_REALLOC_BUF
(
dst_size
,
dst
,
src
,
size
);
#define COPY_STR(str) { \
const char *s = str; \
while (*s) \
*q++ = *s++; \
}
p
=
src
;
q
=
*
dst
;
while
(
*
p
)
{
switch
(
*
p
)
{
case
'&'
:
COPY_STR
(
"&"
);
break
;
case
'<'
:
COPY_STR
(
"<"
);
break
;
case
'>'
:
COPY_STR
(
">"
);
break
;
case
'\"'
:
COPY_STR
(
"""
);
break
;
case
'\''
:
COPY_STR
(
"'"
);
break
;
default:
*
q
++
=
*
p
;
}
p
++
;
}
*
q
=
0
;
return
*
dst
;
}
static
void
xml_print_header
(
WriterContext
*
wctx
)
{
XMLContext
*
xml
=
wctx
->
priv
;
const
char
*
qual
=
" xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' "
"xmlns:ffprobe='http://www.ffmpeg.org/schema/ffprobe' "
"xsi:schemaLocation='http://www.ffmpeg.org/schema/ffprobe ffprobe.xsd'"
;
printf
(
"<?xml version=
\"
1.0
\"
encoding=
\"
UTF-8
\"
?>
\n
"
);
printf
(
"<%sffprobe%s>
\n
"
,
xml
->
fully_qualified
?
"ffprobe:"
:
""
,
xml
->
fully_qualified
?
qual
:
""
);
xml
->
indent_level
++
;
}
static
void
xml_print_footer
(
WriterContext
*
wctx
)
{
XMLContext
*
xml
=
wctx
->
priv
;
xml
->
indent_level
--
;
printf
(
"</%sffprobe>
\n
"
,
xml
->
fully_qualified
?
"ffprobe:"
:
""
);
}
#define XML_INDENT() { int i; for (i = 0; i < xml->indent_level; i++) printf(INDENT); }
static
void
xml_print_chapter_header
(
WriterContext
*
wctx
,
const
char
*
chapter
)
{
XMLContext
*
xml
=
wctx
->
priv
;
if
(
wctx
->
nb_chapter
)
printf
(
"
\n
"
);
xml
->
multiple_entries
=
!
strcmp
(
chapter
,
"packets"
)
||
!
strcmp
(
chapter
,
"streams"
);
if
(
xml
->
multiple_entries
)
{
XML_INDENT
();
printf
(
"<%s>
\n
"
,
chapter
);
xml
->
indent_level
++
;
}
}
static
void
xml_print_chapter_footer
(
WriterContext
*
wctx
,
const
char
*
chapter
)
{
XMLContext
*
xml
=
wctx
->
priv
;
if
(
xml
->
multiple_entries
)
{
xml
->
indent_level
--
;
XML_INDENT
();
printf
(
"</%s>
\n
"
,
chapter
);
}
}
static
void
xml_print_section_header
(
WriterContext
*
wctx
,
const
char
*
section
)
{
XMLContext
*
xml
=
wctx
->
priv
;
XML_INDENT
();
printf
(
"<%s "
,
section
);
xml
->
within_tag
=
1
;
}
static
void
xml_print_section_footer
(
WriterContext
*
wctx
,
const
char
*
section
)
{
XMLContext
*
xml
=
wctx
->
priv
;
if
(
xml
->
within_tag
)
printf
(
"/>
\n
"
);
else
{
XML_INDENT
();
printf
(
"</%s>
\n
"
,
section
);
}
}
static
void
xml_print_str
(
WriterContext
*
wctx
,
const
char
*
key
,
const
char
*
value
)
{
XMLContext
*
xml
=
wctx
->
priv
;
if
(
wctx
->
nb_item
)
printf
(
" "
);
printf
(
"%s=
\"
%s
\"
"
,
key
,
xml_escape_str
(
&
xml
->
buf
,
&
xml
->
buf_size
,
value
,
wctx
));
}
static
void
xml_print_int
(
WriterContext
*
wctx
,
const
char
*
key
,
long
long
int
value
)
{
if
(
wctx
->
nb_item
)
printf
(
" "
);
printf
(
"%s=
\"
%lld
\"
"
,
key
,
value
);
}
static
void
xml_show_tags
(
WriterContext
*
wctx
,
AVDictionary
*
dict
)
{
XMLContext
*
xml
=
wctx
->
priv
;
AVDictionaryEntry
*
tag
=
NULL
;
int
is_first
=
1
;
xml
->
indent_level
++
;
while
((
tag
=
av_dict_get
(
dict
,
""
,
tag
,
AV_DICT_IGNORE_SUFFIX
)))
{
if
(
is_first
)
{
/* close section tag */
printf
(
">
\n
"
);
xml
->
within_tag
=
0
;
is_first
=
0
;
}
XML_INDENT
();
printf
(
"<tag key=
\"
%s
\"
"
,
xml_escape_str
(
&
xml
->
buf
,
&
xml
->
buf_size
,
tag
->
key
,
wctx
));
printf
(
" value=
\"
%s
\"
/>
\n
"
,
xml_escape_str
(
&
xml
->
buf
,
&
xml
->
buf_size
,
tag
->
value
,
wctx
));
}
xml
->
indent_level
--
;
}
static
Writer
xml_writer
=
{
.
name
=
"xml"
,
.
priv_size
=
sizeof
(
XMLContext
),
.
init
=
xml_init
,
.
uninit
=
xml_uninit
,
.
print_header
=
xml_print_header
,
.
print_footer
=
xml_print_footer
,
.
print_chapter_header
=
xml_print_chapter_header
,
.
print_chapter_footer
=
xml_print_chapter_footer
,
.
print_section_header
=
xml_print_section_header
,
.
print_section_footer
=
xml_print_section_footer
,
.
print_integer
=
xml_print_int
,
.
print_string
=
xml_print_str
,
.
show_tags
=
xml_show_tags
,
};
static
void
writer_register_all
(
void
)
{
static
int
initialized
;
...
...
@@ -879,6 +1121,7 @@ static void writer_register_all(void)
writer_register
(
&
compact_writer
);
writer_register
(
&
csv_writer
);
writer_register
(
&
json_writer
);
writer_register
(
&
xml_writer
);
}
#define print_fmt(k, f, ...) do { \
...
...
@@ -1236,7 +1479,7 @@ static const OptionDef options[] = {
{
"pretty"
,
0
,
{(
void
*
)
&
opt_pretty
},
"prettify the format of displayed values, make it more human readable"
},
{
"print_format"
,
OPT_STRING
|
HAS_ARG
,
{(
void
*
)
&
print_format
},
"set the output printing format (available formats are: default, compact, csv, json)"
,
"format"
},
"set the output printing format (available formats are: default, compact, csv, json
, xml
)"
,
"format"
},
{
"show_format"
,
OPT_BOOL
,
{(
void
*
)
&
do_show_format
}
,
"show format/container info"
},
{
"show_packets"
,
OPT_BOOL
,
{(
void
*
)
&
do_show_packets
},
"show packets info"
},
{
"show_streams"
,
OPT_BOOL
,
{(
void
*
)
&
do_show_streams
},
"show streams info"
},
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment