2 * Copyright (c) 2007-2010 Stefano Sabatini
4 * This file is part of FFmpeg.
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.
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.
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
23 * simple media prober based on the FFmpeg libraries
27 #include "libavutil/ffversion.h"
31 #include "libavformat/avformat.h"
32 #include "libavcodec/avcodec.h"
33 #include "libavutil/avassert.h"
34 #include "libavutil/avstring.h"
35 #include "libavutil/bprint.h"
36 #include "libavutil/hash.h"
37 #include "libavutil/opt.h"
38 #include "libavutil/pixdesc.h"
39 #include "libavutil/dict.h"
40 #include "libavutil/libm.h"
41 #include "libavutil/parseutils.h"
42 #include "libavutil/timecode.h"
43 #include "libavutil/timestamp.h"
44 #include "libavdevice/avdevice.h"
45 #include "libswscale/swscale.h"
46 #include "libswresample/swresample.h"
47 #include "libpostproc/postprocess.h"
50 const char program_name
[] = "ffprobe";
51 const int program_birth_year
= 2007;
53 static int do_bitexact
= 0;
54 static int do_count_frames
= 0;
55 static int do_count_packets
= 0;
56 static int do_read_frames
= 0;
57 static int do_read_packets
= 0;
58 static int do_show_chapters
= 0;
59 static int do_show_error
= 0;
60 static int do_show_format
= 0;
61 static int do_show_frames
= 0;
62 static int do_show_packets
= 0;
63 static int do_show_programs
= 0;
64 static int do_show_streams
= 0;
65 static int do_show_stream_disposition
= 0;
66 static int do_show_data
= 0;
67 static int do_show_program_version
= 0;
68 static int do_show_library_versions
= 0;
70 static int do_show_chapter_tags
= 0;
71 static int do_show_format_tags
= 0;
72 static int do_show_frame_tags
= 0;
73 static int do_show_program_tags
= 0;
74 static int do_show_stream_tags
= 0;
76 static int show_value_unit
= 0;
77 static int use_value_prefix
= 0;
78 static int use_byte_value_binary_prefix
= 0;
79 static int use_value_sexagesimal_format
= 0;
80 static int show_private_data
= 1;
82 static char *print_format
;
83 static char *stream_specifier
;
84 static char *show_data_hash
;
87 int id
; ///< identifier
88 int64_t start
, end
; ///< start, end in second/AV_TIME_BASE units
89 int has_start
, has_end
;
90 int start_is_offset
, end_is_offset
;
94 static ReadInterval
*read_intervals
;
95 static int read_intervals_nb
= 0;
97 /* section structure definition */
99 #define SECTION_MAX_NB_CHILDREN 10
102 int id
; ///< unique id identifying a section
105 #define SECTION_FLAG_IS_WRAPPER 1 ///< the section only contains other sections, but has no data at its own level
106 #define SECTION_FLAG_IS_ARRAY 2 ///< the section contains an array of elements of the same type
107 #define SECTION_FLAG_HAS_VARIABLE_FIELDS 4 ///< the section may contain a variable number of fields with variable keys.
108 /// For these sections the element_name field is mandatory.
110 int children_ids
[SECTION_MAX_NB_CHILDREN
+1]; ///< list of children section IDS, terminated by -1
111 const char *element_name
; ///< name of the contained element, if provided
112 const char *unique_name
; ///< unique section name, in case the name is ambiguous
113 AVDictionary
*entries_to_show
;
114 int show_all_entries
;
118 SECTION_ID_NONE
= -1,
120 SECTION_ID_CHAPTER_TAGS
,
124 SECTION_ID_FORMAT_TAGS
,
127 SECTION_ID_FRAME_TAGS
,
128 SECTION_ID_FRAME_SIDE_DATA_LIST
,
129 SECTION_ID_FRAME_SIDE_DATA
,
130 SECTION_ID_LIBRARY_VERSION
,
131 SECTION_ID_LIBRARY_VERSIONS
,
134 SECTION_ID_PACKETS_AND_FRAMES
,
135 SECTION_ID_PROGRAM_STREAM_DISPOSITION
,
136 SECTION_ID_PROGRAM_STREAM_TAGS
,
138 SECTION_ID_PROGRAM_STREAMS
,
139 SECTION_ID_PROGRAM_STREAM
,
140 SECTION_ID_PROGRAM_TAGS
,
141 SECTION_ID_PROGRAM_VERSION
,
145 SECTION_ID_STREAM_DISPOSITION
,
147 SECTION_ID_STREAM_TAGS
,
151 static struct section sections
[] = {
152 [SECTION_ID_CHAPTERS
] = { SECTION_ID_CHAPTERS
, "chapters", SECTION_FLAG_IS_ARRAY
, { SECTION_ID_CHAPTER
, -1 } },
153 [SECTION_ID_CHAPTER
] = { SECTION_ID_CHAPTER
, "chapter", 0, { SECTION_ID_CHAPTER_TAGS
, -1 } },
154 [SECTION_ID_CHAPTER_TAGS
] = { SECTION_ID_CHAPTER_TAGS
, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS
, { -1 }, .element_name
= "tag", .unique_name
= "chapter_tags" },
155 [SECTION_ID_ERROR
] = { SECTION_ID_ERROR
, "error", 0, { -1 } },
156 [SECTION_ID_FORMAT
] = { SECTION_ID_FORMAT
, "format", 0, { SECTION_ID_FORMAT_TAGS
, -1 } },
157 [SECTION_ID_FORMAT_TAGS
] = { SECTION_ID_FORMAT_TAGS
, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS
, { -1 }, .element_name
= "tag", .unique_name
= "format_tags" },
158 [SECTION_ID_FRAMES
] = { SECTION_ID_FRAMES
, "frames", SECTION_FLAG_IS_ARRAY
, { SECTION_ID_FRAME
, SECTION_ID_SUBTITLE
, -1 } },
159 [SECTION_ID_FRAME
] = { SECTION_ID_FRAME
, "frame", 0, { SECTION_ID_FRAME_TAGS
, SECTION_ID_FRAME_SIDE_DATA_LIST
, -1 } },
160 [SECTION_ID_FRAME_TAGS
] = { SECTION_ID_FRAME_TAGS
, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS
, { -1 }, .element_name
= "tag", .unique_name
= "frame_tags" },
161 [SECTION_ID_FRAME_SIDE_DATA_LIST
] ={ SECTION_ID_FRAME_SIDE_DATA_LIST
, "side_data_list", SECTION_FLAG_IS_ARRAY
, { SECTION_ID_FRAME_SIDE_DATA
, -1 } },
162 [SECTION_ID_FRAME_SIDE_DATA
] = { SECTION_ID_FRAME_SIDE_DATA
, "side_data", 0, { -1 } },
163 [SECTION_ID_LIBRARY_VERSIONS
] = { SECTION_ID_LIBRARY_VERSIONS
, "library_versions", SECTION_FLAG_IS_ARRAY
, { SECTION_ID_LIBRARY_VERSION
, -1 } },
164 [SECTION_ID_LIBRARY_VERSION
] = { SECTION_ID_LIBRARY_VERSION
, "library_version", 0, { -1 } },
165 [SECTION_ID_PACKETS
] = { SECTION_ID_PACKETS
, "packets", SECTION_FLAG_IS_ARRAY
, { SECTION_ID_PACKET
, -1} },
166 [SECTION_ID_PACKETS_AND_FRAMES
] = { SECTION_ID_PACKETS_AND_FRAMES
, "packets_and_frames", SECTION_FLAG_IS_ARRAY
, { SECTION_ID_PACKET
, -1} },
167 [SECTION_ID_PACKET
] = { SECTION_ID_PACKET
, "packet", 0, { -1 } },
168 [SECTION_ID_PROGRAM_STREAM_DISPOSITION
] = { SECTION_ID_PROGRAM_STREAM_DISPOSITION
, "disposition", 0, { -1 }, .unique_name
= "program_stream_disposition" },
169 [SECTION_ID_PROGRAM_STREAM_TAGS
] = { SECTION_ID_PROGRAM_STREAM_TAGS
, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS
, { -1 }, .element_name
= "tag", .unique_name
= "program_stream_tags" },
170 [SECTION_ID_PROGRAM
] = { SECTION_ID_PROGRAM
, "program", 0, { SECTION_ID_PROGRAM_TAGS
, SECTION_ID_PROGRAM_STREAMS
, -1 } },
171 [SECTION_ID_PROGRAM_STREAMS
] = { SECTION_ID_PROGRAM_STREAMS
, "streams", SECTION_FLAG_IS_ARRAY
, { SECTION_ID_PROGRAM_STREAM
, -1 }, .unique_name
= "program_streams" },
172 [SECTION_ID_PROGRAM_STREAM
] = { SECTION_ID_PROGRAM_STREAM
, "stream", 0, { SECTION_ID_PROGRAM_STREAM_DISPOSITION
, SECTION_ID_PROGRAM_STREAM_TAGS
, -1 }, .unique_name
= "program_stream" },
173 [SECTION_ID_PROGRAM_TAGS
] = { SECTION_ID_PROGRAM_TAGS
, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS
, { -1 }, .element_name
= "tag", .unique_name
= "program_tags" },
174 [SECTION_ID_PROGRAM_VERSION
] = { SECTION_ID_PROGRAM_VERSION
, "program_version", 0, { -1 } },
175 [SECTION_ID_PROGRAMS
] = { SECTION_ID_PROGRAMS
, "programs", SECTION_FLAG_IS_ARRAY
, { SECTION_ID_PROGRAM
, -1 } },
176 [SECTION_ID_ROOT
] = { SECTION_ID_ROOT
, "root", SECTION_FLAG_IS_WRAPPER
,
177 { SECTION_ID_CHAPTERS
, SECTION_ID_FORMAT
, SECTION_ID_FRAMES
, SECTION_ID_PROGRAMS
, SECTION_ID_STREAMS
,
178 SECTION_ID_PACKETS
, SECTION_ID_ERROR
, SECTION_ID_PROGRAM_VERSION
, SECTION_ID_LIBRARY_VERSIONS
, -1} },
179 [SECTION_ID_STREAMS
] = { SECTION_ID_STREAMS
, "streams", SECTION_FLAG_IS_ARRAY
, { SECTION_ID_STREAM
, -1 } },
180 [SECTION_ID_STREAM
] = { SECTION_ID_STREAM
, "stream", 0, { SECTION_ID_STREAM_DISPOSITION
, SECTION_ID_STREAM_TAGS
, -1 } },
181 [SECTION_ID_STREAM_DISPOSITION
] = { SECTION_ID_STREAM_DISPOSITION
, "disposition", 0, { -1 }, .unique_name
= "stream_disposition" },
182 [SECTION_ID_STREAM_TAGS
] = { SECTION_ID_STREAM_TAGS
, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS
, { -1 }, .element_name
= "tag", .unique_name
= "stream_tags" },
183 [SECTION_ID_SUBTITLE
] = { SECTION_ID_SUBTITLE
, "subtitle", 0, { -1 } },
186 static const OptionDef
*options
;
188 /* FFprobe context */
189 static const char *input_filename
;
190 static AVInputFormat
*iformat
= NULL
;
192 static struct AVHashContext
*hash
;
194 static const char *const binary_unit_prefixes
[] = { "", "Ki", "Mi", "Gi", "Ti", "Pi" };
195 static const char *const decimal_unit_prefixes
[] = { "", "K" , "M" , "G" , "T" , "P" };
197 static const char unit_second_str
[] = "s" ;
198 static const char unit_hertz_str
[] = "Hz" ;
199 static const char unit_byte_str
[] = "byte" ;
200 static const char unit_bit_per_second_str
[] = "bit/s";
202 static int nb_streams
;
203 static uint64_t *nb_streams_packets
;
204 static uint64_t *nb_streams_frames
;
205 static int *selected_streams
;
207 static void ffprobe_cleanup(int ret
)
210 for (i
= 0; i
< FF_ARRAY_ELEMS(sections
); i
++)
211 av_dict_free(&(sections
[i
].entries_to_show
));
215 union { double d
; long long int i
; } val
;
219 static char *value_string(char *buf
, int buf_size
, struct unit_value uv
)
225 if (uv
.unit
== unit_second_str
) {
229 vald
= vali
= uv
.val
.i
;
232 if (uv
.unit
== unit_second_str
&& use_value_sexagesimal_format
) {
236 mins
= (int)secs
/ 60;
237 secs
= secs
- mins
* 60;
240 snprintf(buf
, buf_size
, "%d:%02d:%09.6f", hours
, mins
, secs
);
242 const char *prefix_string
= "";
244 if (use_value_prefix
&& vald
> 1) {
247 if (uv
.unit
== unit_byte_str
&& use_byte_value_binary_prefix
) {
248 index
= (long long int) (log2(vald
)) / 10;
249 index
= av_clip(index
, 0, FF_ARRAY_ELEMS(binary_unit_prefixes
) - 1);
250 vald
/= exp2(index
* 10);
251 prefix_string
= binary_unit_prefixes
[index
];
253 index
= (long long int) (log10(vald
)) / 3;
254 index
= av_clip(index
, 0, FF_ARRAY_ELEMS(decimal_unit_prefixes
) - 1);
255 vald
/= pow(10, index
* 3);
256 prefix_string
= decimal_unit_prefixes
[index
];
261 if (show_float
|| (use_value_prefix
&& vald
!= (long long int)vald
))
262 snprintf(buf
, buf_size
, "%f", vald
);
264 snprintf(buf
, buf_size
, "%lld", vali
);
265 av_strlcatf(buf
, buf_size
, "%s%s%s", *prefix_string
|| show_value_unit
? " " : "",
266 prefix_string
, show_value_unit
? uv
.unit
: "");
274 typedef struct WriterContext WriterContext
;
276 #define WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS 1
277 #define WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER 2
280 WRITER_STRING_VALIDATION_FAIL
,
281 WRITER_STRING_VALIDATION_REPLACE
,
282 WRITER_STRING_VALIDATION_IGNORE
,
283 WRITER_STRING_VALIDATION_NB
286 typedef struct Writer
{
287 const AVClass
*priv_class
; ///< private class of the writer, if any
288 int priv_size
; ///< private size for the writer context
291 int (*init
) (WriterContext
*wctx
);
292 void (*uninit
)(WriterContext
*wctx
);
294 void (*print_section_header
)(WriterContext
*wctx
);
295 void (*print_section_footer
)(WriterContext
*wctx
);
296 void (*print_integer
) (WriterContext
*wctx
, const char *, long long int);
297 void (*print_rational
) (WriterContext
*wctx
, AVRational
*q
, char *sep
);
298 void (*print_string
) (WriterContext
*wctx
, const char *, const char *);
299 int flags
; ///< a combination or WRITER_FLAG_*
302 #define SECTION_MAX_NB_LEVELS 10
304 struct WriterContext
{
305 const AVClass
*class; ///< class of the writer
306 const Writer
*writer
; ///< the Writer of which this is an instance
307 char *name
; ///< name of this writer instance
308 void *priv
; ///< private data for use by the filter
310 const struct section
*sections
; ///< array containing all sections
311 int nb_sections
; ///< number of sections
313 int level
; ///< current level, starting from 0
315 /** number of the item printed in the given section, starting from 0 */
316 unsigned int nb_item
[SECTION_MAX_NB_LEVELS
];
318 /** section per each level */
319 const struct section
*section
[SECTION_MAX_NB_LEVELS
];
320 AVBPrint section_pbuf
[SECTION_MAX_NB_LEVELS
]; ///< generic print buffer dedicated to each section,
321 /// used by various writers
323 unsigned int nb_section_packet
; ///< number of the packet section in case we are in "packets_and_frames" section
324 unsigned int nb_section_frame
; ///< number of the frame section in case we are in "packets_and_frames" section
325 unsigned int nb_section_packet_frame
; ///< nb_section_packet or nb_section_frame according if is_packets_and_frames
327 StringValidation string_validation
;
328 char *string_validation_replacement
;
329 unsigned int string_validation_utf8_flags
;
332 static const char *writer_get_name(void *p
)
334 WriterContext
*wctx
= p
;
335 return wctx
->writer
->name
;
338 #define OFFSET(x) offsetof(WriterContext, x)
340 static const AVOption writer_options
[] = {
341 { "string_validation", "set string validation mode",
342 OFFSET(string_validation
), AV_OPT_TYPE_INT
, {.i64
=WRITER_STRING_VALIDATION_REPLACE
}, 0, WRITER_STRING_VALIDATION_NB
-1, .unit
= "sv" },
343 { "sv", "set string validation mode",
344 OFFSET(string_validation
), AV_OPT_TYPE_INT
, {.i64
=WRITER_STRING_VALIDATION_REPLACE
}, 0, WRITER_STRING_VALIDATION_NB
-1, .unit
= "sv" },
345 { "ignore", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
= WRITER_STRING_VALIDATION_IGNORE
}, .unit
= "sv" },
346 { "replace", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
= WRITER_STRING_VALIDATION_REPLACE
}, .unit
= "sv" },
347 { "fail", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
= WRITER_STRING_VALIDATION_FAIL
}, .unit
= "sv" },
348 { "string_validation_replacement", "set string validation replacement string", OFFSET(string_validation_replacement
), AV_OPT_TYPE_STRING
, {.str
=""}},
349 { "svr", "set string validation replacement string", OFFSET(string_validation_replacement
), AV_OPT_TYPE_STRING
, {.str
="\xEF\xBF\xBD"}},
353 static void *writer_child_next(void *obj
, void *prev
)
355 WriterContext
*ctx
= obj
;
356 if (!prev
&& ctx
->writer
&& ctx
->writer
->priv_class
&& ctx
->priv
)
361 static const AVClass writer_class
= {
362 .class_name
= "Writer",
363 .item_name
= writer_get_name
,
364 .option
= writer_options
,
365 .version
= LIBAVUTIL_VERSION_INT
,
366 .child_next
= writer_child_next
,
369 static void writer_close(WriterContext
**wctx
)
376 if ((*wctx
)->writer
->uninit
)
377 (*wctx
)->writer
->uninit(*wctx
);
378 for (i
= 0; i
< SECTION_MAX_NB_LEVELS
; i
++)
379 av_bprint_finalize(&(*wctx
)->section_pbuf
[i
], NULL
);
380 if ((*wctx
)->writer
->priv_class
)
381 av_opt_free((*wctx
)->priv
);
382 av_freep(&((*wctx
)->priv
));
387 static void bprint_bytes(AVBPrint
*bp
, const uint8_t *ubuf
, size_t ubuf_size
)
390 av_bprintf(bp
, "0X");
391 for (i
= 0; i
< ubuf_size
; i
++)
392 av_bprintf(bp
, "%02X", ubuf
[i
]);
396 static int writer_open(WriterContext
**wctx
, const Writer
*writer
, const char *args
,
397 const struct section
*sections
, int nb_sections
)
401 if (!(*wctx
= av_mallocz(sizeof(WriterContext
)))) {
402 ret
= AVERROR(ENOMEM
);
406 if (!((*wctx
)->priv
= av_mallocz(writer
->priv_size
))) {
407 ret
= AVERROR(ENOMEM
);
411 (*wctx
)->class = &writer_class
;
412 (*wctx
)->writer
= writer
;
414 (*wctx
)->sections
= sections
;
415 (*wctx
)->nb_sections
= nb_sections
;
417 av_opt_set_defaults(*wctx
);
419 if (writer
->priv_class
) {
420 void *priv_ctx
= (*wctx
)->priv
;
421 *((const AVClass
**)priv_ctx
) = writer
->priv_class
;
422 av_opt_set_defaults(priv_ctx
);
425 /* convert options to dictionary */
427 AVDictionary
*opts
= NULL
;
428 AVDictionaryEntry
*opt
= NULL
;
430 if ((ret
= av_dict_parse_string(&opts
, args
, "=", ":", 0)) < 0) {
431 av_log(*wctx
, AV_LOG_ERROR
, "Failed to parse option string '%s' provided to writer context\n", args
);
436 while ((opt
= av_dict_get(opts
, "", opt
, AV_DICT_IGNORE_SUFFIX
))) {
437 if ((ret
= av_opt_set(*wctx
, opt
->key
, opt
->value
, AV_OPT_SEARCH_CHILDREN
)) < 0) {
438 av_log(*wctx
, AV_LOG_ERROR
, "Failed to set option '%s' with value '%s' provided to writer context\n",
439 opt
->key
, opt
->value
);
448 /* validate replace string */
450 const uint8_t *p
= (*wctx
)->string_validation_replacement
;
451 const uint8_t *endp
= p
+ strlen(p
);
453 const uint8_t *p0
= p
;
455 ret
= av_utf8_decode(&code
, &p
, endp
, (*wctx
)->string_validation_utf8_flags
);
458 av_bprint_init(&bp
, 0, AV_BPRINT_SIZE_AUTOMATIC
);
459 bprint_bytes(&bp
, p0
, p
-p0
),
460 av_log(wctx
, AV_LOG_ERROR
,
461 "Invalid UTF8 sequence %s found in string validation replace '%s'\n",
462 bp
.str
, (*wctx
)->string_validation_replacement
);
468 for (i
= 0; i
< SECTION_MAX_NB_LEVELS
; i
++)
469 av_bprint_init(&(*wctx
)->section_pbuf
[i
], 1, AV_BPRINT_SIZE_UNLIMITED
);
471 if ((*wctx
)->writer
->init
)
472 ret
= (*wctx
)->writer
->init(*wctx
);
483 static inline void writer_print_section_header(WriterContext
*wctx
,
486 int parent_section_id
;
488 av_assert0(wctx
->level
< SECTION_MAX_NB_LEVELS
);
489 parent_section_id
= wctx
->level
?
490 (wctx
->section
[wctx
->level
-1])->id
: SECTION_ID_NONE
;
492 wctx
->nb_item
[wctx
->level
] = 0;
493 wctx
->section
[wctx
->level
] = &wctx
->sections
[section_id
];
495 if (section_id
== SECTION_ID_PACKETS_AND_FRAMES
) {
496 wctx
->nb_section_packet
= wctx
->nb_section_frame
=
497 wctx
->nb_section_packet_frame
= 0;
498 } else if (parent_section_id
== SECTION_ID_PACKETS_AND_FRAMES
) {
499 wctx
->nb_section_packet_frame
= section_id
== SECTION_ID_PACKET
?
500 wctx
->nb_section_packet
: wctx
->nb_section_frame
;
503 if (wctx
->writer
->print_section_header
)
504 wctx
->writer
->print_section_header(wctx
);
507 static inline void writer_print_section_footer(WriterContext
*wctx
)
509 int section_id
= wctx
->section
[wctx
->level
]->id
;
510 int parent_section_id
= wctx
->level
?
511 wctx
->section
[wctx
->level
-1]->id
: SECTION_ID_NONE
;
513 if (parent_section_id
!= SECTION_ID_NONE
)
514 wctx
->nb_item
[wctx
->level
-1]++;
515 if (parent_section_id
== SECTION_ID_PACKETS_AND_FRAMES
) {
516 if (section_id
== SECTION_ID_PACKET
) wctx
->nb_section_packet
++;
517 else wctx
->nb_section_frame
++;
519 if (wctx
->writer
->print_section_footer
)
520 wctx
->writer
->print_section_footer(wctx
);
524 static inline void writer_print_integer(WriterContext
*wctx
,
525 const char *key
, long long int val
)
527 const struct section
*section
= wctx
->section
[wctx
->level
];
529 if (section
->show_all_entries
|| av_dict_get(section
->entries_to_show
, key
, NULL
, 0)) {
530 wctx
->writer
->print_integer(wctx
, key
, val
);
531 wctx
->nb_item
[wctx
->level
]++;
535 static inline int validate_string(WriterContext
*wctx
, char **dstp
, const char *src
)
537 const uint8_t *p
, *endp
;
539 int invalid_chars_nb
= 0, ret
= 0;
541 av_bprint_init(&dstbuf
, 0, AV_BPRINT_SIZE_UNLIMITED
);
543 endp
= src
+ strlen(src
);
544 for (p
= (uint8_t *)src
; *p
;) {
547 const uint8_t *p0
= p
;
549 if (av_utf8_decode(&code
, &p
, endp
, wctx
->string_validation_utf8_flags
) < 0) {
551 av_bprint_init(&bp
, 0, AV_BPRINT_SIZE_AUTOMATIC
);
552 bprint_bytes(&bp
, p0
, p
-p0
);
553 av_log(wctx
, AV_LOG_DEBUG
,
554 "Invalid UTF-8 sequence %s found in string '%s'\n", bp
.str
, src
);
561 switch (wctx
->string_validation
) {
562 case WRITER_STRING_VALIDATION_FAIL
:
563 av_log(wctx
, AV_LOG_ERROR
,
564 "Invalid UTF-8 sequence found in string '%s'\n", src
);
565 ret
= AVERROR_INVALIDDATA
;
569 case WRITER_STRING_VALIDATION_REPLACE
:
570 av_bprintf(&dstbuf
, "%s", wctx
->string_validation_replacement
);
575 if (!invalid
|| wctx
->string_validation
== WRITER_STRING_VALIDATION_IGNORE
)
576 av_bprint_append_data(&dstbuf
, p0
, p
-p0
);
579 if (invalid_chars_nb
&& wctx
->string_validation
== WRITER_STRING_VALIDATION_REPLACE
) {
580 av_log(wctx
, AV_LOG_WARNING
,
581 "%d invalid UTF-8 sequence(s) found in string '%s', replaced with '%s'\n",
582 invalid_chars_nb
, src
, wctx
->string_validation_replacement
);
586 av_bprint_finalize(&dstbuf
, dstp
);
590 #define PRINT_STRING_OPT 1
591 #define PRINT_STRING_VALIDATE 2
593 static inline int writer_print_string(WriterContext
*wctx
,
594 const char *key
, const char *val
, int flags
)
596 const struct section
*section
= wctx
->section
[wctx
->level
];
599 if ((flags
& PRINT_STRING_OPT
)
600 && !(wctx
->writer
->flags
& WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS
))
603 if (section
->show_all_entries
|| av_dict_get(section
->entries_to_show
, key
, NULL
, 0)) {
604 if (flags
& PRINT_STRING_VALIDATE
) {
605 char *key1
= NULL
, *val1
= NULL
;
606 ret
= validate_string(wctx
, &key1
, key
);
607 if (ret
< 0) goto end
;
608 ret
= validate_string(wctx
, &val1
, val
);
609 if (ret
< 0) goto end
;
610 wctx
->writer
->print_string(wctx
, key1
, val1
);
613 av_log(wctx
, AV_LOG_ERROR
,
614 "Invalid key=value string combination %s=%s in section %s\n",
615 key
, val
, section
->unique_name
);
620 wctx
->writer
->print_string(wctx
, key
, val
);
623 wctx
->nb_item
[wctx
->level
]++;
629 static inline void writer_print_rational(WriterContext
*wctx
,
630 const char *key
, AVRational q
, char sep
)
633 av_bprint_init(&buf
, 0, AV_BPRINT_SIZE_AUTOMATIC
);
634 av_bprintf(&buf
, "%d%c%d", q
.num
, sep
, q
.den
);
635 writer_print_string(wctx
, key
, buf
.str
, 0);
638 static void writer_print_time(WriterContext
*wctx
, const char *key
,
639 int64_t ts
, const AVRational
*time_base
, int is_duration
)
643 if ((!is_duration
&& ts
== AV_NOPTS_VALUE
) || (is_duration
&& ts
== 0)) {
644 writer_print_string(wctx
, key
, "N/A", PRINT_STRING_OPT
);
646 double d
= ts
* av_q2d(*time_base
);
647 struct unit_value uv
;
649 uv
.unit
= unit_second_str
;
650 value_string(buf
, sizeof(buf
), uv
);
651 writer_print_string(wctx
, key
, buf
, 0);
655 static void writer_print_ts(WriterContext
*wctx
, const char *key
, int64_t ts
, int is_duration
)
657 if ((!is_duration
&& ts
== AV_NOPTS_VALUE
) || (is_duration
&& ts
== 0)) {
658 writer_print_string(wctx
, key
, "N/A", PRINT_STRING_OPT
);
660 writer_print_integer(wctx
, key
, ts
);
664 static void writer_print_data(WriterContext
*wctx
, const char *name
,
665 uint8_t *data
, int size
)
668 int offset
= 0, l
, i
;
670 av_bprint_init(&bp
, 0, AV_BPRINT_SIZE_UNLIMITED
);
671 av_bprintf(&bp
, "\n");
673 av_bprintf(&bp
, "%08x: ", offset
);
675 for (i
= 0; i
< l
; i
++) {
676 av_bprintf(&bp
, "%02x", data
[i
]);
678 av_bprintf(&bp
, " ");
680 av_bprint_chars(&bp
, ' ', 41 - 2 * i
- i
/ 2);
681 for (i
= 0; i
< l
; i
++)
682 av_bprint_chars(&bp
, data
[i
] - 32U < 95 ? data
[i
] : '.', 1);
683 av_bprintf(&bp
, "\n");
688 writer_print_string(wctx
, name
, bp
.str
, 0);
689 av_bprint_finalize(&bp
, NULL
);
692 static void writer_print_data_hash(WriterContext
*wctx
, const char *name
,
693 uint8_t *data
, int size
)
695 char *p
, buf
[AV_HASH_MAX_SIZE
* 2 + 64] = { 0 };
700 av_hash_update(hash
, data
, size
);
701 snprintf(buf
, sizeof(buf
), "%s:", av_hash_get_name(hash
));
702 p
= buf
+ strlen(buf
);
703 av_hash_final_hex(hash
, p
, buf
+ sizeof(buf
) - p
);
704 writer_print_string(wctx
, name
, buf
, 0);
707 #define MAX_REGISTERED_WRITERS_NB 64
709 static const Writer
*registered_writers
[MAX_REGISTERED_WRITERS_NB
+ 1];
711 static int writer_register(const Writer
*writer
)
713 static int next_registered_writer_idx
= 0;
715 if (next_registered_writer_idx
== MAX_REGISTERED_WRITERS_NB
)
716 return AVERROR(ENOMEM
);
718 registered_writers
[next_registered_writer_idx
++] = writer
;
722 static const Writer
*writer_get_by_name(const char *name
)
726 for (i
= 0; registered_writers
[i
]; i
++)
727 if (!strcmp(registered_writers
[i
]->name
, name
))
728 return registered_writers
[i
];
736 #define DEFINE_WRITER_CLASS(name) \
737 static const char *name##_get_name(void *ctx) \
741 static const AVClass name##_class = { \
742 .class_name = #name, \
743 .item_name = name##_get_name, \
744 .option = name##_options \
749 typedef struct DefaultContext
{
750 const AVClass
*class;
752 int noprint_wrappers
;
753 int nested_section
[SECTION_MAX_NB_LEVELS
];
757 #define OFFSET(x) offsetof(DefaultContext, x)
759 static const AVOption default_options
[] = {
760 { "noprint_wrappers", "do not print headers and footers", OFFSET(noprint_wrappers
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1 },
761 { "nw", "do not print headers and footers", OFFSET(noprint_wrappers
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1 },
762 { "nokey", "force no key printing", OFFSET(nokey
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1 },
763 { "nk", "force no key printing", OFFSET(nokey
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1 },
767 DEFINE_WRITER_CLASS(default);
769 /* lame uppercasing routine, assumes the string is lower case ASCII */
770 static inline char *upcase_string(char *dst
, size_t dst_size
, const char *src
)
773 for (i
= 0; src
[i
] && i
< dst_size
-1; i
++)
774 dst
[i
] = av_toupper(src
[i
]);
779 static void default_print_section_header(WriterContext
*wctx
)
781 DefaultContext
*def
= wctx
->priv
;
783 const struct section
*section
= wctx
->section
[wctx
->level
];
784 const struct section
*parent_section
= wctx
->level
?
785 wctx
->section
[wctx
->level
-1] : NULL
;
787 av_bprint_clear(&wctx
->section_pbuf
[wctx
->level
]);
788 if (parent_section
&&
789 !(parent_section
->flags
& (SECTION_FLAG_IS_WRAPPER
|SECTION_FLAG_IS_ARRAY
))) {
790 def
->nested_section
[wctx
->level
] = 1;
791 av_bprintf(&wctx
->section_pbuf
[wctx
->level
], "%s%s:",
792 wctx
->section_pbuf
[wctx
->level
-1].str
,
793 upcase_string(buf
, sizeof(buf
),
794 av_x_if_null(section
->element_name
, section
->name
)));
797 if (def
->noprint_wrappers
|| def
->nested_section
[wctx
->level
])
800 if (!(section
->flags
& (SECTION_FLAG_IS_WRAPPER
|SECTION_FLAG_IS_ARRAY
)))
801 printf("[%s]\n", upcase_string(buf
, sizeof(buf
), section
->name
));
804 static void default_print_section_footer(WriterContext
*wctx
)
806 DefaultContext
*def
= wctx
->priv
;
807 const struct section
*section
= wctx
->section
[wctx
->level
];
810 if (def
->noprint_wrappers
|| def
->nested_section
[wctx
->level
])
813 if (!(section
->flags
& (SECTION_FLAG_IS_WRAPPER
|SECTION_FLAG_IS_ARRAY
)))
814 printf("[/%s]\n", upcase_string(buf
, sizeof(buf
), section
->name
));
817 static void default_print_str(WriterContext
*wctx
, const char *key
, const char *value
)
819 DefaultContext
*def
= wctx
->priv
;
822 printf("%s%s=", wctx
->section_pbuf
[wctx
->level
].str
, key
);
823 printf("%s\n", value
);
826 static void default_print_int(WriterContext
*wctx
, const char *key
, long long int value
)
828 DefaultContext
*def
= wctx
->priv
;
831 printf("%s%s=", wctx
->section_pbuf
[wctx
->level
].str
, key
);
832 printf("%lld\n", value
);
835 static const Writer default_writer
= {
837 .priv_size
= sizeof(DefaultContext
),
838 .print_section_header
= default_print_section_header
,
839 .print_section_footer
= default_print_section_footer
,
840 .print_integer
= default_print_int
,
841 .print_string
= default_print_str
,
842 .flags
= WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS
,
843 .priv_class
= &default_class
,
849 * Apply C-language-like string escaping.
851 static const char *c_escape_str(AVBPrint
*dst
, const char *src
, const char sep
, void *log_ctx
)
855 for (p
= src
; *p
; p
++) {
857 case '\b': av_bprintf(dst
, "%s", "\\b"); break;
858 case '\f': av_bprintf(dst
, "%s", "\\f"); break;
859 case '\n': av_bprintf(dst
, "%s", "\\n"); break;
860 case '\r': av_bprintf(dst
, "%s", "\\r"); break;
861 case '\\': av_bprintf(dst
, "%s", "\\\\"); break;
864 av_bprint_chars(dst
, '\\', 1);
865 av_bprint_chars(dst
, *p
, 1);
872 * Quote fields containing special characters, check RFC4180.
874 static const char *csv_escape_str(AVBPrint
*dst
, const char *src
, const char sep
, void *log_ctx
)
876 char meta_chars
[] = { sep
, '"', '\n', '\r', '\0' };
877 int needs_quoting
= !!src
[strcspn(src
, meta_chars
)];
880 av_bprint_chars(dst
, '"', 1);
882 for (; *src
; src
++) {
884 av_bprint_chars(dst
, '"', 1);
885 av_bprint_chars(dst
, *src
, 1);
888 av_bprint_chars(dst
, '"', 1);
892 static const char *none_escape_str(AVBPrint
*dst
, const char *src
, const char sep
, void *log_ctx
)
897 typedef struct CompactContext
{
898 const AVClass
*class;
903 char *escape_mode_str
;
904 const char * (*escape_str
)(AVBPrint
*dst
, const char *src
, const char sep
, void *log_ctx
);
905 int nested_section
[SECTION_MAX_NB_LEVELS
];
906 int has_nested_elems
[SECTION_MAX_NB_LEVELS
];
907 int terminate_line
[SECTION_MAX_NB_LEVELS
];
911 #define OFFSET(x) offsetof(CompactContext, x)
913 static const AVOption compact_options
[]= {
914 {"item_sep", "set item separator", OFFSET(item_sep_str
), AV_OPT_TYPE_STRING
, {.str
="|"}, CHAR_MIN
, CHAR_MAX
},
915 {"s", "set item separator", OFFSET(item_sep_str
), AV_OPT_TYPE_STRING
, {.str
="|"}, CHAR_MIN
, CHAR_MAX
},
916 {"nokey", "force no key printing", OFFSET(nokey
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1 },
917 {"nk", "force no key printing", OFFSET(nokey
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1 },
918 {"escape", "set escape mode", OFFSET(escape_mode_str
), AV_OPT_TYPE_STRING
, {.str
="c"}, CHAR_MIN
, CHAR_MAX
},
919 {"e", "set escape mode", OFFSET(escape_mode_str
), AV_OPT_TYPE_STRING
, {.str
="c"}, CHAR_MIN
, CHAR_MAX
},
920 {"print_section", "print section name", OFFSET(print_section
), AV_OPT_TYPE_INT
, {.i64
=1}, 0, 1 },
921 {"p", "print section name", OFFSET(print_section
), AV_OPT_TYPE_INT
, {.i64
=1}, 0, 1 },
925 DEFINE_WRITER_CLASS(compact
);
927 static av_cold
int compact_init(WriterContext
*wctx
)
929 CompactContext
*compact
= wctx
->priv
;
931 if (strlen(compact
->item_sep_str
) != 1) {
932 av_log(wctx
, AV_LOG_ERROR
, "Item separator '%s' specified, but must contain a single character\n",
933 compact
->item_sep_str
);
934 return AVERROR(EINVAL
);
936 compact
->item_sep
= compact
->item_sep_str
[0];
938 if (!strcmp(compact
->escape_mode_str
, "none")) compact
->escape_str
= none_escape_str
;
939 else if (!strcmp(compact
->escape_mode_str
, "c" )) compact
->escape_str
= c_escape_str
;
940 else if (!strcmp(compact
->escape_mode_str
, "csv" )) compact
->escape_str
= csv_escape_str
;
942 av_log(wctx
, AV_LOG_ERROR
, "Unknown escape mode '%s'\n", compact
->escape_mode_str
);
943 return AVERROR(EINVAL
);
949 static void compact_print_section_header(WriterContext
*wctx
)
951 CompactContext
*compact
= wctx
->priv
;
952 const struct section
*section
= wctx
->section
[wctx
->level
];
953 const struct section
*parent_section
= wctx
->level
?
954 wctx
->section
[wctx
->level
-1] : NULL
;
955 compact
->terminate_line
[wctx
->level
] = 1;
956 compact
->has_nested_elems
[wctx
->level
] = 0;
958 av_bprint_clear(&wctx
->section_pbuf
[wctx
->level
]);
959 if (!(section
->flags
& SECTION_FLAG_IS_ARRAY
) && parent_section
&&
960 !(parent_section
->flags
& (SECTION_FLAG_IS_WRAPPER
|SECTION_FLAG_IS_ARRAY
))) {
961 compact
->nested_section
[wctx
->level
] = 1;
962 compact
->has_nested_elems
[wctx
->level
-1] = 1;
963 av_bprintf(&wctx
->section_pbuf
[wctx
->level
], "%s%s:",
964 wctx
->section_pbuf
[wctx
->level
-1].str
,
965 (char *)av_x_if_null(section
->element_name
, section
->name
));
966 wctx
->nb_item
[wctx
->level
] = wctx
->nb_item
[wctx
->level
-1];
968 if (parent_section
&& compact
->has_nested_elems
[wctx
->level
-1] &&
969 (section
->flags
& SECTION_FLAG_IS_ARRAY
)) {
970 compact
->terminate_line
[wctx
->level
-1] = 0;
973 if (compact
->print_section
&&
974 !(section
->flags
& (SECTION_FLAG_IS_WRAPPER
|SECTION_FLAG_IS_ARRAY
)))
975 printf("%s%c", section
->name
, compact
->item_sep
);
979 static void compact_print_section_footer(WriterContext
*wctx
)
981 CompactContext
*compact
= wctx
->priv
;
983 if (!compact
->nested_section
[wctx
->level
] &&
984 compact
->terminate_line
[wctx
->level
] &&
985 !(wctx
->section
[wctx
->level
]->flags
& (SECTION_FLAG_IS_WRAPPER
|SECTION_FLAG_IS_ARRAY
)))
989 static void compact_print_str(WriterContext
*wctx
, const char *key
, const char *value
)
991 CompactContext
*compact
= wctx
->priv
;
994 if (wctx
->nb_item
[wctx
->level
]) printf("%c", compact
->item_sep
);
996 printf("%s%s=", wctx
->section_pbuf
[wctx
->level
].str
, key
);
997 av_bprint_init(&buf
, 1, AV_BPRINT_SIZE_UNLIMITED
);
998 printf("%s", compact
->escape_str(&buf
, value
, compact
->item_sep
, wctx
));
999 av_bprint_finalize(&buf
, NULL
);
1002 static void compact_print_int(WriterContext
*wctx
, const char *key
, long long int value
)
1004 CompactContext
*compact
= wctx
->priv
;
1006 if (wctx
->nb_item
[wctx
->level
]) printf("%c", compact
->item_sep
);
1007 if (!compact
->nokey
)
1008 printf("%s%s=", wctx
->section_pbuf
[wctx
->level
].str
, key
);
1009 printf("%lld", value
);
1012 static const Writer compact_writer
= {
1014 .priv_size
= sizeof(CompactContext
),
1015 .init
= compact_init
,
1016 .print_section_header
= compact_print_section_header
,
1017 .print_section_footer
= compact_print_section_footer
,
1018 .print_integer
= compact_print_int
,
1019 .print_string
= compact_print_str
,
1020 .flags
= WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS
,
1021 .priv_class
= &compact_class
,
1027 #define OFFSET(x) offsetof(CompactContext, x)
1029 static const AVOption csv_options
[] = {
1030 {"item_sep", "set item separator", OFFSET(item_sep_str
), AV_OPT_TYPE_STRING
, {.str
=","}, CHAR_MIN
, CHAR_MAX
},
1031 {"s", "set item separator", OFFSET(item_sep_str
), AV_OPT_TYPE_STRING
, {.str
=","}, CHAR_MIN
, CHAR_MAX
},
1032 {"nokey", "force no key printing", OFFSET(nokey
), AV_OPT_TYPE_INT
, {.i64
=1}, 0, 1 },
1033 {"nk", "force no key printing", OFFSET(nokey
), AV_OPT_TYPE_INT
, {.i64
=1}, 0, 1 },
1034 {"escape", "set escape mode", OFFSET(escape_mode_str
), AV_OPT_TYPE_STRING
, {.str
="csv"}, CHAR_MIN
, CHAR_MAX
},
1035 {"e", "set escape mode", OFFSET(escape_mode_str
), AV_OPT_TYPE_STRING
, {.str
="csv"}, CHAR_MIN
, CHAR_MAX
},
1036 {"print_section", "print section name", OFFSET(print_section
), AV_OPT_TYPE_INT
, {.i64
=1}, 0, 1 },
1037 {"p", "print section name", OFFSET(print_section
), AV_OPT_TYPE_INT
, {.i64
=1}, 0, 1 },
1041 DEFINE_WRITER_CLASS(csv
);
1043 static const Writer csv_writer
= {
1045 .priv_size
= sizeof(CompactContext
),
1046 .init
= compact_init
,
1047 .print_section_header
= compact_print_section_header
,
1048 .print_section_footer
= compact_print_section_footer
,
1049 .print_integer
= compact_print_int
,
1050 .print_string
= compact_print_str
,
1051 .flags
= WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS
,
1052 .priv_class
= &csv_class
,
1057 typedef struct FlatContext
{
1058 const AVClass
*class;
1059 const char *sep_str
;
1065 #define OFFSET(x) offsetof(FlatContext, x)
1067 static const AVOption flat_options
[]= {
1068 {"sep_char", "set separator", OFFSET(sep_str
), AV_OPT_TYPE_STRING
, {.str
="."}, CHAR_MIN
, CHAR_MAX
},
1069 {"s", "set separator", OFFSET(sep_str
), AV_OPT_TYPE_STRING
, {.str
="."}, CHAR_MIN
, CHAR_MAX
},
1070 {"hierarchical", "specify if the section specification should be hierarchical", OFFSET(hierarchical
), AV_OPT_TYPE_INT
, {.i64
=1}, 0, 1 },
1071 {"h", "specify if the section specification should be hierarchical", OFFSET(hierarchical
), AV_OPT_TYPE_INT
, {.i64
=1}, 0, 1 },
1075 DEFINE_WRITER_CLASS(flat
);
1077 static av_cold
int flat_init(WriterContext
*wctx
)
1079 FlatContext
*flat
= wctx
->priv
;
1081 if (strlen(flat
->sep_str
) != 1) {
1082 av_log(wctx
, AV_LOG_ERROR
, "Item separator '%s' specified, but must contain a single character\n",
1084 return AVERROR(EINVAL
);
1086 flat
->sep
= flat
->sep_str
[0];
1091 static const char *flat_escape_key_str(AVBPrint
*dst
, const char *src
, const char sep
)
1095 for (p
= src
; *p
; p
++) {
1096 if (!((*p
>= '0' && *p
<= '9') ||
1097 (*p
>= 'a' && *p
<= 'z') ||
1098 (*p
>= 'A' && *p
<= 'Z')))
1099 av_bprint_chars(dst
, '_', 1);
1101 av_bprint_chars(dst
, *p
, 1);
1106 static const char *flat_escape_value_str(AVBPrint
*dst
, const char *src
)
1110 for (p
= src
; *p
; p
++) {
1112 case '\n': av_bprintf(dst
, "%s", "\\n"); break;
1113 case '\r': av_bprintf(dst
, "%s", "\\r"); break;
1114 case '\\': av_bprintf(dst
, "%s", "\\\\"); break;
1115 case '"': av_bprintf(dst
, "%s", "\\\""); break;
1116 case '`': av_bprintf(dst
, "%s", "\\`"); break;
1117 case '$': av_bprintf(dst
, "%s", "\\$"); break;
1118 default: av_bprint_chars(dst
, *p
, 1); break;
1124 static void flat_print_section_header(WriterContext
*wctx
)
1126 FlatContext
*flat
= wctx
->priv
;
1127 AVBPrint
*buf
= &wctx
->section_pbuf
[wctx
->level
];
1128 const struct section
*section
= wctx
->section
[wctx
->level
];
1129 const struct section
*parent_section
= wctx
->level
?
1130 wctx
->section
[wctx
->level
-1] : NULL
;
1132 /* build section header */
1133 av_bprint_clear(buf
);
1134 if (!parent_section
)
1136 av_bprintf(buf
, "%s", wctx
->section_pbuf
[wctx
->level
-1].str
);
1138 if (flat
->hierarchical
||
1139 !(section
->flags
& (SECTION_FLAG_IS_ARRAY
|SECTION_FLAG_IS_WRAPPER
))) {
1140 av_bprintf(buf
, "%s%s", wctx
->section
[wctx
->level
]->name
, flat
->sep_str
);
1142 if (parent_section
->flags
& SECTION_FLAG_IS_ARRAY
) {
1143 int n
= parent_section
->id
== SECTION_ID_PACKETS_AND_FRAMES
?
1144 wctx
->nb_section_packet_frame
: wctx
->nb_item
[wctx
->level
-1];
1145 av_bprintf(buf
, "%d%s", n
, flat
->sep_str
);
1150 static void flat_print_int(WriterContext
*wctx
, const char *key
, long long int value
)
1152 printf("%s%s=%lld\n", wctx
->section_pbuf
[wctx
->level
].str
, key
, value
);
1155 static void flat_print_str(WriterContext
*wctx
, const char *key
, const char *value
)
1157 FlatContext
*flat
= wctx
->priv
;
1160 printf("%s", wctx
->section_pbuf
[wctx
->level
].str
);
1161 av_bprint_init(&buf
, 1, AV_BPRINT_SIZE_UNLIMITED
);
1162 printf("%s=", flat_escape_key_str(&buf
, key
, flat
->sep
));
1163 av_bprint_clear(&buf
);
1164 printf("\"%s\"\n", flat_escape_value_str(&buf
, value
));
1165 av_bprint_finalize(&buf
, NULL
);
1168 static const Writer flat_writer
= {
1170 .priv_size
= sizeof(FlatContext
),
1172 .print_section_header
= flat_print_section_header
,
1173 .print_integer
= flat_print_int
,
1174 .print_string
= flat_print_str
,
1175 .flags
= WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS
|WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER
,
1176 .priv_class
= &flat_class
,
1179 /* INI format output */
1182 const AVClass
*class;
1187 #define OFFSET(x) offsetof(INIContext, x)
1189 static const AVOption ini_options
[] = {
1190 {"hierarchical", "specify if the section specification should be hierarchical", OFFSET(hierarchical
), AV_OPT_TYPE_INT
, {.i64
=1}, 0, 1 },
1191 {"h", "specify if the section specification should be hierarchical", OFFSET(hierarchical
), AV_OPT_TYPE_INT
, {.i64
=1}, 0, 1 },
1195 DEFINE_WRITER_CLASS(ini
);
1197 static char *ini_escape_str(AVBPrint
*dst
, const char *src
)
1202 while (c
= src
[i
++]) {
1204 case '\b': av_bprintf(dst
, "%s", "\\b"); break;
1205 case '\f': av_bprintf(dst
, "%s", "\\f"); break;
1206 case '\n': av_bprintf(dst
, "%s", "\\n"); break;
1207 case '\r': av_bprintf(dst
, "%s", "\\r"); break;
1208 case '\t': av_bprintf(dst
, "%s", "\\t"); break;
1212 case ':' : av_bprint_chars(dst
, '\\', 1);
1214 if ((unsigned char)c
< 32)
1215 av_bprintf(dst
, "\\x00%02x", c
& 0xff);
1217 av_bprint_chars(dst
, c
, 1);
1224 static void ini_print_section_header(WriterContext
*wctx
)
1226 INIContext
*ini
= wctx
->priv
;
1227 AVBPrint
*buf
= &wctx
->section_pbuf
[wctx
->level
];
1228 const struct section
*section
= wctx
->section
[wctx
->level
];
1229 const struct section
*parent_section
= wctx
->level
?
1230 wctx
->section
[wctx
->level
-1] : NULL
;
1232 av_bprint_clear(buf
);
1233 if (!parent_section
) {
1234 printf("# ffprobe output\n\n");
1238 if (wctx
->nb_item
[wctx
->level
-1])
1241 av_bprintf(buf
, "%s", wctx
->section_pbuf
[wctx
->level
-1].str
);
1242 if (ini
->hierarchical
||
1243 !(section
->flags
& (SECTION_FLAG_IS_ARRAY
|SECTION_FLAG_IS_WRAPPER
))) {
1244 av_bprintf(buf
, "%s%s", buf
->str
[0] ? "." : "", wctx
->section
[wctx
->level
]->name
);
1246 if (parent_section
->flags
& SECTION_FLAG_IS_ARRAY
) {
1247 int n
= parent_section
->id
== SECTION_ID_PACKETS_AND_FRAMES
?
1248 wctx
->nb_section_packet_frame
: wctx
->nb_item
[wctx
->level
-1];
1249 av_bprintf(buf
, ".%d", n
);
1253 if (!(section
->flags
& (SECTION_FLAG_IS_ARRAY
|SECTION_FLAG_IS_WRAPPER
)))
1254 printf("[%s]\n", buf
->str
);
1257 static void ini_print_str(WriterContext
*wctx
, const char *key
, const char *value
)
1261 av_bprint_init(&buf
, 1, AV_BPRINT_SIZE_UNLIMITED
);
1262 printf("%s=", ini_escape_str(&buf
, key
));
1263 av_bprint_clear(&buf
);
1264 printf("%s\n", ini_escape_str(&buf
, value
));
1265 av_bprint_finalize(&buf
, NULL
);
1268 static void ini_print_int(WriterContext
*wctx
, const char *key
, long long int value
)
1270 printf("%s=%lld\n", key
, value
);
1273 static const Writer ini_writer
= {
1275 .priv_size
= sizeof(INIContext
),
1276 .print_section_header
= ini_print_section_header
,
1277 .print_integer
= ini_print_int
,
1278 .print_string
= ini_print_str
,
1279 .flags
= WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS
|WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER
,
1280 .priv_class
= &ini_class
,
1286 const AVClass
*class;
1289 const char *item_sep
, *item_start_end
;
1293 #define OFFSET(x) offsetof(JSONContext, x)
1295 static const AVOption json_options
[]= {
1296 { "compact", "enable compact output", OFFSET(compact
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1 },
1297 { "c", "enable compact output", OFFSET(compact
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1 },
1301 DEFINE_WRITER_CLASS(json
);
1303 static av_cold
int json_init(WriterContext
*wctx
)
1305 JSONContext
*json
= wctx
->priv
;
1307 json
->item_sep
= json
->compact
? ", " : ",\n";
1308 json
->item_start_end
= json
->compact
? " " : "\n";
1313 static const char *json_escape_str(AVBPrint
*dst
, const char *src
, void *log_ctx
)
1315 static const char json_escape
[] = {'"', '\\', '\b', '\f', '\n', '\r', '\t', 0};
1316 static const char json_subst
[] = {'"', '\\', 'b', 'f', 'n', 'r', 't', 0};
1319 for (p
= src
; *p
; p
++) {
1320 char *s
= strchr(json_escape
, *p
);
1322 av_bprint_chars(dst
, '\\', 1);
1323 av_bprint_chars(dst
, json_subst
[s
- json_escape
], 1);
1324 } else if ((unsigned char)*p
< 32) {
1325 av_bprintf(dst
, "\\u00%02x", *p
& 0xff);
1327 av_bprint_chars(dst
, *p
, 1);
1333 #define JSON_INDENT() printf("%*c", json->indent_level * 4, ' ')
1335 static void json_print_section_header(WriterContext
*wctx
)
1337 JSONContext
*json
= wctx
->priv
;
1339 const struct section
*section
= wctx
->section
[wctx
->level
];
1340 const struct section
*parent_section
= wctx
->level
?
1341 wctx
->section
[wctx
->level
-1] : NULL
;
1343 if (wctx
->level
&& wctx
->nb_item
[wctx
->level
-1])
1346 if (section
->flags
& SECTION_FLAG_IS_WRAPPER
) {
1348 json
->indent_level
++;
1350 av_bprint_init(&buf
, 1, AV_BPRINT_SIZE_UNLIMITED
);
1351 json_escape_str(&buf
, section
->name
, wctx
);
1354 json
->indent_level
++;
1355 if (section
->flags
& SECTION_FLAG_IS_ARRAY
) {
1356 printf("\"%s\": [\n", buf
.str
);
1357 } else if (parent_section
&& !(parent_section
->flags
& SECTION_FLAG_IS_ARRAY
)) {
1358 printf("\"%s\": {%s", buf
.str
, json
->item_start_end
);
1360 printf("{%s", json
->item_start_end
);
1362 /* this is required so the parser can distinguish between packets and frames */
1363 if (parent_section
&& parent_section
->id
== SECTION_ID_PACKETS_AND_FRAMES
) {
1366 printf("\"type\": \"%s\"%s", section
->name
, json
->item_sep
);
1369 av_bprint_finalize(&buf
, NULL
);
1373 static void json_print_section_footer(WriterContext
*wctx
)
1375 JSONContext
*json
= wctx
->priv
;
1376 const struct section
*section
= wctx
->section
[wctx
->level
];
1378 if (wctx
->level
== 0) {
1379 json
->indent_level
--;
1381 } else if (section
->flags
& SECTION_FLAG_IS_ARRAY
) {
1383 json
->indent_level
--;
1387 printf("%s", json
->item_start_end
);
1388 json
->indent_level
--;
1395 static inline void json_print_item_str(WriterContext
*wctx
,
1396 const char *key
, const char *value
)
1400 av_bprint_init(&buf
, 1, AV_BPRINT_SIZE_UNLIMITED
);
1401 printf("\"%s\":", json_escape_str(&buf
, key
, wctx
));
1402 av_bprint_clear(&buf
);
1403 printf(" \"%s\"", json_escape_str(&buf
, value
, wctx
));
1404 av_bprint_finalize(&buf
, NULL
);
1407 static void json_print_str(WriterContext
*wctx
, const char *key
, const char *value
)
1409 JSONContext
*json
= wctx
->priv
;
1411 if (wctx
->nb_item
[wctx
->level
])
1412 printf("%s", json
->item_sep
);
1415 json_print_item_str(wctx
, key
, value
);
1418 static void json_print_int(WriterContext
*wctx
, const char *key
, long long int value
)
1420 JSONContext
*json
= wctx
->priv
;
1423 if (wctx
->nb_item
[wctx
->level
])
1424 printf("%s", json
->item_sep
);
1428 av_bprint_init(&buf
, 1, AV_BPRINT_SIZE_UNLIMITED
);
1429 printf("\"%s\": %lld", json_escape_str(&buf
, key
, wctx
), value
);
1430 av_bprint_finalize(&buf
, NULL
);
1433 static const Writer json_writer
= {
1435 .priv_size
= sizeof(JSONContext
),
1437 .print_section_header
= json_print_section_header
,
1438 .print_section_footer
= json_print_section_footer
,
1439 .print_integer
= json_print_int
,
1440 .print_string
= json_print_str
,
1441 .flags
= WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER
,
1442 .priv_class
= &json_class
,
1448 const AVClass
*class;
1451 int fully_qualified
;
1456 #define OFFSET(x) offsetof(XMLContext, x)
1458 static const AVOption xml_options
[] = {
1459 {"fully_qualified", "specify if the output should be fully qualified", OFFSET(fully_qualified
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1 },
1460 {"q", "specify if the output should be fully qualified", OFFSET(fully_qualified
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1 },
1461 {"xsd_strict", "ensure that the output is XSD compliant", OFFSET(xsd_strict
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1 },
1462 {"x", "ensure that the output is XSD compliant", OFFSET(xsd_strict
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1 },
1466 DEFINE_WRITER_CLASS(xml
);
1468 static av_cold
int xml_init(WriterContext
*wctx
)
1470 XMLContext
*xml
= wctx
->priv
;
1472 if (xml
->xsd_strict
) {
1473 xml
->fully_qualified
= 1;
1474 #define CHECK_COMPLIANCE(opt, opt_name) \
1476 av_log(wctx, AV_LOG_ERROR, \
1477 "XSD-compliant output selected but option '%s' was selected, XML output may be non-compliant.\n" \
1478 "You need to disable such option with '-no%s'\n", opt_name, opt_name); \
1479 return AVERROR(EINVAL); \
1481 CHECK_COMPLIANCE(show_private_data
, "private");
1482 CHECK_COMPLIANCE(show_value_unit
, "unit");
1483 CHECK_COMPLIANCE(use_value_prefix
, "prefix");
1485 if (do_show_frames
&& do_show_packets
) {
1486 av_log(wctx
, AV_LOG_ERROR
,
1487 "Interleaved frames and packets are not allowed in XSD. "
1488 "Select only one between the -show_frames and the -show_packets options.\n");
1489 return AVERROR(EINVAL
);
1496 static const char *xml_escape_str(AVBPrint
*dst
, const char *src
, void *log_ctx
)
1500 for (p
= src
; *p
; p
++) {
1502 case '&' : av_bprintf(dst
, "%s", "&"); break;
1503 case '<' : av_bprintf(dst
, "%s", "<"); break;
1504 case '>' : av_bprintf(dst
, "%s", ">"); break;
1505 case '"' : av_bprintf(dst
, "%s", """); break;
1506 case '\'': av_bprintf(dst
, "%s", "'"); break;
1507 default: av_bprint_chars(dst
, *p
, 1);
1514 #define XML_INDENT() printf("%*c", xml->indent_level * 4, ' ')
1516 static void xml_print_section_header(WriterContext
*wctx
)
1518 XMLContext
*xml
= wctx
->priv
;
1519 const struct section
*section
= wctx
->section
[wctx
->level
];
1520 const struct section
*parent_section
= wctx
->level
?
1521 wctx
->section
[wctx
->level
-1] : NULL
;
1523 if (wctx
->level
== 0) {
1524 const char *qual
= " xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' "
1525 "xmlns:ffprobe='http://www.ffmpeg.org/schema/ffprobe' "
1526 "xsi:schemaLocation='http://www.ffmpeg.org/schema/ffprobe ffprobe.xsd'";
1528 printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1529 printf("<%sffprobe%s>\n",
1530 xml
->fully_qualified
? "ffprobe:" : "",
1531 xml
->fully_qualified
? qual
: "");
1535 if (xml
->within_tag
) {
1536 xml
->within_tag
= 0;
1539 if (section
->flags
& SECTION_FLAG_HAS_VARIABLE_FIELDS
) {
1540 xml
->indent_level
++;
1542 if (parent_section
&& (parent_section
->flags
& SECTION_FLAG_IS_WRAPPER
) &&
1543 wctx
->level
&& wctx
->nb_item
[wctx
->level
-1])
1545 xml
->indent_level
++;
1547 if (section
->flags
& SECTION_FLAG_IS_ARRAY
) {
1548 XML_INDENT(); printf("<%s>\n", section
->name
);
1550 XML_INDENT(); printf("<%s ", section
->name
);
1551 xml
->within_tag
= 1;
1556 static void xml_print_section_footer(WriterContext
*wctx
)
1558 XMLContext
*xml
= wctx
->priv
;
1559 const struct section
*section
= wctx
->section
[wctx
->level
];
1561 if (wctx
->level
== 0) {
1562 printf("</%sffprobe>\n", xml
->fully_qualified
? "ffprobe:" : "");
1563 } else if (xml
->within_tag
) {
1564 xml
->within_tag
= 0;
1566 xml
->indent_level
--;
1567 } else if (section
->flags
& SECTION_FLAG_HAS_VARIABLE_FIELDS
) {
1568 xml
->indent_level
--;
1570 XML_INDENT(); printf("</%s>\n", section
->name
);
1571 xml
->indent_level
--;
1575 static void xml_print_str(WriterContext
*wctx
, const char *key
, const char *value
)
1578 XMLContext
*xml
= wctx
->priv
;
1579 const struct section
*section
= wctx
->section
[wctx
->level
];
1581 av_bprint_init(&buf
, 1, AV_BPRINT_SIZE_UNLIMITED
);
1583 if (section
->flags
& SECTION_FLAG_HAS_VARIABLE_FIELDS
) {
1585 printf("<%s key=\"%s\"",
1586 section
->element_name
, xml_escape_str(&buf
, key
, wctx
));
1587 av_bprint_clear(&buf
);
1588 printf(" value=\"%s\"/>\n", xml_escape_str(&buf
, value
, wctx
));
1590 if (wctx
->nb_item
[wctx
->level
])
1592 printf("%s=\"%s\"", key
, xml_escape_str(&buf
, value
, wctx
));
1595 av_bprint_finalize(&buf
, NULL
);
1598 static void xml_print_int(WriterContext
*wctx
, const char *key
, long long int value
)
1600 if (wctx
->nb_item
[wctx
->level
])
1602 printf("%s=\"%lld\"", key
, value
);
1605 static Writer xml_writer
= {
1607 .priv_size
= sizeof(XMLContext
),
1609 .print_section_header
= xml_print_section_header
,
1610 .print_section_footer
= xml_print_section_footer
,
1611 .print_integer
= xml_print_int
,
1612 .print_string
= xml_print_str
,
1613 .flags
= WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER
,
1614 .priv_class
= &xml_class
,
1617 static void writer_register_all(void)
1619 static int initialized
;
1625 writer_register(&default_writer
);
1626 writer_register(&compact_writer
);
1627 writer_register(&csv_writer
);
1628 writer_register(&flat_writer
);
1629 writer_register(&ini_writer
);
1630 writer_register(&json_writer
);
1631 writer_register(&xml_writer
);
1634 #define print_fmt(k, f, ...) do { \
1635 av_bprint_clear(&pbuf); \
1636 av_bprintf(&pbuf, f, __VA_ARGS__); \
1637 writer_print_string(w, k, pbuf.str, 0); \
1640 #define print_int(k, v) writer_print_integer(w, k, v)
1641 #define print_q(k, v, s) writer_print_rational(w, k, v, s)
1642 #define print_str(k, v) writer_print_string(w, k, v, 0)
1643 #define print_str_opt(k, v) writer_print_string(w, k, v, PRINT_STRING_OPT)
1644 #define print_str_validate(k, v) writer_print_string(w, k, v, PRINT_STRING_VALIDATE)
1645 #define print_time(k, v, tb) writer_print_time(w, k, v, tb, 0)
1646 #define print_ts(k, v) writer_print_ts(w, k, v, 0)
1647 #define print_duration_time(k, v, tb) writer_print_time(w, k, v, tb, 1)
1648 #define print_duration_ts(k, v) writer_print_ts(w, k, v, 1)
1649 #define print_val(k, v, u) do { \
1650 struct unit_value uv; \
1653 writer_print_string(w, k, value_string(val_str, sizeof(val_str), uv), 0); \
1656 #define print_section_header(s) writer_print_section_header(w, s)
1657 #define print_section_footer(s) writer_print_section_footer(w, s)
1659 #define REALLOCZ_ARRAY_STREAM(ptr, cur_n, new_n) \
1661 ret = av_reallocp_array(&(ptr), (new_n), sizeof(*(ptr))); \
1664 memset( (ptr) + (cur_n), 0, ((new_n) - (cur_n)) * sizeof(*(ptr)) ); \
1667 static inline int show_tags(WriterContext
*w
, AVDictionary
*tags
, int section_id
)
1669 AVDictionaryEntry
*tag
= NULL
;
1674 writer_print_section_header(w
, section_id
);
1676 while ((tag
= av_dict_get(tags
, "", tag
, AV_DICT_IGNORE_SUFFIX
))) {
1677 if ((ret
= print_str_validate(tag
->key
, tag
->value
)) < 0)
1680 writer_print_section_footer(w
);
1685 static void show_packet(WriterContext
*w
, AVFormatContext
*fmt_ctx
, AVPacket
*pkt
, int packet_idx
)
1688 AVStream
*st
= fmt_ctx
->streams
[pkt
->stream_index
];
1692 av_bprint_init(&pbuf
, 1, AV_BPRINT_SIZE_UNLIMITED
);
1694 writer_print_section_header(w
, SECTION_ID_PACKET
);
1696 s
= av_get_media_type_string(st
->codec
->codec_type
);
1697 if (s
) print_str ("codec_type", s
);
1698 else print_str_opt("codec_type", "unknown");
1699 print_int("stream_index", pkt
->stream_index
);
1700 print_ts ("pts", pkt
->pts
);
1701 print_time("pts_time", pkt
->pts
, &st
->time_base
);
1702 print_ts ("dts", pkt
->dts
);
1703 print_time("dts_time", pkt
->dts
, &st
->time_base
);
1704 print_duration_ts("duration", pkt
->duration
);
1705 print_duration_time("duration_time", pkt
->duration
, &st
->time_base
);
1706 print_duration_ts("convergence_duration", pkt
->convergence_duration
);
1707 print_duration_time("convergence_duration_time", pkt
->convergence_duration
, &st
->time_base
);
1708 print_val("size", pkt
->size
, unit_byte_str
);
1709 if (pkt
->pos
!= -1) print_fmt ("pos", "%"PRId64
, pkt
->pos
);
1710 else print_str_opt("pos", "N/A");
1711 print_fmt("flags", "%c", pkt
->flags
& AV_PKT_FLAG_KEY
? 'K' : '_');
1713 writer_print_data(w
, "data", pkt
->data
, pkt
->size
);
1714 writer_print_data_hash(w
, "data_hash", pkt
->data
, pkt
->size
);
1715 writer_print_section_footer(w
);
1717 av_bprint_finalize(&pbuf
, NULL
);
1721 static void show_subtitle(WriterContext
*w
, AVSubtitle
*sub
, AVStream
*stream
,
1722 AVFormatContext
*fmt_ctx
)
1726 av_bprint_init(&pbuf
, 1, AV_BPRINT_SIZE_UNLIMITED
);
1728 writer_print_section_header(w
, SECTION_ID_SUBTITLE
);
1730 print_str ("media_type", "subtitle");
1731 print_ts ("pts", sub
->pts
);
1732 print_time("pts_time", sub
->pts
, &AV_TIME_BASE_Q
);
1733 print_int ("format", sub
->format
);
1734 print_int ("start_display_time", sub
->start_display_time
);
1735 print_int ("end_display_time", sub
->end_display_time
);
1736 print_int ("num_rects", sub
->num_rects
);
1738 writer_print_section_footer(w
);
1740 av_bprint_finalize(&pbuf
, NULL
);
1744 static void show_frame(WriterContext
*w
, AVFrame
*frame
, AVStream
*stream
,
1745 AVFormatContext
*fmt_ctx
)
1751 av_bprint_init(&pbuf
, 1, AV_BPRINT_SIZE_UNLIMITED
);
1753 writer_print_section_header(w
, SECTION_ID_FRAME
);
1755 s
= av_get_media_type_string(stream
->codec
->codec_type
);
1756 if (s
) print_str ("media_type", s
);
1757 else print_str_opt("media_type", "unknown");
1758 print_int("key_frame", frame
->key_frame
);
1759 print_ts ("pkt_pts", frame
->pkt_pts
);
1760 print_time("pkt_pts_time", frame
->pkt_pts
, &stream
->time_base
);
1761 print_ts ("pkt_dts", frame
->pkt_dts
);
1762 print_time("pkt_dts_time", frame
->pkt_dts
, &stream
->time_base
);
1763 print_ts ("best_effort_timestamp", av_frame_get_best_effort_timestamp(frame
));
1764 print_time("best_effort_timestamp_time", av_frame_get_best_effort_timestamp(frame
), &stream
->time_base
);
1765 print_duration_ts ("pkt_duration", av_frame_get_pkt_duration(frame
));
1766 print_duration_time("pkt_duration_time", av_frame_get_pkt_duration(frame
), &stream
->time_base
);
1767 if (av_frame_get_pkt_pos (frame
) != -1) print_fmt ("pkt_pos", "%"PRId64
, av_frame_get_pkt_pos(frame
));
1768 else print_str_opt("pkt_pos", "N/A");
1769 if (av_frame_get_pkt_size(frame
) != -1) print_fmt ("pkt_size", "%d", av_frame_get_pkt_size(frame
));
1770 else print_str_opt("pkt_size", "N/A");
1772 switch (stream
->codec
->codec_type
) {
1775 case AVMEDIA_TYPE_VIDEO
:
1776 print_int("width", frame
->width
);
1777 print_int("height", frame
->height
);
1778 s
= av_get_pix_fmt_name(frame
->format
);
1779 if (s
) print_str ("pix_fmt", s
);
1780 else print_str_opt("pix_fmt", "unknown");
1781 sar
= av_guess_sample_aspect_ratio(fmt_ctx
, stream
, frame
);
1783 print_q("sample_aspect_ratio", sar
, ':');
1785 print_str_opt("sample_aspect_ratio", "N/A");
1787 print_fmt("pict_type", "%c", av_get_picture_type_char(frame
->pict_type
));
1788 print_int("coded_picture_number", frame
->coded_picture_number
);
1789 print_int("display_picture_number", frame
->display_picture_number
);
1790 print_int("interlaced_frame", frame
->interlaced_frame
);
1791 print_int("top_field_first", frame
->top_field_first
);
1792 print_int("repeat_pict", frame
->repeat_pict
);
1795 case AVMEDIA_TYPE_AUDIO
:
1796 s
= av_get_sample_fmt_name(frame
->format
);
1797 if (s
) print_str ("sample_fmt", s
);
1798 else print_str_opt("sample_fmt", "unknown");
1799 print_int("nb_samples", frame
->nb_samples
);
1800 print_int("channels", av_frame_get_channels(frame
));
1801 if (av_frame_get_channel_layout(frame
)) {
1802 av_bprint_clear(&pbuf
);
1803 av_bprint_channel_layout(&pbuf
, av_frame_get_channels(frame
),
1804 av_frame_get_channel_layout(frame
));
1805 print_str ("channel_layout", pbuf
.str
);
1807 print_str_opt("channel_layout", "unknown");
1810 if (do_show_frame_tags
)
1811 show_tags(w
, av_frame_get_metadata(frame
), SECTION_ID_FRAME_TAGS
);
1812 if (frame
->nb_side_data
) {
1813 writer_print_section_header(w
, SECTION_ID_FRAME_SIDE_DATA_LIST
);
1814 for (i
= 0; i
< frame
->nb_side_data
; i
++) {
1815 AVFrameSideData
*sd
= frame
->side_data
[i
];
1818 writer_print_section_header(w
, SECTION_ID_FRAME_SIDE_DATA
);
1819 name
= av_frame_side_data_name(sd
->type
);
1820 print_str("side_data_type", name
? name
: "unknown");
1821 print_int("side_data_size", sd
->size
);
1822 writer_print_section_footer(w
);
1824 writer_print_section_footer(w
);
1827 writer_print_section_footer(w
);
1829 av_bprint_finalize(&pbuf
, NULL
);
1833 static av_always_inline
int process_frame(WriterContext
*w
,
1834 AVFormatContext
*fmt_ctx
,
1835 AVFrame
*frame
, AVPacket
*pkt
)
1837 AVCodecContext
*dec_ctx
= fmt_ctx
->streams
[pkt
->stream_index
]->codec
;
1839 int ret
= 0, got_frame
= 0;
1841 if (dec_ctx
->codec
) {
1842 switch (dec_ctx
->codec_type
) {
1843 case AVMEDIA_TYPE_VIDEO
:
1844 ret
= avcodec_decode_video2(dec_ctx
, frame
, &got_frame
, pkt
);
1847 case AVMEDIA_TYPE_AUDIO
:
1848 ret
= avcodec_decode_audio4(dec_ctx
, frame
, &got_frame
, pkt
);
1851 case AVMEDIA_TYPE_SUBTITLE
:
1852 ret
= avcodec_decode_subtitle2(dec_ctx
, &sub
, &got_frame
, pkt
);
1859 ret
= FFMIN(ret
, pkt
->size
); /* guard against bogus return values */
1863 int is_sub
= (dec_ctx
->codec_type
== AVMEDIA_TYPE_SUBTITLE
);
1864 nb_streams_frames
[pkt
->stream_index
]++;
1867 show_subtitle(w
, &sub
, fmt_ctx
->streams
[pkt
->stream_index
], fmt_ctx
);
1869 show_frame(w
, frame
, fmt_ctx
->streams
[pkt
->stream_index
], fmt_ctx
);
1871 avsubtitle_free(&sub
);
1876 static void log_read_interval(const ReadInterval
*interval
, void *log_ctx
, int log_level
)
1878 av_log(log_ctx
, log_level
, "id:%d", interval
->id
);
1880 if (interval
->has_start
) {
1881 av_log(log_ctx
, log_level
, " start:%s%s", interval
->start_is_offset
? "+" : "",
1882 av_ts2timestr(interval
->start
, &AV_TIME_BASE_Q
));
1884 av_log(log_ctx
, log_level
, " start:N/A");
1887 if (interval
->has_end
) {
1888 av_log(log_ctx
, log_level
, " end:%s", interval
->end_is_offset
? "+" : "");
1889 if (interval
->duration_frames
)
1890 av_log(log_ctx
, log_level
, "#%"PRId64
, interval
->end
);
1892 av_log(log_ctx
, log_level
, "%s", av_ts2timestr(interval
->end
, &AV_TIME_BASE_Q
));
1894 av_log(log_ctx
, log_level
, " end:N/A");
1897 av_log(log_ctx
, log_level
, "\n");
1900 static int read_interval_packets(WriterContext
*w
, AVFormatContext
*fmt_ctx
,
1901 const ReadInterval
*interval
, int64_t *cur_ts
)
1904 AVFrame
*frame
= NULL
;
1905 int ret
= 0, i
= 0, frame_count
= 0;
1906 int64_t start
= -INT64_MAX
, end
= interval
->end
;
1907 int has_start
= 0, has_end
= interval
->has_end
&& !interval
->end_is_offset
;
1909 av_init_packet(&pkt
);
1911 av_log(NULL
, AV_LOG_VERBOSE
, "Processing read interval ");
1912 log_read_interval(interval
, NULL
, AV_LOG_VERBOSE
);
1914 if (interval
->has_start
) {
1916 if (interval
->start_is_offset
) {
1917 if (*cur_ts
== AV_NOPTS_VALUE
) {
1918 av_log(NULL
, AV_LOG_ERROR
,
1919 "Could not seek to relative position since current "
1920 "timestamp is not defined\n");
1921 ret
= AVERROR(EINVAL
);
1924 target
= *cur_ts
+ interval
->start
;
1926 target
= interval
->start
;
1929 av_log(NULL
, AV_LOG_VERBOSE
, "Seeking to read interval start point %s\n",
1930 av_ts2timestr(target
, &AV_TIME_BASE_Q
));
1931 if ((ret
= avformat_seek_file(fmt_ctx
, -1, -INT64_MAX
, target
, INT64_MAX
, 0)) < 0) {
1932 av_log(NULL
, AV_LOG_ERROR
, "Could not seek to position %"PRId64
": %s\n",
1933 interval
->start
, av_err2str(ret
));
1938 frame
= av_frame_alloc();
1940 ret
= AVERROR(ENOMEM
);
1943 while (!av_read_frame(fmt_ctx
, &pkt
)) {
1944 if (fmt_ctx
->nb_streams
> nb_streams
) {
1945 REALLOCZ_ARRAY_STREAM(nb_streams_frames
, nb_streams
, fmt_ctx
->nb_streams
);
1946 REALLOCZ_ARRAY_STREAM(nb_streams_packets
, nb_streams
, fmt_ctx
->nb_streams
);
1947 REALLOCZ_ARRAY_STREAM(selected_streams
, nb_streams
, fmt_ctx
->nb_streams
);
1948 nb_streams
= fmt_ctx
->nb_streams
;
1950 if (selected_streams
[pkt
.stream_index
]) {
1951 AVRational tb
= fmt_ctx
->streams
[pkt
.stream_index
]->time_base
;
1953 if (pkt
.pts
!= AV_NOPTS_VALUE
)
1954 *cur_ts
= av_rescale_q(pkt
.pts
, tb
, AV_TIME_BASE_Q
);
1956 if (!has_start
&& *cur_ts
!= AV_NOPTS_VALUE
) {
1961 if (has_start
&& !has_end
&& interval
->end_is_offset
) {
1962 end
= start
+ interval
->end
;
1966 if (interval
->end_is_offset
&& interval
->duration_frames
) {
1967 if (frame_count
>= interval
->end
)
1969 } else if (has_end
&& *cur_ts
!= AV_NOPTS_VALUE
&& *cur_ts
>= end
) {
1974 if (do_read_packets
) {
1975 if (do_show_packets
)
1976 show_packet(w
, fmt_ctx
, &pkt
, i
++);
1977 nb_streams_packets
[pkt
.stream_index
]++;
1979 if (do_read_frames
) {
1981 while (pkt1
.size
&& process_frame(w
, fmt_ctx
, frame
, &pkt1
) > 0);
1984 av_free_packet(&pkt
);
1986 av_init_packet(&pkt
);
1989 //Flush remaining frames that are cached in the decoder
1990 for (i
= 0; i
< fmt_ctx
->nb_streams
; i
++) {
1991 pkt
.stream_index
= i
;
1993 while (process_frame(w
, fmt_ctx
, frame
, &pkt
) > 0);
1997 av_frame_free(&frame
);
1999 av_log(NULL
, AV_LOG_ERROR
, "Could not read packets in interval ");
2000 log_read_interval(interval
, NULL
, AV_LOG_ERROR
);
2005 static int read_packets(WriterContext
*w
, AVFormatContext
*fmt_ctx
)
2008 int64_t cur_ts
= fmt_ctx
->start_time
;
2010 if (read_intervals_nb
== 0) {
2011 ReadInterval interval
= (ReadInterval
) { .has_start
= 0, .has_end
= 0 };
2012 ret
= read_interval_packets(w
, fmt_ctx
, &interval
, &cur_ts
);
2014 for (i
= 0; i
< read_intervals_nb
; i
++) {
2015 ret
= read_interval_packets(w
, fmt_ctx
, &read_intervals
[i
], &cur_ts
);
2024 static int show_stream(WriterContext
*w
, AVFormatContext
*fmt_ctx
, int stream_idx
, int in_program
)
2026 AVStream
*stream
= fmt_ctx
->streams
[stream_idx
];
2027 AVCodecContext
*dec_ctx
;
2031 AVRational sar
, dar
;
2033 const AVCodecDescriptor
*cd
;
2036 av_bprint_init(&pbuf
, 1, AV_BPRINT_SIZE_UNLIMITED
);
2038 writer_print_section_header(w
, in_program
? SECTION_ID_PROGRAM_STREAM
: SECTION_ID_STREAM
);
2040 print_int("index", stream
->index
);
2042 if ((dec_ctx
= stream
->codec
)) {
2043 const char *profile
= NULL
;
2044 dec
= dec_ctx
->codec
;
2046 print_str("codec_name", dec
->name
);
2048 if (dec
->long_name
) print_str ("codec_long_name", dec
->long_name
);
2049 else print_str_opt("codec_long_name", "unknown");
2051 } else if ((cd
= avcodec_descriptor_get(stream
->codec
->codec_id
))) {
2052 print_str_opt("codec_name", cd
->name
);
2054 print_str_opt("codec_long_name",
2055 cd
->long_name
? cd
->long_name
: "unknown");
2058 print_str_opt("codec_name", "unknown");
2060 print_str_opt("codec_long_name", "unknown");
2064 if (dec
&& (profile
= av_get_profile_name(dec
, dec_ctx
->profile
)))
2065 print_str("profile", profile
);
2067 print_str_opt("profile", "unknown");
2069 s
= av_get_media_type_string(dec_ctx
->codec_type
);
2070 if (s
) print_str ("codec_type", s
);
2071 else print_str_opt("codec_type", "unknown");
2072 print_q("codec_time_base", dec_ctx
->time_base
, '/');
2074 /* print AVI/FourCC tag */
2075 av_get_codec_tag_string(val_str
, sizeof(val_str
), dec_ctx
->codec_tag
);
2076 print_str("codec_tag_string", val_str
);
2077 print_fmt("codec_tag", "0x%04x", dec_ctx
->codec_tag
);
2079 switch (dec_ctx
->codec_type
) {
2080 case AVMEDIA_TYPE_VIDEO
:
2081 print_int("width", dec_ctx
->width
);
2082 print_int("height", dec_ctx
->height
);
2083 print_int("has_b_frames", dec_ctx
->has_b_frames
);
2084 sar
= av_guess_sample_aspect_ratio(fmt_ctx
, stream
, NULL
);
2086 print_q("sample_aspect_ratio", sar
, ':');
2087 av_reduce(&dar
.num
, &dar
.den
,
2088 dec_ctx
->width
* sar
.num
,
2089 dec_ctx
->height
* sar
.den
,
2091 print_q("display_aspect_ratio", dar
, ':');
2093 print_str_opt("sample_aspect_ratio", "N/A");
2094 print_str_opt("display_aspect_ratio", "N/A");
2096 s
= av_get_pix_fmt_name(dec_ctx
->pix_fmt
);
2097 if (s
) print_str ("pix_fmt", s
);
2098 else print_str_opt("pix_fmt", "unknown");
2099 print_int("level", dec_ctx
->level
);
2100 if (dec_ctx
->color_range
!= AVCOL_RANGE_UNSPECIFIED
)
2101 print_str ("color_range", dec_ctx
->color_range
== AVCOL_RANGE_MPEG
? "tv": "pc");
2103 print_str_opt("color_range", "N/A");
2104 s
= av_get_colorspace_name(dec_ctx
->colorspace
);
2105 if (s
) print_str ("color_space", s
);
2106 else print_str_opt("color_space", "unknown");
2107 if (dec_ctx
->timecode_frame_start
>= 0) {
2108 char tcbuf
[AV_TIMECODE_STR_SIZE
];
2109 av_timecode_make_mpeg_tc_string(tcbuf
, dec_ctx
->timecode_frame_start
);
2110 print_str("timecode", tcbuf
);
2112 print_str_opt("timecode", "N/A");
2116 case AVMEDIA_TYPE_AUDIO
:
2117 s
= av_get_sample_fmt_name(dec_ctx
->sample_fmt
);
2118 if (s
) print_str ("sample_fmt", s
);
2119 else print_str_opt("sample_fmt", "unknown");
2120 print_val("sample_rate", dec_ctx
->sample_rate
, unit_hertz_str
);
2121 print_int("channels", dec_ctx
->channels
);
2123 if (dec_ctx
->channel_layout
) {
2124 av_bprint_clear(&pbuf
);
2125 av_bprint_channel_layout(&pbuf
, dec_ctx
->channels
, dec_ctx
->channel_layout
);
2126 print_str ("channel_layout", pbuf
.str
);
2128 print_str_opt("channel_layout", "unknown");
2131 print_int("bits_per_sample", av_get_bits_per_sample(dec_ctx
->codec_id
));
2134 case AVMEDIA_TYPE_SUBTITLE
:
2136 print_int("width", dec_ctx
->width
);
2138 print_str_opt("width", "N/A");
2139 if (dec_ctx
->height
)
2140 print_int("height", dec_ctx
->height
);
2142 print_str_opt("height", "N/A");
2146 print_str_opt("codec_type", "unknown");
2148 if (dec_ctx
->codec
&& dec_ctx
->codec
->priv_class
&& show_private_data
) {
2149 const AVOption
*opt
= NULL
;
2150 while (opt
= av_opt_next(dec_ctx
->priv_data
,opt
)) {
2152 if (opt
->flags
) continue;
2153 if (av_opt_get(dec_ctx
->priv_data
, opt
->name
, 0, &str
) >= 0) {
2154 print_str(opt
->name
, str
);
2160 if (fmt_ctx
->iformat
->flags
& AVFMT_SHOW_IDS
) print_fmt ("id", "0x%x", stream
->id
);
2161 else print_str_opt("id", "N/A");
2162 print_q("r_frame_rate", stream
->r_frame_rate
, '/');
2163 print_q("avg_frame_rate", stream
->avg_frame_rate
, '/');
2164 print_q("time_base", stream
->time_base
, '/');
2165 print_ts ("start_pts", stream
->start_time
);
2166 print_time("start_time", stream
->start_time
, &stream
->time_base
);
2167 print_ts ("duration_ts", stream
->duration
);
2168 print_time("duration", stream
->duration
, &stream
->time_base
);
2169 if (dec_ctx
->bit_rate
> 0) print_val ("bit_rate", dec_ctx
->bit_rate
, unit_bit_per_second_str
);
2170 else print_str_opt("bit_rate", "N/A");
2171 if (dec_ctx
->rc_max_rate
> 0) print_val ("max_bit_rate", dec_ctx
->rc_max_rate
, unit_bit_per_second_str
);
2172 else print_str_opt("max_bit_rate", "N/A");
2173 if (dec_ctx
->bits_per_raw_sample
> 0) print_fmt("bits_per_raw_sample", "%d", dec_ctx
->bits_per_raw_sample
);
2174 else print_str_opt("bits_per_raw_sample", "N/A");
2175 if (stream
->nb_frames
) print_fmt ("nb_frames", "%"PRId64
, stream
->nb_frames
);
2176 else print_str_opt("nb_frames", "N/A");
2177 if (nb_streams_frames
[stream_idx
]) print_fmt ("nb_read_frames", "%"PRIu64
, nb_streams_frames
[stream_idx
]);
2178 else print_str_opt("nb_read_frames", "N/A");
2179 if (nb_streams_packets
[stream_idx
]) print_fmt ("nb_read_packets", "%"PRIu64
, nb_streams_packets
[stream_idx
]);
2180 else print_str_opt("nb_read_packets", "N/A");
2182 writer_print_data(w
, "extradata", dec_ctx
->extradata
,
2183 dec_ctx
->extradata_size
);
2184 writer_print_data_hash(w
, "extradata_hash", dec_ctx
->extradata
,
2185 dec_ctx
->extradata_size
);
2187 /* Print disposition information */
2188 #define PRINT_DISPOSITION(flagname, name) do { \
2189 print_int(name, !!(stream->disposition & AV_DISPOSITION_##flagname)); \
2192 if (do_show_stream_disposition
) {
2193 writer_print_section_header(w
, in_program
? SECTION_ID_PROGRAM_STREAM_DISPOSITION
: SECTION_ID_STREAM_DISPOSITION
);
2194 PRINT_DISPOSITION(DEFAULT
, "default");
2195 PRINT_DISPOSITION(DUB
, "dub");
2196 PRINT_DISPOSITION(ORIGINAL
, "original");
2197 PRINT_DISPOSITION(COMMENT
, "comment");
2198 PRINT_DISPOSITION(LYRICS
, "lyrics");
2199 PRINT_DISPOSITION(KARAOKE
, "karaoke");
2200 PRINT_DISPOSITION(FORCED
, "forced");
2201 PRINT_DISPOSITION(HEARING_IMPAIRED
, "hearing_impaired");
2202 PRINT_DISPOSITION(VISUAL_IMPAIRED
, "visual_impaired");
2203 PRINT_DISPOSITION(CLEAN_EFFECTS
, "clean_effects");
2204 PRINT_DISPOSITION(ATTACHED_PIC
, "attached_pic");
2205 writer_print_section_footer(w
);
2208 if (do_show_stream_tags
)
2209 ret
= show_tags(w
, stream
->metadata
, in_program
? SECTION_ID_PROGRAM_STREAM_TAGS
: SECTION_ID_STREAM_TAGS
);
2211 writer_print_section_footer(w
);
2212 av_bprint_finalize(&pbuf
, NULL
);
2218 static int show_streams(WriterContext
*w
, AVFormatContext
*fmt_ctx
)
2222 writer_print_section_header(w
, SECTION_ID_STREAMS
);
2223 for (i
= 0; i
< fmt_ctx
->nb_streams
; i
++)
2224 if (selected_streams
[i
]) {
2225 ret
= show_stream(w
, fmt_ctx
, i
, 0);
2229 writer_print_section_footer(w
);
2234 static int show_program(WriterContext
*w
, AVFormatContext
*fmt_ctx
, AVProgram
*program
)
2238 writer_print_section_header(w
, SECTION_ID_PROGRAM
);
2239 print_int("program_id", program
->id
);
2240 print_int("program_num", program
->program_num
);
2241 print_int("nb_streams", program
->nb_stream_indexes
);
2242 print_int("pmt_pid", program
->pmt_pid
);
2243 print_int("pcr_pid", program
->pcr_pid
);
2244 print_ts("start_pts", program
->start_time
);
2245 print_time("start_time", program
->start_time
, &AV_TIME_BASE_Q
);
2246 print_ts("end_pts", program
->end_time
);
2247 print_time("end_time", program
->end_time
, &AV_TIME_BASE_Q
);
2248 if (do_show_program_tags
)
2249 ret
= show_tags(w
, program
->metadata
, SECTION_ID_PROGRAM_TAGS
);
2253 writer_print_section_header(w
, SECTION_ID_PROGRAM_STREAMS
);
2254 for (i
= 0; i
< program
->nb_stream_indexes
; i
++) {
2255 if (selected_streams
[program
->stream_index
[i
]]) {
2256 ret
= show_stream(w
, fmt_ctx
, program
->stream_index
[i
], 1);
2261 writer_print_section_footer(w
);
2264 writer_print_section_footer(w
);
2268 static int show_programs(WriterContext
*w
, AVFormatContext
*fmt_ctx
)
2272 writer_print_section_header(w
, SECTION_ID_PROGRAMS
);
2273 for (i
= 0; i
< fmt_ctx
->nb_programs
; i
++) {
2274 AVProgram
*program
= fmt_ctx
->programs
[i
];
2277 ret
= show_program(w
, fmt_ctx
, program
);
2281 writer_print_section_footer(w
);
2285 static int show_chapters(WriterContext
*w
, AVFormatContext
*fmt_ctx
)
2289 writer_print_section_header(w
, SECTION_ID_CHAPTERS
);
2290 for (i
= 0; i
< fmt_ctx
->nb_chapters
; i
++) {
2291 AVChapter
*chapter
= fmt_ctx
->chapters
[i
];
2293 writer_print_section_header(w
, SECTION_ID_CHAPTER
);
2294 print_int("id", chapter
->id
);
2295 print_q ("time_base", chapter
->time_base
, '/');
2296 print_int("start", chapter
->start
);
2297 print_time("start_time", chapter
->start
, &chapter
->time_base
);
2298 print_int("end", chapter
->end
);
2299 print_time("end_time", chapter
->end
, &chapter
->time_base
);
2300 if (do_show_chapter_tags
)
2301 ret
= show_tags(w
, chapter
->metadata
, SECTION_ID_CHAPTER_TAGS
);
2302 writer_print_section_footer(w
);
2304 writer_print_section_footer(w
);
2309 static int show_format(WriterContext
*w
, AVFormatContext
*fmt_ctx
)
2312 int64_t size
= fmt_ctx
->pb
? avio_size(fmt_ctx
->pb
) : -1;
2315 writer_print_section_header(w
, SECTION_ID_FORMAT
);
2316 print_str_validate("filename", fmt_ctx
->filename
);
2317 print_int("nb_streams", fmt_ctx
->nb_streams
);
2318 print_int("nb_programs", fmt_ctx
->nb_programs
);
2319 print_str("format_name", fmt_ctx
->iformat
->name
);
2321 if (fmt_ctx
->iformat
->long_name
) print_str ("format_long_name", fmt_ctx
->iformat
->long_name
);
2322 else print_str_opt("format_long_name", "unknown");
2324 print_time("start_time", fmt_ctx
->start_time
, &AV_TIME_BASE_Q
);
2325 print_time("duration", fmt_ctx
->duration
, &AV_TIME_BASE_Q
);
2326 if (size
>= 0) print_val ("size", size
, unit_byte_str
);
2327 else print_str_opt("size", "N/A");
2328 if (fmt_ctx
->bit_rate
> 0) print_val ("bit_rate", fmt_ctx
->bit_rate
, unit_bit_per_second_str
);
2329 else print_str_opt("bit_rate", "N/A");
2330 print_int("probe_score", av_format_get_probe_score(fmt_ctx
));
2331 if (do_show_format_tags
)
2332 ret
= show_tags(w
, fmt_ctx
->metadata
, SECTION_ID_FORMAT_TAGS
);
2334 writer_print_section_footer(w
);
2339 static void show_error(WriterContext
*w
, int err
)
2342 const char *errbuf_ptr
= errbuf
;
2344 if (av_strerror(err
, errbuf
, sizeof(errbuf
)) < 0)
2345 errbuf_ptr
= strerror(AVUNERROR(err
));
2347 writer_print_section_header(w
, SECTION_ID_ERROR
);
2348 print_int("code", err
);
2349 print_str("string", errbuf_ptr
);
2350 writer_print_section_footer(w
);
2353 static int open_input_file(AVFormatContext
**fmt_ctx_ptr
, const char *filename
)
2355 int err
, i
, orig_nb_streams
;
2356 AVFormatContext
*fmt_ctx
= NULL
;
2357 AVDictionaryEntry
*t
;
2358 AVDictionary
**opts
;
2360 if ((err
= avformat_open_input(&fmt_ctx
, filename
,
2361 iformat
, &format_opts
)) < 0) {
2362 print_error(filename
, err
);
2365 if ((t
= av_dict_get(format_opts
, "", NULL
, AV_DICT_IGNORE_SUFFIX
))) {
2366 av_log(NULL
, AV_LOG_ERROR
, "Option %s not found.\n", t
->key
);
2367 return AVERROR_OPTION_NOT_FOUND
;
2370 /* fill the streams in the format context */
2371 opts
= setup_find_stream_info_opts(fmt_ctx
, codec_opts
);
2372 orig_nb_streams
= fmt_ctx
->nb_streams
;
2374 if ((err
= avformat_find_stream_info(fmt_ctx
, opts
)) < 0) {
2375 print_error(filename
, err
);
2378 for (i
= 0; i
< orig_nb_streams
; i
++)
2379 av_dict_free(&opts
[i
]);
2382 av_dump_format(fmt_ctx
, 0, filename
, 0);
2384 /* bind a decoder to each input stream */
2385 for (i
= 0; i
< fmt_ctx
->nb_streams
; i
++) {
2386 AVStream
*stream
= fmt_ctx
->streams
[i
];
2389 if (stream
->codec
->codec_id
== AV_CODEC_ID_PROBE
) {
2390 av_log(NULL
, AV_LOG_WARNING
,
2391 "Failed to probe codec for input stream %d\n",
2393 } else if (!(codec
= avcodec_find_decoder(stream
->codec
->codec_id
))) {
2394 av_log(NULL
, AV_LOG_WARNING
,
2395 "Unsupported codec with id %d for input stream %d\n",
2396 stream
->codec
->codec_id
, stream
->index
);
2398 AVDictionary
*opts
= filter_codec_opts(codec_opts
, stream
->codec
->codec_id
,
2399 fmt_ctx
, stream
, codec
);
2400 if (avcodec_open2(stream
->codec
, codec
, &opts
) < 0) {
2401 av_log(NULL
, AV_LOG_WARNING
, "Could not open codec for input stream %d\n",
2404 if ((t
= av_dict_get(opts
, "", NULL
, AV_DICT_IGNORE_SUFFIX
))) {
2405 av_log(NULL
, AV_LOG_ERROR
, "Option %s for input stream %d not found\n",
2406 t
->key
, stream
->index
);
2407 return AVERROR_OPTION_NOT_FOUND
;
2412 *fmt_ctx_ptr
= fmt_ctx
;
2416 static void close_input_file(AVFormatContext
**ctx_ptr
)
2419 AVFormatContext
*fmt_ctx
= *ctx_ptr
;
2421 /* close decoder for each stream */
2422 for (i
= 0; i
< fmt_ctx
->nb_streams
; i
++)
2423 if (fmt_ctx
->streams
[i
]->codec
->codec_id
!= AV_CODEC_ID_NONE
)
2424 avcodec_close(fmt_ctx
->streams
[i
]->codec
);
2426 avformat_close_input(ctx_ptr
);
2429 static int probe_file(WriterContext
*wctx
, const char *filename
)
2431 AVFormatContext
*fmt_ctx
;
2435 do_read_frames
= do_show_frames
|| do_count_frames
;
2436 do_read_packets
= do_show_packets
|| do_count_packets
;
2438 ret
= open_input_file(&fmt_ctx
, filename
);
2442 #define CHECK_END if (ret < 0) goto end
2444 nb_streams
= fmt_ctx
->nb_streams
;
2445 REALLOCZ_ARRAY_STREAM(nb_streams_frames
,0,fmt_ctx
->nb_streams
);
2446 REALLOCZ_ARRAY_STREAM(nb_streams_packets
,0,fmt_ctx
->nb_streams
);
2447 REALLOCZ_ARRAY_STREAM(selected_streams
,0,fmt_ctx
->nb_streams
);
2449 for (i
= 0; i
< fmt_ctx
->nb_streams
; i
++) {
2450 if (stream_specifier
) {
2451 ret
= avformat_match_stream_specifier(fmt_ctx
,
2452 fmt_ctx
->streams
[i
],
2456 selected_streams
[i
] = ret
;
2459 selected_streams
[i
] = 1;
2463 if (do_read_frames
|| do_read_packets
) {
2464 if (do_show_frames
&& do_show_packets
&&
2465 wctx
->writer
->flags
& WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER
)
2466 section_id
= SECTION_ID_PACKETS_AND_FRAMES
;
2467 else if (do_show_packets
&& !do_show_frames
)
2468 section_id
= SECTION_ID_PACKETS
;
2469 else // (!do_show_packets && do_show_frames)
2470 section_id
= SECTION_ID_FRAMES
;
2471 if (do_show_frames
|| do_show_packets
)
2472 writer_print_section_header(wctx
, section_id
);
2473 ret
= read_packets(wctx
, fmt_ctx
);
2474 if (do_show_frames
|| do_show_packets
)
2475 writer_print_section_footer(wctx
);
2479 if (do_show_programs
) {
2480 ret
= show_programs(wctx
, fmt_ctx
);
2484 if (do_show_streams
) {
2485 ret
= show_streams(wctx
, fmt_ctx
);
2488 if (do_show_chapters
) {
2489 ret
= show_chapters(wctx
, fmt_ctx
);
2492 if (do_show_format
) {
2493 ret
= show_format(wctx
, fmt_ctx
);
2498 close_input_file(&fmt_ctx
);
2499 av_freep(&nb_streams_frames
);
2500 av_freep(&nb_streams_packets
);
2501 av_freep(&selected_streams
);
2506 static void show_usage(void)
2508 av_log(NULL
, AV_LOG_INFO
, "Simple multimedia streams analyzer\n");
2509 av_log(NULL
, AV_LOG_INFO
, "usage: %s [OPTIONS] [INPUT_FILE]\n", program_name
);
2510 av_log(NULL
, AV_LOG_INFO
, "\n");
2513 static void ffprobe_show_program_version(WriterContext
*w
)
2516 av_bprint_init(&pbuf
, 1, AV_BPRINT_SIZE_UNLIMITED
);
2518 writer_print_section_header(w
, SECTION_ID_PROGRAM_VERSION
);
2519 print_str("version", FFMPEG_VERSION
);
2520 print_fmt("copyright", "Copyright (c) %d-%d the FFmpeg developers",
2521 program_birth_year
, CONFIG_THIS_YEAR
);
2522 print_str("build_date", __DATE__
);
2523 print_str("build_time", __TIME__
);
2524 print_str("compiler_ident", CC_IDENT
);
2525 print_str("configuration", FFMPEG_CONFIGURATION
);
2526 writer_print_section_footer(w
);
2528 av_bprint_finalize(&pbuf
, NULL
);
2531 #define SHOW_LIB_VERSION(libname, LIBNAME) \
2533 if (CONFIG_##LIBNAME) { \
2534 unsigned int version = libname##_version(); \
2535 writer_print_section_header(w, SECTION_ID_LIBRARY_VERSION); \
2536 print_str("name", "lib" #libname); \
2537 print_int("major", LIB##LIBNAME##_VERSION_MAJOR); \
2538 print_int("minor", LIB##LIBNAME##_VERSION_MINOR); \
2539 print_int("micro", LIB##LIBNAME##_VERSION_MICRO); \
2540 print_int("version", version); \
2541 print_str("ident", LIB##LIBNAME##_IDENT); \
2542 writer_print_section_footer(w); \
2546 static void ffprobe_show_library_versions(WriterContext
*w
)
2548 writer_print_section_header(w
, SECTION_ID_LIBRARY_VERSIONS
);
2549 SHOW_LIB_VERSION(avutil
, AVUTIL
);
2550 SHOW_LIB_VERSION(avcodec
, AVCODEC
);
2551 SHOW_LIB_VERSION(avformat
, AVFORMAT
);
2552 SHOW_LIB_VERSION(avdevice
, AVDEVICE
);
2553 SHOW_LIB_VERSION(avfilter
, AVFILTER
);
2554 SHOW_LIB_VERSION(swscale
, SWSCALE
);
2555 SHOW_LIB_VERSION(swresample
, SWRESAMPLE
);
2556 SHOW_LIB_VERSION(postproc
, POSTPROC
);
2557 writer_print_section_footer(w
);
2560 static int opt_format(void *optctx
, const char *opt
, const char *arg
)
2562 iformat
= av_find_input_format(arg
);
2564 av_log(NULL
, AV_LOG_ERROR
, "Unknown input format: %s\n", arg
);
2565 return AVERROR(EINVAL
);
2570 static inline void mark_section_show_entries(SectionID section_id
,
2571 int show_all_entries
, AVDictionary
*entries
)
2573 struct section
*section
= §ions
[section_id
];
2575 section
->show_all_entries
= show_all_entries
;
2576 if (show_all_entries
) {
2578 for (id
= section
->children_ids
; *id
!= -1; id
++)
2579 mark_section_show_entries(*id
, show_all_entries
, entries
);
2581 av_dict_copy(§ion
->entries_to_show
, entries
, 0);
2585 static int match_section(const char *section_name
,
2586 int show_all_entries
, AVDictionary
*entries
)
2590 for (i
= 0; i
< FF_ARRAY_ELEMS(sections
); i
++) {
2591 const struct section
*section
= §ions
[i
];
2592 if (!strcmp(section_name
, section
->name
) ||
2593 (section
->unique_name
&& !strcmp(section_name
, section
->unique_name
))) {
2594 av_log(NULL
, AV_LOG_DEBUG
,
2595 "'%s' matches section with unique name '%s'\n", section_name
,
2596 (char *)av_x_if_null(section
->unique_name
, section
->name
));
2598 mark_section_show_entries(section
->id
, show_all_entries
, entries
);
2604 static int opt_show_entries(void *optctx
, const char *opt
, const char *arg
)
2606 const char *p
= arg
;
2610 AVDictionary
*entries
= NULL
;
2611 char *section_name
= av_get_token(&p
, "=:");
2612 int show_all_entries
= 0;
2614 if (!section_name
) {
2615 av_log(NULL
, AV_LOG_ERROR
,
2616 "Missing section name for option '%s'\n", opt
);
2617 return AVERROR(EINVAL
);
2622 while (*p
&& *p
!= ':') {
2623 char *entry
= av_get_token(&p
, ",:");
2626 av_log(NULL
, AV_LOG_VERBOSE
,
2627 "Adding '%s' to the entries to show in section '%s'\n",
2628 entry
, section_name
);
2629 av_dict_set(&entries
, entry
, "", AV_DICT_DONT_STRDUP_KEY
);
2634 show_all_entries
= 1;
2637 ret
= match_section(section_name
, show_all_entries
, entries
);
2639 av_log(NULL
, AV_LOG_ERROR
, "No match for section '%s'\n", section_name
);
2640 ret
= AVERROR(EINVAL
);
2642 av_dict_free(&entries
);
2643 av_free(section_name
);
2654 static int opt_show_format_entry(void *optctx
, const char *opt
, const char *arg
)
2656 char *buf
= av_asprintf("format=%s", arg
);
2659 av_log(NULL
, AV_LOG_WARNING
,
2660 "Option '%s' is deprecated, use '-show_entries format=%s' instead\n",
2662 ret
= opt_show_entries(optctx
, opt
, buf
);
2667 static void opt_input_file(void *optctx
, const char *arg
)
2669 if (input_filename
) {
2670 av_log(NULL
, AV_LOG_ERROR
,
2671 "Argument '%s' provided as input filename, but '%s' was already specified.\n",
2672 arg
, input_filename
);
2675 if (!strcmp(arg
, "-"))
2677 input_filename
= arg
;
2680 static int opt_input_file_i(void *optctx
, const char *opt
, const char *arg
)
2682 opt_input_file(optctx
, arg
);
2686 void show_help_default(const char *opt
, const char *arg
)
2688 av_log_set_callback(log_callback_help
);
2690 show_help_options(options
, "Main options:", 0, 0, 0);
2693 show_help_children(avformat_get_class(), AV_OPT_FLAG_DECODING_PARAM
);
2697 * Parse interval specification, according to the format:
2698 * INTERVAL ::= [START|+START_OFFSET][%[END|+END_OFFSET]]
2699 * INTERVALS ::= INTERVAL[,INTERVALS]
2701 static int parse_read_interval(const char *interval_spec
,
2702 ReadInterval
*interval
)
2705 char *next
, *p
, *spec
= av_strdup(interval_spec
);
2707 return AVERROR(ENOMEM
);
2710 av_log(NULL
, AV_LOG_ERROR
, "Invalid empty interval specification\n");
2711 ret
= AVERROR(EINVAL
);
2716 next
= strchr(spec
, '%');
2720 /* parse first part */
2722 interval
->has_start
= 1;
2725 interval
->start_is_offset
= 1;
2728 interval
->start_is_offset
= 0;
2731 ret
= av_parse_time(&interval
->start
, p
, 1);
2733 av_log(NULL
, AV_LOG_ERROR
, "Invalid interval start specification '%s'\n", p
);
2737 interval
->has_start
= 0;
2740 /* parse second part */
2744 interval
->has_end
= 1;
2747 interval
->end_is_offset
= 1;
2750 interval
->end_is_offset
= 0;
2753 if (interval
->end_is_offset
&& *p
== '#') {
2756 interval
->duration_frames
= 1;
2758 lli
= strtoll(p
, &tail
, 10);
2759 if (*tail
|| lli
< 0) {
2760 av_log(NULL
, AV_LOG_ERROR
,
2761 "Invalid or negative value '%s' for duration number of frames\n", p
);
2764 interval
->end
= lli
;
2766 ret
= av_parse_time(&us
, p
, 1);
2768 av_log(NULL
, AV_LOG_ERROR
, "Invalid interval end/duration specification '%s'\n", p
);
2774 interval
->has_end
= 0;
2782 static int parse_read_intervals(const char *intervals_spec
)
2785 char *p
, *spec
= av_strdup(intervals_spec
);
2787 return AVERROR(ENOMEM
);
2789 /* preparse specification, get number of intervals */
2790 for (n
= 0, p
= spec
; *p
; p
++)
2795 read_intervals
= av_malloc_array(n
, sizeof(*read_intervals
));
2796 if (!read_intervals
) {
2797 ret
= AVERROR(ENOMEM
);
2800 read_intervals_nb
= n
;
2802 /* parse intervals */
2804 for (i
= 0; p
; i
++) {
2807 av_assert0(i
< read_intervals_nb
);
2808 next
= strchr(p
, ',');
2812 read_intervals
[i
].id
= i
;
2813 ret
= parse_read_interval(p
, &read_intervals
[i
]);
2815 av_log(NULL
, AV_LOG_ERROR
, "Error parsing read interval #%d '%s'\n",
2819 av_log(NULL
, AV_LOG_VERBOSE
, "Parsed log interval ");
2820 log_read_interval(&read_intervals
[i
], NULL
, AV_LOG_VERBOSE
);
2823 av_assert0(i
== read_intervals_nb
);
2830 static int opt_read_intervals(void *optctx
, const char *opt
, const char *arg
)
2832 return parse_read_intervals(arg
);
2835 static int opt_pretty(void *optctx
, const char *opt
, const char *arg
)
2837 show_value_unit
= 1;
2838 use_value_prefix
= 1;
2839 use_byte_value_binary_prefix
= 1;
2840 use_value_sexagesimal_format
= 1;
2844 static void print_section(SectionID id
, int level
)
2846 const SectionID
*pid
;
2847 const struct section
*section
= §ions
[id
];
2849 section
->flags
& SECTION_FLAG_IS_WRAPPER
? 'W' : '.',
2850 section
->flags
& SECTION_FLAG_IS_ARRAY
? 'A' : '.',
2851 section
->flags
& SECTION_FLAG_HAS_VARIABLE_FIELDS
? 'V' : '.');
2852 printf("%*c %s", level
* 4, ' ', section
->name
);
2853 if (section
->unique_name
)
2854 printf("/%s", section
->unique_name
);
2857 for (pid
= section
->children_ids
; *pid
!= -1; pid
++)
2858 print_section(*pid
, level
+1);
2861 static int opt_sections(void *optctx
, const char *opt
, const char *arg
)
2863 printf("Sections:\n"
2864 "W.. = Section is a wrapper (contains other sections, no local entries)\n"
2865 ".A. = Section contains an array of elements of the same type\n"
2866 "..V = Section may contain a variable number of fields with variable keys\n"
2867 "FLAGS NAME/UNIQUE_NAME\n"
2869 print_section(SECTION_ID_ROOT
, 0);
2873 static int opt_show_versions(const char *opt
, const char *arg
)
2875 mark_section_show_entries(SECTION_ID_PROGRAM_VERSION
, 1, NULL
);
2876 mark_section_show_entries(SECTION_ID_LIBRARY_VERSION
, 1, NULL
);
2880 #define DEFINE_OPT_SHOW_SECTION(section, target_section_id) \
2881 static int opt_show_##section(const char *opt, const char *arg) \
2883 mark_section_show_entries(SECTION_ID_##target_section_id, 1, NULL); \
2887 DEFINE_OPT_SHOW_SECTION(chapters
, CHAPTERS
);
2888 DEFINE_OPT_SHOW_SECTION(error
, ERROR
);
2889 DEFINE_OPT_SHOW_SECTION(format
, FORMAT
);
2890 DEFINE_OPT_SHOW_SECTION(frames
, FRAMES
);
2891 DEFINE_OPT_SHOW_SECTION(library_versions
, LIBRARY_VERSIONS
);
2892 DEFINE_OPT_SHOW_SECTION(packets
, PACKETS
);
2893 DEFINE_OPT_SHOW_SECTION(program_version
, PROGRAM_VERSION
);
2894 DEFINE_OPT_SHOW_SECTION(streams
, STREAMS
);
2895 DEFINE_OPT_SHOW_SECTION(programs
, PROGRAMS
);
2897 static const OptionDef real_options
[] = {
2898 #include "cmdutils_common_opts.h"
2899 { "f", HAS_ARG
, {.func_arg
= opt_format
}, "force format", "format" },
2900 { "unit", OPT_BOOL
, {&show_value_unit
}, "show unit of the displayed values" },
2901 { "prefix", OPT_BOOL
, {&use_value_prefix
}, "use SI prefixes for the displayed values" },
2902 { "byte_binary_prefix", OPT_BOOL
, {&use_byte_value_binary_prefix
},
2903 "use binary prefixes for byte units" },
2904 { "sexagesimal", OPT_BOOL
, {&use_value_sexagesimal_format
},
2905 "use sexagesimal format HOURS:MM:SS.MICROSECONDS for time units" },
2906 { "pretty", 0, {.func_arg
= opt_pretty
},
2907 "prettify the format of displayed values, make it more human readable" },
2908 { "print_format", OPT_STRING
| HAS_ARG
, {(void*)&print_format
},
2909 "set the output printing format (available formats are: default, compact, csv, flat, ini, json, xml)", "format" },
2910 { "of", OPT_STRING
| HAS_ARG
, {(void*)&print_format
}, "alias for -print_format", "format" },
2911 { "select_streams", OPT_STRING
| HAS_ARG
, {(void*)&stream_specifier
}, "select the specified streams", "stream_specifier" },
2912 { "sections", OPT_EXIT
, {.func_arg
= opt_sections
}, "print sections structure and section information, and exit" },
2913 { "show_data", OPT_BOOL
, {(void*)&do_show_data
}, "show packets data" },
2914 { "show_data_hash", OPT_STRING
| HAS_ARG
, {(void*)&show_data_hash
}, "show packets data hash" },
2915 { "show_error", 0, {(void*)&opt_show_error
}, "show probing error" },
2916 { "show_format", 0, {(void*)&opt_show_format
}, "show format/container info" },
2917 { "show_frames", 0, {(void*)&opt_show_frames
}, "show frames info" },
2918 { "show_format_entry", HAS_ARG
, {.func_arg
= opt_show_format_entry
},
2919 "show a particular entry from the format/container info", "entry" },
2920 { "show_entries", HAS_ARG
, {.func_arg
= opt_show_entries
},
2921 "show a set of specified entries", "entry_list" },
2922 { "show_packets", 0, {(void*)&opt_show_packets
}, "show packets info" },
2923 { "show_programs", 0, {(void*)&opt_show_programs
}, "show programs info" },
2924 { "show_streams", 0, {(void*)&opt_show_streams
}, "show streams info" },
2925 { "show_chapters", 0, {(void*)&opt_show_chapters
}, "show chapters info" },
2926 { "count_frames", OPT_BOOL
, {(void*)&do_count_frames
}, "count the number of frames per stream" },
2927 { "count_packets", OPT_BOOL
, {(void*)&do_count_packets
}, "count the number of packets per stream" },
2928 { "show_program_version", 0, {(void*)&opt_show_program_version
}, "show ffprobe version" },
2929 { "show_library_versions", 0, {(void*)&opt_show_library_versions
}, "show library versions" },
2930 { "show_versions", 0, {(void*)&opt_show_versions
}, "show program and library versions" },
2931 { "show_private_data", OPT_BOOL
, {(void*)&show_private_data
}, "show private data" },
2932 { "private", OPT_BOOL
, {(void*)&show_private_data
}, "same as show_private_data" },
2933 { "bitexact", OPT_BOOL
, {&do_bitexact
}, "force bitexact output" },
2934 { "read_intervals", HAS_ARG
, {.func_arg
= opt_read_intervals
}, "set read intervals", "read_intervals" },
2935 { "default", HAS_ARG
| OPT_AUDIO
| OPT_VIDEO
| OPT_EXPERT
, {.func_arg
= opt_default
}, "generic catch all option", "" },
2936 { "i", HAS_ARG
, {.func_arg
= opt_input_file_i
}, "read specified file", "input_file"},
2940 static inline int check_section_show_entries(int section_id
)
2943 struct section
*section
= §ions
[section_id
];
2944 if (sections
[section_id
].show_all_entries
|| sections
[section_id
].entries_to_show
)
2946 for (id
= section
->children_ids
; *id
!= -1; id
++)
2947 if (check_section_show_entries(*id
))
2952 #define SET_DO_SHOW(id, varname) do { \
2953 if (check_section_show_entries(SECTION_ID_##id)) \
2954 do_show_##varname = 1; \
2957 int main(int argc
, char **argv
)
2960 WriterContext
*wctx
;
2962 char *w_name
= NULL
, *w_args
= NULL
;
2965 av_log_set_flags(AV_LOG_SKIP_REPEATED
);
2966 register_exit(ffprobe_cleanup
);
2968 options
= real_options
;
2969 parse_loglevel(argc
, argv
, options
);
2971 avformat_network_init();
2974 avdevice_register_all();
2977 show_banner(argc
, argv
, options
);
2978 parse_options(NULL
, argc
, argv
, options
, opt_input_file
);
2980 /* mark things to show, based on -show_entries */
2981 SET_DO_SHOW(CHAPTERS
, chapters
);
2982 SET_DO_SHOW(ERROR
, error
);
2983 SET_DO_SHOW(FORMAT
, format
);
2984 SET_DO_SHOW(FRAMES
, frames
);
2985 SET_DO_SHOW(LIBRARY_VERSIONS
, library_versions
);
2986 SET_DO_SHOW(PACKETS
, packets
);
2987 SET_DO_SHOW(PROGRAM_VERSION
, program_version
);
2988 SET_DO_SHOW(PROGRAMS
, programs
);
2989 SET_DO_SHOW(STREAMS
, streams
);
2990 SET_DO_SHOW(STREAM_DISPOSITION
, stream_disposition
);
2991 SET_DO_SHOW(PROGRAM_STREAM_DISPOSITION
, stream_disposition
);
2993 SET_DO_SHOW(CHAPTER_TAGS
, chapter_tags
);
2994 SET_DO_SHOW(FORMAT_TAGS
, format_tags
);
2995 SET_DO_SHOW(FRAME_TAGS
, frame_tags
);
2996 SET_DO_SHOW(PROGRAM_TAGS
, program_tags
);
2997 SET_DO_SHOW(STREAM_TAGS
, stream_tags
);
2999 if (do_bitexact
&& (do_show_program_version
|| do_show_library_versions
)) {
3000 av_log(NULL
, AV_LOG_ERROR
,
3001 "-bitexact and -show_program_version or -show_library_versions "
3002 "options are incompatible\n");
3003 ret
= AVERROR(EINVAL
);
3007 writer_register_all();
3010 print_format
= av_strdup("default");
3011 if (!print_format
) {
3012 ret
= AVERROR(ENOMEM
);
3015 w_name
= av_strtok(print_format
, "=", &buf
);
3018 if (show_data_hash
) {
3019 if ((ret
= av_hash_alloc(&hash
, show_data_hash
)) < 0) {
3020 if (ret
== AVERROR(EINVAL
)) {
3022 av_log(NULL
, AV_LOG_ERROR
,
3023 "Unknown hash algorithm '%s'\nKnown algorithms:",
3025 for (i
= 0; (n
= av_hash_names(i
)); i
++)
3026 av_log(NULL
, AV_LOG_ERROR
, " %s", n
);
3027 av_log(NULL
, AV_LOG_ERROR
, "\n");
3033 w
= writer_get_by_name(w_name
);
3035 av_log(NULL
, AV_LOG_ERROR
, "Unknown output format with name '%s'\n", w_name
);
3036 ret
= AVERROR(EINVAL
);
3040 if ((ret
= writer_open(&wctx
, w
, w_args
,
3041 sections
, FF_ARRAY_ELEMS(sections
))) >= 0) {
3042 if (w
== &xml_writer
)
3043 wctx
->string_validation_utf8_flags
|= AV_UTF8_FLAG_EXCLUDE_XML_INVALID_CONTROL_CODES
;
3045 writer_print_section_header(wctx
, SECTION_ID_ROOT
);
3047 if (do_show_program_version
)
3048 ffprobe_show_program_version(wctx
);
3049 if (do_show_library_versions
)
3050 ffprobe_show_library_versions(wctx
);
3052 if (!input_filename
&&
3053 ((do_show_format
|| do_show_programs
|| do_show_streams
|| do_show_chapters
|| do_show_packets
|| do_show_error
) ||
3054 (!do_show_program_version
&& !do_show_library_versions
))) {
3056 av_log(NULL
, AV_LOG_ERROR
, "You have to specify one input file.\n");
3057 av_log(NULL
, AV_LOG_ERROR
, "Use -h to get full help or, even better, run 'man %s'.\n", program_name
);
3058 ret
= AVERROR(EINVAL
);
3059 } else if (input_filename
) {
3060 ret
= probe_file(wctx
, input_filename
);
3061 if (ret
< 0 && do_show_error
)
3062 show_error(wctx
, ret
);
3065 writer_print_section_footer(wctx
);
3066 writer_close(&wctx
);
3070 av_freep(&print_format
);
3071 av_freep(&read_intervals
);
3072 av_hash_freep(&hash
);
3075 for (i
= 0; i
< FF_ARRAY_ELEMS(sections
); i
++)
3076 av_dict_free(&(sections
[i
].entries_to_show
));
3078 avformat_network_deinit();