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;
69 static int do_show_pixel_formats
= 0;
70 static int do_show_pixel_format_flags
= 0;
71 static int do_show_pixel_format_components
= 0;
73 static int do_show_chapter_tags
= 0;
74 static int do_show_format_tags
= 0;
75 static int do_show_frame_tags
= 0;
76 static int do_show_program_tags
= 0;
77 static int do_show_stream_tags
= 0;
79 static int show_value_unit
= 0;
80 static int use_value_prefix
= 0;
81 static int use_byte_value_binary_prefix
= 0;
82 static int use_value_sexagesimal_format
= 0;
83 static int show_private_data
= 1;
85 static char *print_format
;
86 static char *stream_specifier
;
87 static char *show_data_hash
;
90 int id
; ///< identifier
91 int64_t start
, end
; ///< start, end in second/AV_TIME_BASE units
92 int has_start
, has_end
;
93 int start_is_offset
, end_is_offset
;
97 static ReadInterval
*read_intervals
;
98 static int read_intervals_nb
= 0;
100 /* section structure definition */
102 #define SECTION_MAX_NB_CHILDREN 10
105 int id
; ///< unique id identifying a section
108 #define SECTION_FLAG_IS_WRAPPER 1 ///< the section only contains other sections, but has no data at its own level
109 #define SECTION_FLAG_IS_ARRAY 2 ///< the section contains an array of elements of the same type
110 #define SECTION_FLAG_HAS_VARIABLE_FIELDS 4 ///< the section may contain a variable number of fields with variable keys.
111 /// For these sections the element_name field is mandatory.
113 int children_ids
[SECTION_MAX_NB_CHILDREN
+1]; ///< list of children section IDS, terminated by -1
114 const char *element_name
; ///< name of the contained element, if provided
115 const char *unique_name
; ///< unique section name, in case the name is ambiguous
116 AVDictionary
*entries_to_show
;
117 int show_all_entries
;
121 SECTION_ID_NONE
= -1,
123 SECTION_ID_CHAPTER_TAGS
,
127 SECTION_ID_FORMAT_TAGS
,
130 SECTION_ID_FRAME_TAGS
,
131 SECTION_ID_FRAME_SIDE_DATA_LIST
,
132 SECTION_ID_FRAME_SIDE_DATA
,
133 SECTION_ID_LIBRARY_VERSION
,
134 SECTION_ID_LIBRARY_VERSIONS
,
137 SECTION_ID_PACKETS_AND_FRAMES
,
138 SECTION_ID_PIXEL_FORMAT
,
139 SECTION_ID_PIXEL_FORMAT_FLAGS
,
140 SECTION_ID_PIXEL_FORMAT_COMPONENT
,
141 SECTION_ID_PIXEL_FORMAT_COMPONENTS
,
142 SECTION_ID_PIXEL_FORMATS
,
143 SECTION_ID_PROGRAM_STREAM_DISPOSITION
,
144 SECTION_ID_PROGRAM_STREAM_TAGS
,
146 SECTION_ID_PROGRAM_STREAMS
,
147 SECTION_ID_PROGRAM_STREAM
,
148 SECTION_ID_PROGRAM_TAGS
,
149 SECTION_ID_PROGRAM_VERSION
,
153 SECTION_ID_STREAM_DISPOSITION
,
155 SECTION_ID_STREAM_TAGS
,
159 static struct section sections
[] = {
160 [SECTION_ID_CHAPTERS
] = { SECTION_ID_CHAPTERS
, "chapters", SECTION_FLAG_IS_ARRAY
, { SECTION_ID_CHAPTER
, -1 } },
161 [SECTION_ID_CHAPTER
] = { SECTION_ID_CHAPTER
, "chapter", 0, { SECTION_ID_CHAPTER_TAGS
, -1 } },
162 [SECTION_ID_CHAPTER_TAGS
] = { SECTION_ID_CHAPTER_TAGS
, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS
, { -1 }, .element_name
= "tag", .unique_name
= "chapter_tags" },
163 [SECTION_ID_ERROR
] = { SECTION_ID_ERROR
, "error", 0, { -1 } },
164 [SECTION_ID_FORMAT
] = { SECTION_ID_FORMAT
, "format", 0, { SECTION_ID_FORMAT_TAGS
, -1 } },
165 [SECTION_ID_FORMAT_TAGS
] = { SECTION_ID_FORMAT_TAGS
, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS
, { -1 }, .element_name
= "tag", .unique_name
= "format_tags" },
166 [SECTION_ID_FRAMES
] = { SECTION_ID_FRAMES
, "frames", SECTION_FLAG_IS_ARRAY
, { SECTION_ID_FRAME
, SECTION_ID_SUBTITLE
, -1 } },
167 [SECTION_ID_FRAME
] = { SECTION_ID_FRAME
, "frame", 0, { SECTION_ID_FRAME_TAGS
, SECTION_ID_FRAME_SIDE_DATA_LIST
, -1 } },
168 [SECTION_ID_FRAME_TAGS
] = { SECTION_ID_FRAME_TAGS
, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS
, { -1 }, .element_name
= "tag", .unique_name
= "frame_tags" },
169 [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 } },
170 [SECTION_ID_FRAME_SIDE_DATA
] = { SECTION_ID_FRAME_SIDE_DATA
, "side_data", 0, { -1 } },
171 [SECTION_ID_LIBRARY_VERSIONS
] = { SECTION_ID_LIBRARY_VERSIONS
, "library_versions", SECTION_FLAG_IS_ARRAY
, { SECTION_ID_LIBRARY_VERSION
, -1 } },
172 [SECTION_ID_LIBRARY_VERSION
] = { SECTION_ID_LIBRARY_VERSION
, "library_version", 0, { -1 } },
173 [SECTION_ID_PACKETS
] = { SECTION_ID_PACKETS
, "packets", SECTION_FLAG_IS_ARRAY
, { SECTION_ID_PACKET
, -1} },
174 [SECTION_ID_PACKETS_AND_FRAMES
] = { SECTION_ID_PACKETS_AND_FRAMES
, "packets_and_frames", SECTION_FLAG_IS_ARRAY
, { SECTION_ID_PACKET
, -1} },
175 [SECTION_ID_PACKET
] = { SECTION_ID_PACKET
, "packet", 0, { -1 } },
176 [SECTION_ID_PIXEL_FORMATS
] = { SECTION_ID_PIXEL_FORMATS
, "pixel_formats", SECTION_FLAG_IS_ARRAY
, { SECTION_ID_PIXEL_FORMAT
, -1 } },
177 [SECTION_ID_PIXEL_FORMAT
] = { SECTION_ID_PIXEL_FORMAT
, "pixel_format", 0, { SECTION_ID_PIXEL_FORMAT_FLAGS
, SECTION_ID_PIXEL_FORMAT_COMPONENTS
, -1 } },
178 [SECTION_ID_PIXEL_FORMAT_FLAGS
] = { SECTION_ID_PIXEL_FORMAT_FLAGS
, "flags", 0, { -1 }, .unique_name
= "pixel_format_flags" },
179 [SECTION_ID_PIXEL_FORMAT_COMPONENTS
] = { SECTION_ID_PIXEL_FORMAT_COMPONENTS
, "components", SECTION_FLAG_IS_ARRAY
, {SECTION_ID_PIXEL_FORMAT_COMPONENT
, -1 }, .unique_name
= "pixel_format_components" },
180 [SECTION_ID_PIXEL_FORMAT_COMPONENT
] = { SECTION_ID_PIXEL_FORMAT_COMPONENT
, "component", 0, { -1 } },
181 [SECTION_ID_PROGRAM_STREAM_DISPOSITION
] = { SECTION_ID_PROGRAM_STREAM_DISPOSITION
, "disposition", 0, { -1 }, .unique_name
= "program_stream_disposition" },
182 [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" },
183 [SECTION_ID_PROGRAM
] = { SECTION_ID_PROGRAM
, "program", 0, { SECTION_ID_PROGRAM_TAGS
, SECTION_ID_PROGRAM_STREAMS
, -1 } },
184 [SECTION_ID_PROGRAM_STREAMS
] = { SECTION_ID_PROGRAM_STREAMS
, "streams", SECTION_FLAG_IS_ARRAY
, { SECTION_ID_PROGRAM_STREAM
, -1 }, .unique_name
= "program_streams" },
185 [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" },
186 [SECTION_ID_PROGRAM_TAGS
] = { SECTION_ID_PROGRAM_TAGS
, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS
, { -1 }, .element_name
= "tag", .unique_name
= "program_tags" },
187 [SECTION_ID_PROGRAM_VERSION
] = { SECTION_ID_PROGRAM_VERSION
, "program_version", 0, { -1 } },
188 [SECTION_ID_PROGRAMS
] = { SECTION_ID_PROGRAMS
, "programs", SECTION_FLAG_IS_ARRAY
, { SECTION_ID_PROGRAM
, -1 } },
189 [SECTION_ID_ROOT
] = { SECTION_ID_ROOT
, "root", SECTION_FLAG_IS_WRAPPER
,
190 { SECTION_ID_CHAPTERS
, SECTION_ID_FORMAT
, SECTION_ID_FRAMES
, SECTION_ID_PROGRAMS
, SECTION_ID_STREAMS
,
191 SECTION_ID_PACKETS
, SECTION_ID_ERROR
, SECTION_ID_PROGRAM_VERSION
, SECTION_ID_LIBRARY_VERSIONS
,
192 SECTION_ID_PIXEL_FORMATS
, -1} },
193 [SECTION_ID_STREAMS
] = { SECTION_ID_STREAMS
, "streams", SECTION_FLAG_IS_ARRAY
, { SECTION_ID_STREAM
, -1 } },
194 [SECTION_ID_STREAM
] = { SECTION_ID_STREAM
, "stream", 0, { SECTION_ID_STREAM_DISPOSITION
, SECTION_ID_STREAM_TAGS
, -1 } },
195 [SECTION_ID_STREAM_DISPOSITION
] = { SECTION_ID_STREAM_DISPOSITION
, "disposition", 0, { -1 }, .unique_name
= "stream_disposition" },
196 [SECTION_ID_STREAM_TAGS
] = { SECTION_ID_STREAM_TAGS
, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS
, { -1 }, .element_name
= "tag", .unique_name
= "stream_tags" },
197 [SECTION_ID_SUBTITLE
] = { SECTION_ID_SUBTITLE
, "subtitle", 0, { -1 } },
200 static const OptionDef
*options
;
202 /* FFprobe context */
203 static const char *input_filename
;
204 static AVInputFormat
*iformat
= NULL
;
206 static struct AVHashContext
*hash
;
208 static const char *const binary_unit_prefixes
[] = { "", "Ki", "Mi", "Gi", "Ti", "Pi" };
209 static const char *const decimal_unit_prefixes
[] = { "", "K" , "M" , "G" , "T" , "P" };
211 static const char unit_second_str
[] = "s" ;
212 static const char unit_hertz_str
[] = "Hz" ;
213 static const char unit_byte_str
[] = "byte" ;
214 static const char unit_bit_per_second_str
[] = "bit/s";
216 static int nb_streams
;
217 static uint64_t *nb_streams_packets
;
218 static uint64_t *nb_streams_frames
;
219 static int *selected_streams
;
221 static void ffprobe_cleanup(int ret
)
224 for (i
= 0; i
< FF_ARRAY_ELEMS(sections
); i
++)
225 av_dict_free(&(sections
[i
].entries_to_show
));
229 union { double d
; long long int i
; } val
;
233 static char *value_string(char *buf
, int buf_size
, struct unit_value uv
)
239 if (uv
.unit
== unit_second_str
) {
243 vald
= vali
= uv
.val
.i
;
246 if (uv
.unit
== unit_second_str
&& use_value_sexagesimal_format
) {
250 mins
= (int)secs
/ 60;
251 secs
= secs
- mins
* 60;
254 snprintf(buf
, buf_size
, "%d:%02d:%09.6f", hours
, mins
, secs
);
256 const char *prefix_string
= "";
258 if (use_value_prefix
&& vald
> 1) {
261 if (uv
.unit
== unit_byte_str
&& use_byte_value_binary_prefix
) {
262 index
= (long long int) (log2(vald
)) / 10;
263 index
= av_clip(index
, 0, FF_ARRAY_ELEMS(binary_unit_prefixes
) - 1);
264 vald
/= exp2(index
* 10);
265 prefix_string
= binary_unit_prefixes
[index
];
267 index
= (long long int) (log10(vald
)) / 3;
268 index
= av_clip(index
, 0, FF_ARRAY_ELEMS(decimal_unit_prefixes
) - 1);
269 vald
/= pow(10, index
* 3);
270 prefix_string
= decimal_unit_prefixes
[index
];
275 if (show_float
|| (use_value_prefix
&& vald
!= (long long int)vald
))
276 snprintf(buf
, buf_size
, "%f", vald
);
278 snprintf(buf
, buf_size
, "%lld", vali
);
279 av_strlcatf(buf
, buf_size
, "%s%s%s", *prefix_string
|| show_value_unit
? " " : "",
280 prefix_string
, show_value_unit
? uv
.unit
: "");
288 typedef struct WriterContext WriterContext
;
290 #define WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS 1
291 #define WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER 2
294 WRITER_STRING_VALIDATION_FAIL
,
295 WRITER_STRING_VALIDATION_REPLACE
,
296 WRITER_STRING_VALIDATION_IGNORE
,
297 WRITER_STRING_VALIDATION_NB
300 typedef struct Writer
{
301 const AVClass
*priv_class
; ///< private class of the writer, if any
302 int priv_size
; ///< private size for the writer context
305 int (*init
) (WriterContext
*wctx
);
306 void (*uninit
)(WriterContext
*wctx
);
308 void (*print_section_header
)(WriterContext
*wctx
);
309 void (*print_section_footer
)(WriterContext
*wctx
);
310 void (*print_integer
) (WriterContext
*wctx
, const char *, long long int);
311 void (*print_rational
) (WriterContext
*wctx
, AVRational
*q
, char *sep
);
312 void (*print_string
) (WriterContext
*wctx
, const char *, const char *);
313 int flags
; ///< a combination or WRITER_FLAG_*
316 #define SECTION_MAX_NB_LEVELS 10
318 struct WriterContext
{
319 const AVClass
*class; ///< class of the writer
320 const Writer
*writer
; ///< the Writer of which this is an instance
321 char *name
; ///< name of this writer instance
322 void *priv
; ///< private data for use by the filter
324 const struct section
*sections
; ///< array containing all sections
325 int nb_sections
; ///< number of sections
327 int level
; ///< current level, starting from 0
329 /** number of the item printed in the given section, starting from 0 */
330 unsigned int nb_item
[SECTION_MAX_NB_LEVELS
];
332 /** section per each level */
333 const struct section
*section
[SECTION_MAX_NB_LEVELS
];
334 AVBPrint section_pbuf
[SECTION_MAX_NB_LEVELS
]; ///< generic print buffer dedicated to each section,
335 /// used by various writers
337 unsigned int nb_section_packet
; ///< number of the packet section in case we are in "packets_and_frames" section
338 unsigned int nb_section_frame
; ///< number of the frame section in case we are in "packets_and_frames" section
339 unsigned int nb_section_packet_frame
; ///< nb_section_packet or nb_section_frame according if is_packets_and_frames
341 StringValidation string_validation
;
342 char *string_validation_replacement
;
343 unsigned int string_validation_utf8_flags
;
346 static const char *writer_get_name(void *p
)
348 WriterContext
*wctx
= p
;
349 return wctx
->writer
->name
;
352 #define OFFSET(x) offsetof(WriterContext, x)
354 static const AVOption writer_options
[] = {
355 { "string_validation", "set string validation mode",
356 OFFSET(string_validation
), AV_OPT_TYPE_INT
, {.i64
=WRITER_STRING_VALIDATION_REPLACE
}, 0, WRITER_STRING_VALIDATION_NB
-1, .unit
= "sv" },
357 { "sv", "set string validation mode",
358 OFFSET(string_validation
), AV_OPT_TYPE_INT
, {.i64
=WRITER_STRING_VALIDATION_REPLACE
}, 0, WRITER_STRING_VALIDATION_NB
-1, .unit
= "sv" },
359 { "ignore", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
= WRITER_STRING_VALIDATION_IGNORE
}, .unit
= "sv" },
360 { "replace", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
= WRITER_STRING_VALIDATION_REPLACE
}, .unit
= "sv" },
361 { "fail", NULL
, 0, AV_OPT_TYPE_CONST
, {.i64
= WRITER_STRING_VALIDATION_FAIL
}, .unit
= "sv" },
362 { "string_validation_replacement", "set string validation replacement string", OFFSET(string_validation_replacement
), AV_OPT_TYPE_STRING
, {.str
=""}},
363 { "svr", "set string validation replacement string", OFFSET(string_validation_replacement
), AV_OPT_TYPE_STRING
, {.str
="\xEF\xBF\xBD"}},
367 static void *writer_child_next(void *obj
, void *prev
)
369 WriterContext
*ctx
= obj
;
370 if (!prev
&& ctx
->writer
&& ctx
->writer
->priv_class
&& ctx
->priv
)
375 static const AVClass writer_class
= {
376 .class_name
= "Writer",
377 .item_name
= writer_get_name
,
378 .option
= writer_options
,
379 .version
= LIBAVUTIL_VERSION_INT
,
380 .child_next
= writer_child_next
,
383 static void writer_close(WriterContext
**wctx
)
390 if ((*wctx
)->writer
->uninit
)
391 (*wctx
)->writer
->uninit(*wctx
);
392 for (i
= 0; i
< SECTION_MAX_NB_LEVELS
; i
++)
393 av_bprint_finalize(&(*wctx
)->section_pbuf
[i
], NULL
);
394 if ((*wctx
)->writer
->priv_class
)
395 av_opt_free((*wctx
)->priv
);
396 av_freep(&((*wctx
)->priv
));
401 static void bprint_bytes(AVBPrint
*bp
, const uint8_t *ubuf
, size_t ubuf_size
)
404 av_bprintf(bp
, "0X");
405 for (i
= 0; i
< ubuf_size
; i
++)
406 av_bprintf(bp
, "%02X", ubuf
[i
]);
410 static int writer_open(WriterContext
**wctx
, const Writer
*writer
, const char *args
,
411 const struct section
*sections
, int nb_sections
)
415 if (!(*wctx
= av_mallocz(sizeof(WriterContext
)))) {
416 ret
= AVERROR(ENOMEM
);
420 if (!((*wctx
)->priv
= av_mallocz(writer
->priv_size
))) {
421 ret
= AVERROR(ENOMEM
);
425 (*wctx
)->class = &writer_class
;
426 (*wctx
)->writer
= writer
;
428 (*wctx
)->sections
= sections
;
429 (*wctx
)->nb_sections
= nb_sections
;
431 av_opt_set_defaults(*wctx
);
433 if (writer
->priv_class
) {
434 void *priv_ctx
= (*wctx
)->priv
;
435 *((const AVClass
**)priv_ctx
) = writer
->priv_class
;
436 av_opt_set_defaults(priv_ctx
);
439 /* convert options to dictionary */
441 AVDictionary
*opts
= NULL
;
442 AVDictionaryEntry
*opt
= NULL
;
444 if ((ret
= av_dict_parse_string(&opts
, args
, "=", ":", 0)) < 0) {
445 av_log(*wctx
, AV_LOG_ERROR
, "Failed to parse option string '%s' provided to writer context\n", args
);
450 while ((opt
= av_dict_get(opts
, "", opt
, AV_DICT_IGNORE_SUFFIX
))) {
451 if ((ret
= av_opt_set(*wctx
, opt
->key
, opt
->value
, AV_OPT_SEARCH_CHILDREN
)) < 0) {
452 av_log(*wctx
, AV_LOG_ERROR
, "Failed to set option '%s' with value '%s' provided to writer context\n",
453 opt
->key
, opt
->value
);
462 /* validate replace string */
464 const uint8_t *p
= (*wctx
)->string_validation_replacement
;
465 const uint8_t *endp
= p
+ strlen(p
);
467 const uint8_t *p0
= p
;
469 ret
= av_utf8_decode(&code
, &p
, endp
, (*wctx
)->string_validation_utf8_flags
);
472 av_bprint_init(&bp
, 0, AV_BPRINT_SIZE_AUTOMATIC
);
473 bprint_bytes(&bp
, p0
, p
-p0
),
474 av_log(wctx
, AV_LOG_ERROR
,
475 "Invalid UTF8 sequence %s found in string validation replace '%s'\n",
476 bp
.str
, (*wctx
)->string_validation_replacement
);
482 for (i
= 0; i
< SECTION_MAX_NB_LEVELS
; i
++)
483 av_bprint_init(&(*wctx
)->section_pbuf
[i
], 1, AV_BPRINT_SIZE_UNLIMITED
);
485 if ((*wctx
)->writer
->init
)
486 ret
= (*wctx
)->writer
->init(*wctx
);
497 static inline void writer_print_section_header(WriterContext
*wctx
,
500 int parent_section_id
;
502 av_assert0(wctx
->level
< SECTION_MAX_NB_LEVELS
);
503 parent_section_id
= wctx
->level
?
504 (wctx
->section
[wctx
->level
-1])->id
: SECTION_ID_NONE
;
506 wctx
->nb_item
[wctx
->level
] = 0;
507 wctx
->section
[wctx
->level
] = &wctx
->sections
[section_id
];
509 if (section_id
== SECTION_ID_PACKETS_AND_FRAMES
) {
510 wctx
->nb_section_packet
= wctx
->nb_section_frame
=
511 wctx
->nb_section_packet_frame
= 0;
512 } else if (parent_section_id
== SECTION_ID_PACKETS_AND_FRAMES
) {
513 wctx
->nb_section_packet_frame
= section_id
== SECTION_ID_PACKET
?
514 wctx
->nb_section_packet
: wctx
->nb_section_frame
;
517 if (wctx
->writer
->print_section_header
)
518 wctx
->writer
->print_section_header(wctx
);
521 static inline void writer_print_section_footer(WriterContext
*wctx
)
523 int section_id
= wctx
->section
[wctx
->level
]->id
;
524 int parent_section_id
= wctx
->level
?
525 wctx
->section
[wctx
->level
-1]->id
: SECTION_ID_NONE
;
527 if (parent_section_id
!= SECTION_ID_NONE
)
528 wctx
->nb_item
[wctx
->level
-1]++;
529 if (parent_section_id
== SECTION_ID_PACKETS_AND_FRAMES
) {
530 if (section_id
== SECTION_ID_PACKET
) wctx
->nb_section_packet
++;
531 else wctx
->nb_section_frame
++;
533 if (wctx
->writer
->print_section_footer
)
534 wctx
->writer
->print_section_footer(wctx
);
538 static inline void writer_print_integer(WriterContext
*wctx
,
539 const char *key
, long long int val
)
541 const struct section
*section
= wctx
->section
[wctx
->level
];
543 if (section
->show_all_entries
|| av_dict_get(section
->entries_to_show
, key
, NULL
, 0)) {
544 wctx
->writer
->print_integer(wctx
, key
, val
);
545 wctx
->nb_item
[wctx
->level
]++;
549 static inline int validate_string(WriterContext
*wctx
, char **dstp
, const char *src
)
551 const uint8_t *p
, *endp
;
553 int invalid_chars_nb
= 0, ret
= 0;
555 av_bprint_init(&dstbuf
, 0, AV_BPRINT_SIZE_UNLIMITED
);
557 endp
= src
+ strlen(src
);
558 for (p
= (uint8_t *)src
; *p
;) {
561 const uint8_t *p0
= p
;
563 if (av_utf8_decode(&code
, &p
, endp
, wctx
->string_validation_utf8_flags
) < 0) {
565 av_bprint_init(&bp
, 0, AV_BPRINT_SIZE_AUTOMATIC
);
566 bprint_bytes(&bp
, p0
, p
-p0
);
567 av_log(wctx
, AV_LOG_DEBUG
,
568 "Invalid UTF-8 sequence %s found in string '%s'\n", bp
.str
, src
);
575 switch (wctx
->string_validation
) {
576 case WRITER_STRING_VALIDATION_FAIL
:
577 av_log(wctx
, AV_LOG_ERROR
,
578 "Invalid UTF-8 sequence found in string '%s'\n", src
);
579 ret
= AVERROR_INVALIDDATA
;
583 case WRITER_STRING_VALIDATION_REPLACE
:
584 av_bprintf(&dstbuf
, "%s", wctx
->string_validation_replacement
);
589 if (!invalid
|| wctx
->string_validation
== WRITER_STRING_VALIDATION_IGNORE
)
590 av_bprint_append_data(&dstbuf
, p0
, p
-p0
);
593 if (invalid_chars_nb
&& wctx
->string_validation
== WRITER_STRING_VALIDATION_REPLACE
) {
594 av_log(wctx
, AV_LOG_WARNING
,
595 "%d invalid UTF-8 sequence(s) found in string '%s', replaced with '%s'\n",
596 invalid_chars_nb
, src
, wctx
->string_validation_replacement
);
600 av_bprint_finalize(&dstbuf
, dstp
);
604 #define PRINT_STRING_OPT 1
605 #define PRINT_STRING_VALIDATE 2
607 static inline int writer_print_string(WriterContext
*wctx
,
608 const char *key
, const char *val
, int flags
)
610 const struct section
*section
= wctx
->section
[wctx
->level
];
613 if ((flags
& PRINT_STRING_OPT
)
614 && !(wctx
->writer
->flags
& WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS
))
617 if (section
->show_all_entries
|| av_dict_get(section
->entries_to_show
, key
, NULL
, 0)) {
618 if (flags
& PRINT_STRING_VALIDATE
) {
619 char *key1
= NULL
, *val1
= NULL
;
620 ret
= validate_string(wctx
, &key1
, key
);
621 if (ret
< 0) goto end
;
622 ret
= validate_string(wctx
, &val1
, val
);
623 if (ret
< 0) goto end
;
624 wctx
->writer
->print_string(wctx
, key1
, val1
);
627 av_log(wctx
, AV_LOG_ERROR
,
628 "Invalid key=value string combination %s=%s in section %s\n",
629 key
, val
, section
->unique_name
);
634 wctx
->writer
->print_string(wctx
, key
, val
);
637 wctx
->nb_item
[wctx
->level
]++;
643 static inline void writer_print_rational(WriterContext
*wctx
,
644 const char *key
, AVRational q
, char sep
)
647 av_bprint_init(&buf
, 0, AV_BPRINT_SIZE_AUTOMATIC
);
648 av_bprintf(&buf
, "%d%c%d", q
.num
, sep
, q
.den
);
649 writer_print_string(wctx
, key
, buf
.str
, 0);
652 static void writer_print_time(WriterContext
*wctx
, const char *key
,
653 int64_t ts
, const AVRational
*time_base
, 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 double d
= ts
* av_q2d(*time_base
);
661 struct unit_value uv
;
663 uv
.unit
= unit_second_str
;
664 value_string(buf
, sizeof(buf
), uv
);
665 writer_print_string(wctx
, key
, buf
, 0);
669 static void writer_print_ts(WriterContext
*wctx
, const char *key
, int64_t ts
, int is_duration
)
671 if ((!is_duration
&& ts
== AV_NOPTS_VALUE
) || (is_duration
&& ts
== 0)) {
672 writer_print_string(wctx
, key
, "N/A", PRINT_STRING_OPT
);
674 writer_print_integer(wctx
, key
, ts
);
678 static void writer_print_data(WriterContext
*wctx
, const char *name
,
679 uint8_t *data
, int size
)
682 int offset
= 0, l
, i
;
684 av_bprint_init(&bp
, 0, AV_BPRINT_SIZE_UNLIMITED
);
685 av_bprintf(&bp
, "\n");
687 av_bprintf(&bp
, "%08x: ", offset
);
689 for (i
= 0; i
< l
; i
++) {
690 av_bprintf(&bp
, "%02x", data
[i
]);
692 av_bprintf(&bp
, " ");
694 av_bprint_chars(&bp
, ' ', 41 - 2 * i
- i
/ 2);
695 for (i
= 0; i
< l
; i
++)
696 av_bprint_chars(&bp
, data
[i
] - 32U < 95 ? data
[i
] : '.', 1);
697 av_bprintf(&bp
, "\n");
702 writer_print_string(wctx
, name
, bp
.str
, 0);
703 av_bprint_finalize(&bp
, NULL
);
706 static void writer_print_data_hash(WriterContext
*wctx
, const char *name
,
707 uint8_t *data
, int size
)
709 char *p
, buf
[AV_HASH_MAX_SIZE
* 2 + 64] = { 0 };
714 av_hash_update(hash
, data
, size
);
715 snprintf(buf
, sizeof(buf
), "%s:", av_hash_get_name(hash
));
716 p
= buf
+ strlen(buf
);
717 av_hash_final_hex(hash
, p
, buf
+ sizeof(buf
) - p
);
718 writer_print_string(wctx
, name
, buf
, 0);
721 #define MAX_REGISTERED_WRITERS_NB 64
723 static const Writer
*registered_writers
[MAX_REGISTERED_WRITERS_NB
+ 1];
725 static int writer_register(const Writer
*writer
)
727 static int next_registered_writer_idx
= 0;
729 if (next_registered_writer_idx
== MAX_REGISTERED_WRITERS_NB
)
730 return AVERROR(ENOMEM
);
732 registered_writers
[next_registered_writer_idx
++] = writer
;
736 static const Writer
*writer_get_by_name(const char *name
)
740 for (i
= 0; registered_writers
[i
]; i
++)
741 if (!strcmp(registered_writers
[i
]->name
, name
))
742 return registered_writers
[i
];
750 #define DEFINE_WRITER_CLASS(name) \
751 static const char *name##_get_name(void *ctx) \
755 static const AVClass name##_class = { \
756 .class_name = #name, \
757 .item_name = name##_get_name, \
758 .option = name##_options \
763 typedef struct DefaultContext
{
764 const AVClass
*class;
766 int noprint_wrappers
;
767 int nested_section
[SECTION_MAX_NB_LEVELS
];
771 #define OFFSET(x) offsetof(DefaultContext, x)
773 static const AVOption default_options
[] = {
774 { "noprint_wrappers", "do not print headers and footers", OFFSET(noprint_wrappers
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1 },
775 { "nw", "do not print headers and footers", OFFSET(noprint_wrappers
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1 },
776 { "nokey", "force no key printing", OFFSET(nokey
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1 },
777 { "nk", "force no key printing", OFFSET(nokey
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1 },
781 DEFINE_WRITER_CLASS(default);
783 /* lame uppercasing routine, assumes the string is lower case ASCII */
784 static inline char *upcase_string(char *dst
, size_t dst_size
, const char *src
)
787 for (i
= 0; src
[i
] && i
< dst_size
-1; i
++)
788 dst
[i
] = av_toupper(src
[i
]);
793 static void default_print_section_header(WriterContext
*wctx
)
795 DefaultContext
*def
= wctx
->priv
;
797 const struct section
*section
= wctx
->section
[wctx
->level
];
798 const struct section
*parent_section
= wctx
->level
?
799 wctx
->section
[wctx
->level
-1] : NULL
;
801 av_bprint_clear(&wctx
->section_pbuf
[wctx
->level
]);
802 if (parent_section
&&
803 !(parent_section
->flags
& (SECTION_FLAG_IS_WRAPPER
|SECTION_FLAG_IS_ARRAY
))) {
804 def
->nested_section
[wctx
->level
] = 1;
805 av_bprintf(&wctx
->section_pbuf
[wctx
->level
], "%s%s:",
806 wctx
->section_pbuf
[wctx
->level
-1].str
,
807 upcase_string(buf
, sizeof(buf
),
808 av_x_if_null(section
->element_name
, section
->name
)));
811 if (def
->noprint_wrappers
|| def
->nested_section
[wctx
->level
])
814 if (!(section
->flags
& (SECTION_FLAG_IS_WRAPPER
|SECTION_FLAG_IS_ARRAY
)))
815 printf("[%s]\n", upcase_string(buf
, sizeof(buf
), section
->name
));
818 static void default_print_section_footer(WriterContext
*wctx
)
820 DefaultContext
*def
= wctx
->priv
;
821 const struct section
*section
= wctx
->section
[wctx
->level
];
824 if (def
->noprint_wrappers
|| def
->nested_section
[wctx
->level
])
827 if (!(section
->flags
& (SECTION_FLAG_IS_WRAPPER
|SECTION_FLAG_IS_ARRAY
)))
828 printf("[/%s]\n", upcase_string(buf
, sizeof(buf
), section
->name
));
831 static void default_print_str(WriterContext
*wctx
, const char *key
, const char *value
)
833 DefaultContext
*def
= wctx
->priv
;
836 printf("%s%s=", wctx
->section_pbuf
[wctx
->level
].str
, key
);
837 printf("%s\n", value
);
840 static void default_print_int(WriterContext
*wctx
, const char *key
, long long int value
)
842 DefaultContext
*def
= wctx
->priv
;
845 printf("%s%s=", wctx
->section_pbuf
[wctx
->level
].str
, key
);
846 printf("%lld\n", value
);
849 static const Writer default_writer
= {
851 .priv_size
= sizeof(DefaultContext
),
852 .print_section_header
= default_print_section_header
,
853 .print_section_footer
= default_print_section_footer
,
854 .print_integer
= default_print_int
,
855 .print_string
= default_print_str
,
856 .flags
= WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS
,
857 .priv_class
= &default_class
,
863 * Apply C-language-like string escaping.
865 static const char *c_escape_str(AVBPrint
*dst
, const char *src
, const char sep
, void *log_ctx
)
869 for (p
= src
; *p
; p
++) {
871 case '\b': av_bprintf(dst
, "%s", "\\b"); break;
872 case '\f': av_bprintf(dst
, "%s", "\\f"); break;
873 case '\n': av_bprintf(dst
, "%s", "\\n"); break;
874 case '\r': av_bprintf(dst
, "%s", "\\r"); break;
875 case '\\': av_bprintf(dst
, "%s", "\\\\"); break;
878 av_bprint_chars(dst
, '\\', 1);
879 av_bprint_chars(dst
, *p
, 1);
886 * Quote fields containing special characters, check RFC4180.
888 static const char *csv_escape_str(AVBPrint
*dst
, const char *src
, const char sep
, void *log_ctx
)
890 char meta_chars
[] = { sep
, '"', '\n', '\r', '\0' };
891 int needs_quoting
= !!src
[strcspn(src
, meta_chars
)];
894 av_bprint_chars(dst
, '"', 1);
896 for (; *src
; src
++) {
898 av_bprint_chars(dst
, '"', 1);
899 av_bprint_chars(dst
, *src
, 1);
902 av_bprint_chars(dst
, '"', 1);
906 static const char *none_escape_str(AVBPrint
*dst
, const char *src
, const char sep
, void *log_ctx
)
911 typedef struct CompactContext
{
912 const AVClass
*class;
917 char *escape_mode_str
;
918 const char * (*escape_str
)(AVBPrint
*dst
, const char *src
, const char sep
, void *log_ctx
);
919 int nested_section
[SECTION_MAX_NB_LEVELS
];
920 int has_nested_elems
[SECTION_MAX_NB_LEVELS
];
921 int terminate_line
[SECTION_MAX_NB_LEVELS
];
925 #define OFFSET(x) offsetof(CompactContext, x)
927 static const AVOption compact_options
[]= {
928 {"item_sep", "set item separator", OFFSET(item_sep_str
), AV_OPT_TYPE_STRING
, {.str
="|"}, CHAR_MIN
, CHAR_MAX
},
929 {"s", "set item separator", OFFSET(item_sep_str
), AV_OPT_TYPE_STRING
, {.str
="|"}, CHAR_MIN
, CHAR_MAX
},
930 {"nokey", "force no key printing", OFFSET(nokey
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1 },
931 {"nk", "force no key printing", OFFSET(nokey
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1 },
932 {"escape", "set escape mode", OFFSET(escape_mode_str
), AV_OPT_TYPE_STRING
, {.str
="c"}, CHAR_MIN
, CHAR_MAX
},
933 {"e", "set escape mode", OFFSET(escape_mode_str
), AV_OPT_TYPE_STRING
, {.str
="c"}, CHAR_MIN
, CHAR_MAX
},
934 {"print_section", "print section name", OFFSET(print_section
), AV_OPT_TYPE_INT
, {.i64
=1}, 0, 1 },
935 {"p", "print section name", OFFSET(print_section
), AV_OPT_TYPE_INT
, {.i64
=1}, 0, 1 },
939 DEFINE_WRITER_CLASS(compact
);
941 static av_cold
int compact_init(WriterContext
*wctx
)
943 CompactContext
*compact
= wctx
->priv
;
945 if (strlen(compact
->item_sep_str
) != 1) {
946 av_log(wctx
, AV_LOG_ERROR
, "Item separator '%s' specified, but must contain a single character\n",
947 compact
->item_sep_str
);
948 return AVERROR(EINVAL
);
950 compact
->item_sep
= compact
->item_sep_str
[0];
952 if (!strcmp(compact
->escape_mode_str
, "none")) compact
->escape_str
= none_escape_str
;
953 else if (!strcmp(compact
->escape_mode_str
, "c" )) compact
->escape_str
= c_escape_str
;
954 else if (!strcmp(compact
->escape_mode_str
, "csv" )) compact
->escape_str
= csv_escape_str
;
956 av_log(wctx
, AV_LOG_ERROR
, "Unknown escape mode '%s'\n", compact
->escape_mode_str
);
957 return AVERROR(EINVAL
);
963 static void compact_print_section_header(WriterContext
*wctx
)
965 CompactContext
*compact
= wctx
->priv
;
966 const struct section
*section
= wctx
->section
[wctx
->level
];
967 const struct section
*parent_section
= wctx
->level
?
968 wctx
->section
[wctx
->level
-1] : NULL
;
969 compact
->terminate_line
[wctx
->level
] = 1;
970 compact
->has_nested_elems
[wctx
->level
] = 0;
972 av_bprint_clear(&wctx
->section_pbuf
[wctx
->level
]);
973 if (!(section
->flags
& SECTION_FLAG_IS_ARRAY
) && parent_section
&&
974 !(parent_section
->flags
& (SECTION_FLAG_IS_WRAPPER
|SECTION_FLAG_IS_ARRAY
))) {
975 compact
->nested_section
[wctx
->level
] = 1;
976 compact
->has_nested_elems
[wctx
->level
-1] = 1;
977 av_bprintf(&wctx
->section_pbuf
[wctx
->level
], "%s%s:",
978 wctx
->section_pbuf
[wctx
->level
-1].str
,
979 (char *)av_x_if_null(section
->element_name
, section
->name
));
980 wctx
->nb_item
[wctx
->level
] = wctx
->nb_item
[wctx
->level
-1];
982 if (parent_section
&& compact
->has_nested_elems
[wctx
->level
-1] &&
983 (section
->flags
& SECTION_FLAG_IS_ARRAY
)) {
984 compact
->terminate_line
[wctx
->level
-1] = 0;
987 if (compact
->print_section
&&
988 !(section
->flags
& (SECTION_FLAG_IS_WRAPPER
|SECTION_FLAG_IS_ARRAY
)))
989 printf("%s%c", section
->name
, compact
->item_sep
);
993 static void compact_print_section_footer(WriterContext
*wctx
)
995 CompactContext
*compact
= wctx
->priv
;
997 if (!compact
->nested_section
[wctx
->level
] &&
998 compact
->terminate_line
[wctx
->level
] &&
999 !(wctx
->section
[wctx
->level
]->flags
& (SECTION_FLAG_IS_WRAPPER
|SECTION_FLAG_IS_ARRAY
)))
1003 static void compact_print_str(WriterContext
*wctx
, const char *key
, const char *value
)
1005 CompactContext
*compact
= wctx
->priv
;
1008 if (wctx
->nb_item
[wctx
->level
]) printf("%c", compact
->item_sep
);
1009 if (!compact
->nokey
)
1010 printf("%s%s=", wctx
->section_pbuf
[wctx
->level
].str
, key
);
1011 av_bprint_init(&buf
, 1, AV_BPRINT_SIZE_UNLIMITED
);
1012 printf("%s", compact
->escape_str(&buf
, value
, compact
->item_sep
, wctx
));
1013 av_bprint_finalize(&buf
, NULL
);
1016 static void compact_print_int(WriterContext
*wctx
, const char *key
, long long int value
)
1018 CompactContext
*compact
= wctx
->priv
;
1020 if (wctx
->nb_item
[wctx
->level
]) printf("%c", compact
->item_sep
);
1021 if (!compact
->nokey
)
1022 printf("%s%s=", wctx
->section_pbuf
[wctx
->level
].str
, key
);
1023 printf("%lld", value
);
1026 static const Writer compact_writer
= {
1028 .priv_size
= sizeof(CompactContext
),
1029 .init
= compact_init
,
1030 .print_section_header
= compact_print_section_header
,
1031 .print_section_footer
= compact_print_section_footer
,
1032 .print_integer
= compact_print_int
,
1033 .print_string
= compact_print_str
,
1034 .flags
= WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS
,
1035 .priv_class
= &compact_class
,
1041 #define OFFSET(x) offsetof(CompactContext, x)
1043 static const AVOption csv_options
[] = {
1044 {"item_sep", "set item separator", OFFSET(item_sep_str
), AV_OPT_TYPE_STRING
, {.str
=","}, CHAR_MIN
, CHAR_MAX
},
1045 {"s", "set item separator", OFFSET(item_sep_str
), AV_OPT_TYPE_STRING
, {.str
=","}, CHAR_MIN
, CHAR_MAX
},
1046 {"nokey", "force no key printing", OFFSET(nokey
), AV_OPT_TYPE_INT
, {.i64
=1}, 0, 1 },
1047 {"nk", "force no key printing", OFFSET(nokey
), AV_OPT_TYPE_INT
, {.i64
=1}, 0, 1 },
1048 {"escape", "set escape mode", OFFSET(escape_mode_str
), AV_OPT_TYPE_STRING
, {.str
="csv"}, CHAR_MIN
, CHAR_MAX
},
1049 {"e", "set escape mode", OFFSET(escape_mode_str
), AV_OPT_TYPE_STRING
, {.str
="csv"}, CHAR_MIN
, CHAR_MAX
},
1050 {"print_section", "print section name", OFFSET(print_section
), AV_OPT_TYPE_INT
, {.i64
=1}, 0, 1 },
1051 {"p", "print section name", OFFSET(print_section
), AV_OPT_TYPE_INT
, {.i64
=1}, 0, 1 },
1055 DEFINE_WRITER_CLASS(csv
);
1057 static const Writer csv_writer
= {
1059 .priv_size
= sizeof(CompactContext
),
1060 .init
= compact_init
,
1061 .print_section_header
= compact_print_section_header
,
1062 .print_section_footer
= compact_print_section_footer
,
1063 .print_integer
= compact_print_int
,
1064 .print_string
= compact_print_str
,
1065 .flags
= WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS
,
1066 .priv_class
= &csv_class
,
1071 typedef struct FlatContext
{
1072 const AVClass
*class;
1073 const char *sep_str
;
1079 #define OFFSET(x) offsetof(FlatContext, x)
1081 static const AVOption flat_options
[]= {
1082 {"sep_char", "set separator", OFFSET(sep_str
), AV_OPT_TYPE_STRING
, {.str
="."}, CHAR_MIN
, CHAR_MAX
},
1083 {"s", "set separator", OFFSET(sep_str
), AV_OPT_TYPE_STRING
, {.str
="."}, CHAR_MIN
, CHAR_MAX
},
1084 {"hierarchical", "specify if the section specification should be hierarchical", OFFSET(hierarchical
), AV_OPT_TYPE_INT
, {.i64
=1}, 0, 1 },
1085 {"h", "specify if the section specification should be hierarchical", OFFSET(hierarchical
), AV_OPT_TYPE_INT
, {.i64
=1}, 0, 1 },
1089 DEFINE_WRITER_CLASS(flat
);
1091 static av_cold
int flat_init(WriterContext
*wctx
)
1093 FlatContext
*flat
= wctx
->priv
;
1095 if (strlen(flat
->sep_str
) != 1) {
1096 av_log(wctx
, AV_LOG_ERROR
, "Item separator '%s' specified, but must contain a single character\n",
1098 return AVERROR(EINVAL
);
1100 flat
->sep
= flat
->sep_str
[0];
1105 static const char *flat_escape_key_str(AVBPrint
*dst
, const char *src
, const char sep
)
1109 for (p
= src
; *p
; p
++) {
1110 if (!((*p
>= '0' && *p
<= '9') ||
1111 (*p
>= 'a' && *p
<= 'z') ||
1112 (*p
>= 'A' && *p
<= 'Z')))
1113 av_bprint_chars(dst
, '_', 1);
1115 av_bprint_chars(dst
, *p
, 1);
1120 static const char *flat_escape_value_str(AVBPrint
*dst
, const char *src
)
1124 for (p
= src
; *p
; p
++) {
1126 case '\n': av_bprintf(dst
, "%s", "\\n"); break;
1127 case '\r': av_bprintf(dst
, "%s", "\\r"); break;
1128 case '\\': av_bprintf(dst
, "%s", "\\\\"); break;
1129 case '"': av_bprintf(dst
, "%s", "\\\""); break;
1130 case '`': av_bprintf(dst
, "%s", "\\`"); break;
1131 case '$': av_bprintf(dst
, "%s", "\\$"); break;
1132 default: av_bprint_chars(dst
, *p
, 1); break;
1138 static void flat_print_section_header(WriterContext
*wctx
)
1140 FlatContext
*flat
= wctx
->priv
;
1141 AVBPrint
*buf
= &wctx
->section_pbuf
[wctx
->level
];
1142 const struct section
*section
= wctx
->section
[wctx
->level
];
1143 const struct section
*parent_section
= wctx
->level
?
1144 wctx
->section
[wctx
->level
-1] : NULL
;
1146 /* build section header */
1147 av_bprint_clear(buf
);
1148 if (!parent_section
)
1150 av_bprintf(buf
, "%s", wctx
->section_pbuf
[wctx
->level
-1].str
);
1152 if (flat
->hierarchical
||
1153 !(section
->flags
& (SECTION_FLAG_IS_ARRAY
|SECTION_FLAG_IS_WRAPPER
))) {
1154 av_bprintf(buf
, "%s%s", wctx
->section
[wctx
->level
]->name
, flat
->sep_str
);
1156 if (parent_section
->flags
& SECTION_FLAG_IS_ARRAY
) {
1157 int n
= parent_section
->id
== SECTION_ID_PACKETS_AND_FRAMES
?
1158 wctx
->nb_section_packet_frame
: wctx
->nb_item
[wctx
->level
-1];
1159 av_bprintf(buf
, "%d%s", n
, flat
->sep_str
);
1164 static void flat_print_int(WriterContext
*wctx
, const char *key
, long long int value
)
1166 printf("%s%s=%lld\n", wctx
->section_pbuf
[wctx
->level
].str
, key
, value
);
1169 static void flat_print_str(WriterContext
*wctx
, const char *key
, const char *value
)
1171 FlatContext
*flat
= wctx
->priv
;
1174 printf("%s", wctx
->section_pbuf
[wctx
->level
].str
);
1175 av_bprint_init(&buf
, 1, AV_BPRINT_SIZE_UNLIMITED
);
1176 printf("%s=", flat_escape_key_str(&buf
, key
, flat
->sep
));
1177 av_bprint_clear(&buf
);
1178 printf("\"%s\"\n", flat_escape_value_str(&buf
, value
));
1179 av_bprint_finalize(&buf
, NULL
);
1182 static const Writer flat_writer
= {
1184 .priv_size
= sizeof(FlatContext
),
1186 .print_section_header
= flat_print_section_header
,
1187 .print_integer
= flat_print_int
,
1188 .print_string
= flat_print_str
,
1189 .flags
= WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS
|WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER
,
1190 .priv_class
= &flat_class
,
1193 /* INI format output */
1196 const AVClass
*class;
1201 #define OFFSET(x) offsetof(INIContext, x)
1203 static const AVOption ini_options
[] = {
1204 {"hierarchical", "specify if the section specification should be hierarchical", OFFSET(hierarchical
), AV_OPT_TYPE_INT
, {.i64
=1}, 0, 1 },
1205 {"h", "specify if the section specification should be hierarchical", OFFSET(hierarchical
), AV_OPT_TYPE_INT
, {.i64
=1}, 0, 1 },
1209 DEFINE_WRITER_CLASS(ini
);
1211 static char *ini_escape_str(AVBPrint
*dst
, const char *src
)
1216 while (c
= src
[i
++]) {
1218 case '\b': av_bprintf(dst
, "%s", "\\b"); break;
1219 case '\f': av_bprintf(dst
, "%s", "\\f"); break;
1220 case '\n': av_bprintf(dst
, "%s", "\\n"); break;
1221 case '\r': av_bprintf(dst
, "%s", "\\r"); break;
1222 case '\t': av_bprintf(dst
, "%s", "\\t"); break;
1226 case ':' : av_bprint_chars(dst
, '\\', 1);
1228 if ((unsigned char)c
< 32)
1229 av_bprintf(dst
, "\\x00%02x", c
& 0xff);
1231 av_bprint_chars(dst
, c
, 1);
1238 static void ini_print_section_header(WriterContext
*wctx
)
1240 INIContext
*ini
= wctx
->priv
;
1241 AVBPrint
*buf
= &wctx
->section_pbuf
[wctx
->level
];
1242 const struct section
*section
= wctx
->section
[wctx
->level
];
1243 const struct section
*parent_section
= wctx
->level
?
1244 wctx
->section
[wctx
->level
-1] : NULL
;
1246 av_bprint_clear(buf
);
1247 if (!parent_section
) {
1248 printf("# ffprobe output\n\n");
1252 if (wctx
->nb_item
[wctx
->level
-1])
1255 av_bprintf(buf
, "%s", wctx
->section_pbuf
[wctx
->level
-1].str
);
1256 if (ini
->hierarchical
||
1257 !(section
->flags
& (SECTION_FLAG_IS_ARRAY
|SECTION_FLAG_IS_WRAPPER
))) {
1258 av_bprintf(buf
, "%s%s", buf
->str
[0] ? "." : "", wctx
->section
[wctx
->level
]->name
);
1260 if (parent_section
->flags
& SECTION_FLAG_IS_ARRAY
) {
1261 int n
= parent_section
->id
== SECTION_ID_PACKETS_AND_FRAMES
?
1262 wctx
->nb_section_packet_frame
: wctx
->nb_item
[wctx
->level
-1];
1263 av_bprintf(buf
, ".%d", n
);
1267 if (!(section
->flags
& (SECTION_FLAG_IS_ARRAY
|SECTION_FLAG_IS_WRAPPER
)))
1268 printf("[%s]\n", buf
->str
);
1271 static void ini_print_str(WriterContext
*wctx
, const char *key
, const char *value
)
1275 av_bprint_init(&buf
, 1, AV_BPRINT_SIZE_UNLIMITED
);
1276 printf("%s=", ini_escape_str(&buf
, key
));
1277 av_bprint_clear(&buf
);
1278 printf("%s\n", ini_escape_str(&buf
, value
));
1279 av_bprint_finalize(&buf
, NULL
);
1282 static void ini_print_int(WriterContext
*wctx
, const char *key
, long long int value
)
1284 printf("%s=%lld\n", key
, value
);
1287 static const Writer ini_writer
= {
1289 .priv_size
= sizeof(INIContext
),
1290 .print_section_header
= ini_print_section_header
,
1291 .print_integer
= ini_print_int
,
1292 .print_string
= ini_print_str
,
1293 .flags
= WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS
|WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER
,
1294 .priv_class
= &ini_class
,
1300 const AVClass
*class;
1303 const char *item_sep
, *item_start_end
;
1307 #define OFFSET(x) offsetof(JSONContext, x)
1309 static const AVOption json_options
[]= {
1310 { "compact", "enable compact output", OFFSET(compact
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1 },
1311 { "c", "enable compact output", OFFSET(compact
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1 },
1315 DEFINE_WRITER_CLASS(json
);
1317 static av_cold
int json_init(WriterContext
*wctx
)
1319 JSONContext
*json
= wctx
->priv
;
1321 json
->item_sep
= json
->compact
? ", " : ",\n";
1322 json
->item_start_end
= json
->compact
? " " : "\n";
1327 static const char *json_escape_str(AVBPrint
*dst
, const char *src
, void *log_ctx
)
1329 static const char json_escape
[] = {'"', '\\', '\b', '\f', '\n', '\r', '\t', 0};
1330 static const char json_subst
[] = {'"', '\\', 'b', 'f', 'n', 'r', 't', 0};
1333 for (p
= src
; *p
; p
++) {
1334 char *s
= strchr(json_escape
, *p
);
1336 av_bprint_chars(dst
, '\\', 1);
1337 av_bprint_chars(dst
, json_subst
[s
- json_escape
], 1);
1338 } else if ((unsigned char)*p
< 32) {
1339 av_bprintf(dst
, "\\u00%02x", *p
& 0xff);
1341 av_bprint_chars(dst
, *p
, 1);
1347 #define JSON_INDENT() printf("%*c", json->indent_level * 4, ' ')
1349 static void json_print_section_header(WriterContext
*wctx
)
1351 JSONContext
*json
= wctx
->priv
;
1353 const struct section
*section
= wctx
->section
[wctx
->level
];
1354 const struct section
*parent_section
= wctx
->level
?
1355 wctx
->section
[wctx
->level
-1] : NULL
;
1357 if (wctx
->level
&& wctx
->nb_item
[wctx
->level
-1])
1360 if (section
->flags
& SECTION_FLAG_IS_WRAPPER
) {
1362 json
->indent_level
++;
1364 av_bprint_init(&buf
, 1, AV_BPRINT_SIZE_UNLIMITED
);
1365 json_escape_str(&buf
, section
->name
, wctx
);
1368 json
->indent_level
++;
1369 if (section
->flags
& SECTION_FLAG_IS_ARRAY
) {
1370 printf("\"%s\": [\n", buf
.str
);
1371 } else if (parent_section
&& !(parent_section
->flags
& SECTION_FLAG_IS_ARRAY
)) {
1372 printf("\"%s\": {%s", buf
.str
, json
->item_start_end
);
1374 printf("{%s", json
->item_start_end
);
1376 /* this is required so the parser can distinguish between packets and frames */
1377 if (parent_section
&& parent_section
->id
== SECTION_ID_PACKETS_AND_FRAMES
) {
1380 printf("\"type\": \"%s\"%s", section
->name
, json
->item_sep
);
1383 av_bprint_finalize(&buf
, NULL
);
1387 static void json_print_section_footer(WriterContext
*wctx
)
1389 JSONContext
*json
= wctx
->priv
;
1390 const struct section
*section
= wctx
->section
[wctx
->level
];
1392 if (wctx
->level
== 0) {
1393 json
->indent_level
--;
1395 } else if (section
->flags
& SECTION_FLAG_IS_ARRAY
) {
1397 json
->indent_level
--;
1401 printf("%s", json
->item_start_end
);
1402 json
->indent_level
--;
1409 static inline void json_print_item_str(WriterContext
*wctx
,
1410 const char *key
, const char *value
)
1414 av_bprint_init(&buf
, 1, AV_BPRINT_SIZE_UNLIMITED
);
1415 printf("\"%s\":", json_escape_str(&buf
, key
, wctx
));
1416 av_bprint_clear(&buf
);
1417 printf(" \"%s\"", json_escape_str(&buf
, value
, wctx
));
1418 av_bprint_finalize(&buf
, NULL
);
1421 static void json_print_str(WriterContext
*wctx
, const char *key
, const char *value
)
1423 JSONContext
*json
= wctx
->priv
;
1425 if (wctx
->nb_item
[wctx
->level
])
1426 printf("%s", json
->item_sep
);
1429 json_print_item_str(wctx
, key
, value
);
1432 static void json_print_int(WriterContext
*wctx
, const char *key
, long long int value
)
1434 JSONContext
*json
= wctx
->priv
;
1437 if (wctx
->nb_item
[wctx
->level
])
1438 printf("%s", json
->item_sep
);
1442 av_bprint_init(&buf
, 1, AV_BPRINT_SIZE_UNLIMITED
);
1443 printf("\"%s\": %lld", json_escape_str(&buf
, key
, wctx
), value
);
1444 av_bprint_finalize(&buf
, NULL
);
1447 static const Writer json_writer
= {
1449 .priv_size
= sizeof(JSONContext
),
1451 .print_section_header
= json_print_section_header
,
1452 .print_section_footer
= json_print_section_footer
,
1453 .print_integer
= json_print_int
,
1454 .print_string
= json_print_str
,
1455 .flags
= WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER
,
1456 .priv_class
= &json_class
,
1462 const AVClass
*class;
1465 int fully_qualified
;
1470 #define OFFSET(x) offsetof(XMLContext, x)
1472 static const AVOption xml_options
[] = {
1473 {"fully_qualified", "specify if the output should be fully qualified", OFFSET(fully_qualified
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1 },
1474 {"q", "specify if the output should be fully qualified", OFFSET(fully_qualified
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1 },
1475 {"xsd_strict", "ensure that the output is XSD compliant", OFFSET(xsd_strict
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1 },
1476 {"x", "ensure that the output is XSD compliant", OFFSET(xsd_strict
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1 },
1480 DEFINE_WRITER_CLASS(xml
);
1482 static av_cold
int xml_init(WriterContext
*wctx
)
1484 XMLContext
*xml
= wctx
->priv
;
1486 if (xml
->xsd_strict
) {
1487 xml
->fully_qualified
= 1;
1488 #define CHECK_COMPLIANCE(opt, opt_name) \
1490 av_log(wctx, AV_LOG_ERROR, \
1491 "XSD-compliant output selected but option '%s' was selected, XML output may be non-compliant.\n" \
1492 "You need to disable such option with '-no%s'\n", opt_name, opt_name); \
1493 return AVERROR(EINVAL); \
1495 CHECK_COMPLIANCE(show_private_data
, "private");
1496 CHECK_COMPLIANCE(show_value_unit
, "unit");
1497 CHECK_COMPLIANCE(use_value_prefix
, "prefix");
1499 if (do_show_frames
&& do_show_packets
) {
1500 av_log(wctx
, AV_LOG_ERROR
,
1501 "Interleaved frames and packets are not allowed in XSD. "
1502 "Select only one between the -show_frames and the -show_packets options.\n");
1503 return AVERROR(EINVAL
);
1510 static const char *xml_escape_str(AVBPrint
*dst
, const char *src
, void *log_ctx
)
1514 for (p
= src
; *p
; p
++) {
1516 case '&' : av_bprintf(dst
, "%s", "&"); break;
1517 case '<' : av_bprintf(dst
, "%s", "<"); break;
1518 case '>' : av_bprintf(dst
, "%s", ">"); break;
1519 case '"' : av_bprintf(dst
, "%s", """); break;
1520 case '\'': av_bprintf(dst
, "%s", "'"); break;
1521 default: av_bprint_chars(dst
, *p
, 1);
1528 #define XML_INDENT() printf("%*c", xml->indent_level * 4, ' ')
1530 static void xml_print_section_header(WriterContext
*wctx
)
1532 XMLContext
*xml
= wctx
->priv
;
1533 const struct section
*section
= wctx
->section
[wctx
->level
];
1534 const struct section
*parent_section
= wctx
->level
?
1535 wctx
->section
[wctx
->level
-1] : NULL
;
1537 if (wctx
->level
== 0) {
1538 const char *qual
= " xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' "
1539 "xmlns:ffprobe='http://www.ffmpeg.org/schema/ffprobe' "
1540 "xsi:schemaLocation='http://www.ffmpeg.org/schema/ffprobe ffprobe.xsd'";
1542 printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1543 printf("<%sffprobe%s>\n",
1544 xml
->fully_qualified
? "ffprobe:" : "",
1545 xml
->fully_qualified
? qual
: "");
1549 if (xml
->within_tag
) {
1550 xml
->within_tag
= 0;
1553 if (section
->flags
& SECTION_FLAG_HAS_VARIABLE_FIELDS
) {
1554 xml
->indent_level
++;
1556 if (parent_section
&& (parent_section
->flags
& SECTION_FLAG_IS_WRAPPER
) &&
1557 wctx
->level
&& wctx
->nb_item
[wctx
->level
-1])
1559 xml
->indent_level
++;
1561 if (section
->flags
& SECTION_FLAG_IS_ARRAY
) {
1562 XML_INDENT(); printf("<%s>\n", section
->name
);
1564 XML_INDENT(); printf("<%s ", section
->name
);
1565 xml
->within_tag
= 1;
1570 static void xml_print_section_footer(WriterContext
*wctx
)
1572 XMLContext
*xml
= wctx
->priv
;
1573 const struct section
*section
= wctx
->section
[wctx
->level
];
1575 if (wctx
->level
== 0) {
1576 printf("</%sffprobe>\n", xml
->fully_qualified
? "ffprobe:" : "");
1577 } else if (xml
->within_tag
) {
1578 xml
->within_tag
= 0;
1580 xml
->indent_level
--;
1581 } else if (section
->flags
& SECTION_FLAG_HAS_VARIABLE_FIELDS
) {
1582 xml
->indent_level
--;
1584 XML_INDENT(); printf("</%s>\n", section
->name
);
1585 xml
->indent_level
--;
1589 static void xml_print_str(WriterContext
*wctx
, const char *key
, const char *value
)
1592 XMLContext
*xml
= wctx
->priv
;
1593 const struct section
*section
= wctx
->section
[wctx
->level
];
1595 av_bprint_init(&buf
, 1, AV_BPRINT_SIZE_UNLIMITED
);
1597 if (section
->flags
& SECTION_FLAG_HAS_VARIABLE_FIELDS
) {
1599 printf("<%s key=\"%s\"",
1600 section
->element_name
, xml_escape_str(&buf
, key
, wctx
));
1601 av_bprint_clear(&buf
);
1602 printf(" value=\"%s\"/>\n", xml_escape_str(&buf
, value
, wctx
));
1604 if (wctx
->nb_item
[wctx
->level
])
1606 printf("%s=\"%s\"", key
, xml_escape_str(&buf
, value
, wctx
));
1609 av_bprint_finalize(&buf
, NULL
);
1612 static void xml_print_int(WriterContext
*wctx
, const char *key
, long long int value
)
1614 if (wctx
->nb_item
[wctx
->level
])
1616 printf("%s=\"%lld\"", key
, value
);
1619 static Writer xml_writer
= {
1621 .priv_size
= sizeof(XMLContext
),
1623 .print_section_header
= xml_print_section_header
,
1624 .print_section_footer
= xml_print_section_footer
,
1625 .print_integer
= xml_print_int
,
1626 .print_string
= xml_print_str
,
1627 .flags
= WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER
,
1628 .priv_class
= &xml_class
,
1631 static void writer_register_all(void)
1633 static int initialized
;
1639 writer_register(&default_writer
);
1640 writer_register(&compact_writer
);
1641 writer_register(&csv_writer
);
1642 writer_register(&flat_writer
);
1643 writer_register(&ini_writer
);
1644 writer_register(&json_writer
);
1645 writer_register(&xml_writer
);
1648 #define print_fmt(k, f, ...) do { \
1649 av_bprint_clear(&pbuf); \
1650 av_bprintf(&pbuf, f, __VA_ARGS__); \
1651 writer_print_string(w, k, pbuf.str, 0); \
1654 #define print_int(k, v) writer_print_integer(w, k, v)
1655 #define print_q(k, v, s) writer_print_rational(w, k, v, s)
1656 #define print_str(k, v) writer_print_string(w, k, v, 0)
1657 #define print_str_opt(k, v) writer_print_string(w, k, v, PRINT_STRING_OPT)
1658 #define print_str_validate(k, v) writer_print_string(w, k, v, PRINT_STRING_VALIDATE)
1659 #define print_time(k, v, tb) writer_print_time(w, k, v, tb, 0)
1660 #define print_ts(k, v) writer_print_ts(w, k, v, 0)
1661 #define print_duration_time(k, v, tb) writer_print_time(w, k, v, tb, 1)
1662 #define print_duration_ts(k, v) writer_print_ts(w, k, v, 1)
1663 #define print_val(k, v, u) do { \
1664 struct unit_value uv; \
1667 writer_print_string(w, k, value_string(val_str, sizeof(val_str), uv), 0); \
1670 #define print_section_header(s) writer_print_section_header(w, s)
1671 #define print_section_footer(s) writer_print_section_footer(w, s)
1673 #define REALLOCZ_ARRAY_STREAM(ptr, cur_n, new_n) \
1675 ret = av_reallocp_array(&(ptr), (new_n), sizeof(*(ptr))); \
1678 memset( (ptr) + (cur_n), 0, ((new_n) - (cur_n)) * sizeof(*(ptr)) ); \
1681 static inline int show_tags(WriterContext
*w
, AVDictionary
*tags
, int section_id
)
1683 AVDictionaryEntry
*tag
= NULL
;
1688 writer_print_section_header(w
, section_id
);
1690 while ((tag
= av_dict_get(tags
, "", tag
, AV_DICT_IGNORE_SUFFIX
))) {
1691 if ((ret
= print_str_validate(tag
->key
, tag
->value
)) < 0)
1694 writer_print_section_footer(w
);
1699 static void show_packet(WriterContext
*w
, AVFormatContext
*fmt_ctx
, AVPacket
*pkt
, int packet_idx
)
1702 AVStream
*st
= fmt_ctx
->streams
[pkt
->stream_index
];
1706 av_bprint_init(&pbuf
, 1, AV_BPRINT_SIZE_UNLIMITED
);
1708 writer_print_section_header(w
, SECTION_ID_PACKET
);
1710 s
= av_get_media_type_string(st
->codec
->codec_type
);
1711 if (s
) print_str ("codec_type", s
);
1712 else print_str_opt("codec_type", "unknown");
1713 print_int("stream_index", pkt
->stream_index
);
1714 print_ts ("pts", pkt
->pts
);
1715 print_time("pts_time", pkt
->pts
, &st
->time_base
);
1716 print_ts ("dts", pkt
->dts
);
1717 print_time("dts_time", pkt
->dts
, &st
->time_base
);
1718 print_duration_ts("duration", pkt
->duration
);
1719 print_duration_time("duration_time", pkt
->duration
, &st
->time_base
);
1720 print_duration_ts("convergence_duration", pkt
->convergence_duration
);
1721 print_duration_time("convergence_duration_time", pkt
->convergence_duration
, &st
->time_base
);
1722 print_val("size", pkt
->size
, unit_byte_str
);
1723 if (pkt
->pos
!= -1) print_fmt ("pos", "%"PRId64
, pkt
->pos
);
1724 else print_str_opt("pos", "N/A");
1725 print_fmt("flags", "%c", pkt
->flags
& AV_PKT_FLAG_KEY
? 'K' : '_');
1727 writer_print_data(w
, "data", pkt
->data
, pkt
->size
);
1728 writer_print_data_hash(w
, "data_hash", pkt
->data
, pkt
->size
);
1729 writer_print_section_footer(w
);
1731 av_bprint_finalize(&pbuf
, NULL
);
1735 static void show_subtitle(WriterContext
*w
, AVSubtitle
*sub
, AVStream
*stream
,
1736 AVFormatContext
*fmt_ctx
)
1740 av_bprint_init(&pbuf
, 1, AV_BPRINT_SIZE_UNLIMITED
);
1742 writer_print_section_header(w
, SECTION_ID_SUBTITLE
);
1744 print_str ("media_type", "subtitle");
1745 print_ts ("pts", sub
->pts
);
1746 print_time("pts_time", sub
->pts
, &AV_TIME_BASE_Q
);
1747 print_int ("format", sub
->format
);
1748 print_int ("start_display_time", sub
->start_display_time
);
1749 print_int ("end_display_time", sub
->end_display_time
);
1750 print_int ("num_rects", sub
->num_rects
);
1752 writer_print_section_footer(w
);
1754 av_bprint_finalize(&pbuf
, NULL
);
1758 static void show_frame(WriterContext
*w
, AVFrame
*frame
, AVStream
*stream
,
1759 AVFormatContext
*fmt_ctx
)
1765 av_bprint_init(&pbuf
, 1, AV_BPRINT_SIZE_UNLIMITED
);
1767 writer_print_section_header(w
, SECTION_ID_FRAME
);
1769 s
= av_get_media_type_string(stream
->codec
->codec_type
);
1770 if (s
) print_str ("media_type", s
);
1771 else print_str_opt("media_type", "unknown");
1772 print_int("key_frame", frame
->key_frame
);
1773 print_ts ("pkt_pts", frame
->pkt_pts
);
1774 print_time("pkt_pts_time", frame
->pkt_pts
, &stream
->time_base
);
1775 print_ts ("pkt_dts", frame
->pkt_dts
);
1776 print_time("pkt_dts_time", frame
->pkt_dts
, &stream
->time_base
);
1777 print_ts ("best_effort_timestamp", av_frame_get_best_effort_timestamp(frame
));
1778 print_time("best_effort_timestamp_time", av_frame_get_best_effort_timestamp(frame
), &stream
->time_base
);
1779 print_duration_ts ("pkt_duration", av_frame_get_pkt_duration(frame
));
1780 print_duration_time("pkt_duration_time", av_frame_get_pkt_duration(frame
), &stream
->time_base
);
1781 if (av_frame_get_pkt_pos (frame
) != -1) print_fmt ("pkt_pos", "%"PRId64
, av_frame_get_pkt_pos(frame
));
1782 else print_str_opt("pkt_pos", "N/A");
1783 if (av_frame_get_pkt_size(frame
) != -1) print_fmt ("pkt_size", "%d", av_frame_get_pkt_size(frame
));
1784 else print_str_opt("pkt_size", "N/A");
1786 switch (stream
->codec
->codec_type
) {
1789 case AVMEDIA_TYPE_VIDEO
:
1790 print_int("width", frame
->width
);
1791 print_int("height", frame
->height
);
1792 s
= av_get_pix_fmt_name(frame
->format
);
1793 if (s
) print_str ("pix_fmt", s
);
1794 else print_str_opt("pix_fmt", "unknown");
1795 sar
= av_guess_sample_aspect_ratio(fmt_ctx
, stream
, frame
);
1797 print_q("sample_aspect_ratio", sar
, ':');
1799 print_str_opt("sample_aspect_ratio", "N/A");
1801 print_fmt("pict_type", "%c", av_get_picture_type_char(frame
->pict_type
));
1802 print_int("coded_picture_number", frame
->coded_picture_number
);
1803 print_int("display_picture_number", frame
->display_picture_number
);
1804 print_int("interlaced_frame", frame
->interlaced_frame
);
1805 print_int("top_field_first", frame
->top_field_first
);
1806 print_int("repeat_pict", frame
->repeat_pict
);
1809 case AVMEDIA_TYPE_AUDIO
:
1810 s
= av_get_sample_fmt_name(frame
->format
);
1811 if (s
) print_str ("sample_fmt", s
);
1812 else print_str_opt("sample_fmt", "unknown");
1813 print_int("nb_samples", frame
->nb_samples
);
1814 print_int("channels", av_frame_get_channels(frame
));
1815 if (av_frame_get_channel_layout(frame
)) {
1816 av_bprint_clear(&pbuf
);
1817 av_bprint_channel_layout(&pbuf
, av_frame_get_channels(frame
),
1818 av_frame_get_channel_layout(frame
));
1819 print_str ("channel_layout", pbuf
.str
);
1821 print_str_opt("channel_layout", "unknown");
1824 if (do_show_frame_tags
)
1825 show_tags(w
, av_frame_get_metadata(frame
), SECTION_ID_FRAME_TAGS
);
1826 if (frame
->nb_side_data
) {
1827 writer_print_section_header(w
, SECTION_ID_FRAME_SIDE_DATA_LIST
);
1828 for (i
= 0; i
< frame
->nb_side_data
; i
++) {
1829 AVFrameSideData
*sd
= frame
->side_data
[i
];
1832 writer_print_section_header(w
, SECTION_ID_FRAME_SIDE_DATA
);
1833 name
= av_frame_side_data_name(sd
->type
);
1834 print_str("side_data_type", name
? name
: "unknown");
1835 print_int("side_data_size", sd
->size
);
1836 writer_print_section_footer(w
);
1838 writer_print_section_footer(w
);
1841 writer_print_section_footer(w
);
1843 av_bprint_finalize(&pbuf
, NULL
);
1847 static av_always_inline
int process_frame(WriterContext
*w
,
1848 AVFormatContext
*fmt_ctx
,
1849 AVFrame
*frame
, AVPacket
*pkt
)
1851 AVCodecContext
*dec_ctx
= fmt_ctx
->streams
[pkt
->stream_index
]->codec
;
1853 int ret
= 0, got_frame
= 0;
1855 if (dec_ctx
->codec
) {
1856 switch (dec_ctx
->codec_type
) {
1857 case AVMEDIA_TYPE_VIDEO
:
1858 ret
= avcodec_decode_video2(dec_ctx
, frame
, &got_frame
, pkt
);
1861 case AVMEDIA_TYPE_AUDIO
:
1862 ret
= avcodec_decode_audio4(dec_ctx
, frame
, &got_frame
, pkt
);
1865 case AVMEDIA_TYPE_SUBTITLE
:
1866 ret
= avcodec_decode_subtitle2(dec_ctx
, &sub
, &got_frame
, pkt
);
1873 ret
= FFMIN(ret
, pkt
->size
); /* guard against bogus return values */
1877 int is_sub
= (dec_ctx
->codec_type
== AVMEDIA_TYPE_SUBTITLE
);
1878 nb_streams_frames
[pkt
->stream_index
]++;
1881 show_subtitle(w
, &sub
, fmt_ctx
->streams
[pkt
->stream_index
], fmt_ctx
);
1883 show_frame(w
, frame
, fmt_ctx
->streams
[pkt
->stream_index
], fmt_ctx
);
1885 avsubtitle_free(&sub
);
1890 static void log_read_interval(const ReadInterval
*interval
, void *log_ctx
, int log_level
)
1892 av_log(log_ctx
, log_level
, "id:%d", interval
->id
);
1894 if (interval
->has_start
) {
1895 av_log(log_ctx
, log_level
, " start:%s%s", interval
->start_is_offset
? "+" : "",
1896 av_ts2timestr(interval
->start
, &AV_TIME_BASE_Q
));
1898 av_log(log_ctx
, log_level
, " start:N/A");
1901 if (interval
->has_end
) {
1902 av_log(log_ctx
, log_level
, " end:%s", interval
->end_is_offset
? "+" : "");
1903 if (interval
->duration_frames
)
1904 av_log(log_ctx
, log_level
, "#%"PRId64
, interval
->end
);
1906 av_log(log_ctx
, log_level
, "%s", av_ts2timestr(interval
->end
, &AV_TIME_BASE_Q
));
1908 av_log(log_ctx
, log_level
, " end:N/A");
1911 av_log(log_ctx
, log_level
, "\n");
1914 static int read_interval_packets(WriterContext
*w
, AVFormatContext
*fmt_ctx
,
1915 const ReadInterval
*interval
, int64_t *cur_ts
)
1918 AVFrame
*frame
= NULL
;
1919 int ret
= 0, i
= 0, frame_count
= 0;
1920 int64_t start
= -INT64_MAX
, end
= interval
->end
;
1921 int has_start
= 0, has_end
= interval
->has_end
&& !interval
->end_is_offset
;
1923 av_init_packet(&pkt
);
1925 av_log(NULL
, AV_LOG_VERBOSE
, "Processing read interval ");
1926 log_read_interval(interval
, NULL
, AV_LOG_VERBOSE
);
1928 if (interval
->has_start
) {
1930 if (interval
->start_is_offset
) {
1931 if (*cur_ts
== AV_NOPTS_VALUE
) {
1932 av_log(NULL
, AV_LOG_ERROR
,
1933 "Could not seek to relative position since current "
1934 "timestamp is not defined\n");
1935 ret
= AVERROR(EINVAL
);
1938 target
= *cur_ts
+ interval
->start
;
1940 target
= interval
->start
;
1943 av_log(NULL
, AV_LOG_VERBOSE
, "Seeking to read interval start point %s\n",
1944 av_ts2timestr(target
, &AV_TIME_BASE_Q
));
1945 if ((ret
= avformat_seek_file(fmt_ctx
, -1, -INT64_MAX
, target
, INT64_MAX
, 0)) < 0) {
1946 av_log(NULL
, AV_LOG_ERROR
, "Could not seek to position %"PRId64
": %s\n",
1947 interval
->start
, av_err2str(ret
));
1952 frame
= av_frame_alloc();
1954 ret
= AVERROR(ENOMEM
);
1957 while (!av_read_frame(fmt_ctx
, &pkt
)) {
1958 if (fmt_ctx
->nb_streams
> nb_streams
) {
1959 REALLOCZ_ARRAY_STREAM(nb_streams_frames
, nb_streams
, fmt_ctx
->nb_streams
);
1960 REALLOCZ_ARRAY_STREAM(nb_streams_packets
, nb_streams
, fmt_ctx
->nb_streams
);
1961 REALLOCZ_ARRAY_STREAM(selected_streams
, nb_streams
, fmt_ctx
->nb_streams
);
1962 nb_streams
= fmt_ctx
->nb_streams
;
1964 if (selected_streams
[pkt
.stream_index
]) {
1965 AVRational tb
= fmt_ctx
->streams
[pkt
.stream_index
]->time_base
;
1967 if (pkt
.pts
!= AV_NOPTS_VALUE
)
1968 *cur_ts
= av_rescale_q(pkt
.pts
, tb
, AV_TIME_BASE_Q
);
1970 if (!has_start
&& *cur_ts
!= AV_NOPTS_VALUE
) {
1975 if (has_start
&& !has_end
&& interval
->end_is_offset
) {
1976 end
= start
+ interval
->end
;
1980 if (interval
->end_is_offset
&& interval
->duration_frames
) {
1981 if (frame_count
>= interval
->end
)
1983 } else if (has_end
&& *cur_ts
!= AV_NOPTS_VALUE
&& *cur_ts
>= end
) {
1988 if (do_read_packets
) {
1989 if (do_show_packets
)
1990 show_packet(w
, fmt_ctx
, &pkt
, i
++);
1991 nb_streams_packets
[pkt
.stream_index
]++;
1993 if (do_read_frames
) {
1995 while (pkt1
.size
&& process_frame(w
, fmt_ctx
, frame
, &pkt1
) > 0);
1998 av_free_packet(&pkt
);
2000 av_init_packet(&pkt
);
2003 //Flush remaining frames that are cached in the decoder
2004 for (i
= 0; i
< fmt_ctx
->nb_streams
; i
++) {
2005 pkt
.stream_index
= i
;
2007 while (process_frame(w
, fmt_ctx
, frame
, &pkt
) > 0);
2011 av_frame_free(&frame
);
2013 av_log(NULL
, AV_LOG_ERROR
, "Could not read packets in interval ");
2014 log_read_interval(interval
, NULL
, AV_LOG_ERROR
);
2019 static int read_packets(WriterContext
*w
, AVFormatContext
*fmt_ctx
)
2022 int64_t cur_ts
= fmt_ctx
->start_time
;
2024 if (read_intervals_nb
== 0) {
2025 ReadInterval interval
= (ReadInterval
) { .has_start
= 0, .has_end
= 0 };
2026 ret
= read_interval_packets(w
, fmt_ctx
, &interval
, &cur_ts
);
2028 for (i
= 0; i
< read_intervals_nb
; i
++) {
2029 ret
= read_interval_packets(w
, fmt_ctx
, &read_intervals
[i
], &cur_ts
);
2038 static int show_stream(WriterContext
*w
, AVFormatContext
*fmt_ctx
, int stream_idx
, int in_program
)
2040 AVStream
*stream
= fmt_ctx
->streams
[stream_idx
];
2041 AVCodecContext
*dec_ctx
;
2045 AVRational sar
, dar
;
2047 const AVCodecDescriptor
*cd
;
2050 av_bprint_init(&pbuf
, 1, AV_BPRINT_SIZE_UNLIMITED
);
2052 writer_print_section_header(w
, in_program
? SECTION_ID_PROGRAM_STREAM
: SECTION_ID_STREAM
);
2054 print_int("index", stream
->index
);
2056 if ((dec_ctx
= stream
->codec
)) {
2057 const char *profile
= NULL
;
2058 dec
= dec_ctx
->codec
;
2060 print_str("codec_name", dec
->name
);
2062 if (dec
->long_name
) print_str ("codec_long_name", dec
->long_name
);
2063 else print_str_opt("codec_long_name", "unknown");
2065 } else if ((cd
= avcodec_descriptor_get(stream
->codec
->codec_id
))) {
2066 print_str_opt("codec_name", cd
->name
);
2068 print_str_opt("codec_long_name",
2069 cd
->long_name
? cd
->long_name
: "unknown");
2072 print_str_opt("codec_name", "unknown");
2074 print_str_opt("codec_long_name", "unknown");
2078 if (dec
&& (profile
= av_get_profile_name(dec
, dec_ctx
->profile
)))
2079 print_str("profile", profile
);
2081 print_str_opt("profile", "unknown");
2083 s
= av_get_media_type_string(dec_ctx
->codec_type
);
2084 if (s
) print_str ("codec_type", s
);
2085 else print_str_opt("codec_type", "unknown");
2086 print_q("codec_time_base", dec_ctx
->time_base
, '/');
2088 /* print AVI/FourCC tag */
2089 av_get_codec_tag_string(val_str
, sizeof(val_str
), dec_ctx
->codec_tag
);
2090 print_str("codec_tag_string", val_str
);
2091 print_fmt("codec_tag", "0x%04x", dec_ctx
->codec_tag
);
2093 switch (dec_ctx
->codec_type
) {
2094 case AVMEDIA_TYPE_VIDEO
:
2095 print_int("width", dec_ctx
->width
);
2096 print_int("height", dec_ctx
->height
);
2097 print_int("has_b_frames", dec_ctx
->has_b_frames
);
2098 sar
= av_guess_sample_aspect_ratio(fmt_ctx
, stream
, NULL
);
2100 print_q("sample_aspect_ratio", sar
, ':');
2101 av_reduce(&dar
.num
, &dar
.den
,
2102 dec_ctx
->width
* sar
.num
,
2103 dec_ctx
->height
* sar
.den
,
2105 print_q("display_aspect_ratio", dar
, ':');
2107 print_str_opt("sample_aspect_ratio", "N/A");
2108 print_str_opt("display_aspect_ratio", "N/A");
2110 s
= av_get_pix_fmt_name(dec_ctx
->pix_fmt
);
2111 if (s
) print_str ("pix_fmt", s
);
2112 else print_str_opt("pix_fmt", "unknown");
2113 print_int("level", dec_ctx
->level
);
2114 if (dec_ctx
->color_range
!= AVCOL_RANGE_UNSPECIFIED
)
2115 print_str ("color_range", av_color_range_name(dec_ctx
->color_range
));
2117 print_str_opt("color_range", "N/A");
2118 s
= av_get_colorspace_name(dec_ctx
->colorspace
);
2119 if (s
) print_str ("color_space", s
);
2120 else print_str_opt("color_space", "unknown");
2122 if (dec_ctx
->color_trc
!= AVCOL_TRC_UNSPECIFIED
)
2123 print_str("color_transfer", av_color_transfer_name(dec_ctx
->color_trc
));
2125 print_str_opt("color_transfer", av_color_transfer_name(dec_ctx
->color_trc
));
2127 if (dec_ctx
->color_primaries
!= AVCOL_PRI_UNSPECIFIED
)
2128 print_str("color_primaries", av_color_primaries_name(dec_ctx
->color_primaries
));
2130 print_str_opt("color_primaries", av_color_primaries_name(dec_ctx
->color_primaries
));
2132 if (dec_ctx
->chroma_sample_location
!= AVCHROMA_LOC_UNSPECIFIED
)
2133 print_str("chroma_location", av_chroma_location_name(dec_ctx
->chroma_sample_location
));
2135 print_str_opt("chroma_location", av_chroma_location_name(dec_ctx
->chroma_sample_location
));
2137 if (dec_ctx
->timecode_frame_start
>= 0) {
2138 char tcbuf
[AV_TIMECODE_STR_SIZE
];
2139 av_timecode_make_mpeg_tc_string(tcbuf
, dec_ctx
->timecode_frame_start
);
2140 print_str("timecode", tcbuf
);
2142 print_str_opt("timecode", "N/A");
2146 case AVMEDIA_TYPE_AUDIO
:
2147 s
= av_get_sample_fmt_name(dec_ctx
->sample_fmt
);
2148 if (s
) print_str ("sample_fmt", s
);
2149 else print_str_opt("sample_fmt", "unknown");
2150 print_val("sample_rate", dec_ctx
->sample_rate
, unit_hertz_str
);
2151 print_int("channels", dec_ctx
->channels
);
2153 if (dec_ctx
->channel_layout
) {
2154 av_bprint_clear(&pbuf
);
2155 av_bprint_channel_layout(&pbuf
, dec_ctx
->channels
, dec_ctx
->channel_layout
);
2156 print_str ("channel_layout", pbuf
.str
);
2158 print_str_opt("channel_layout", "unknown");
2161 print_int("bits_per_sample", av_get_bits_per_sample(dec_ctx
->codec_id
));
2164 case AVMEDIA_TYPE_SUBTITLE
:
2166 print_int("width", dec_ctx
->width
);
2168 print_str_opt("width", "N/A");
2169 if (dec_ctx
->height
)
2170 print_int("height", dec_ctx
->height
);
2172 print_str_opt("height", "N/A");
2176 print_str_opt("codec_type", "unknown");
2178 if (dec_ctx
->codec
&& dec_ctx
->codec
->priv_class
&& show_private_data
) {
2179 const AVOption
*opt
= NULL
;
2180 while (opt
= av_opt_next(dec_ctx
->priv_data
,opt
)) {
2182 if (opt
->flags
) continue;
2183 if (av_opt_get(dec_ctx
->priv_data
, opt
->name
, 0, &str
) >= 0) {
2184 print_str(opt
->name
, str
);
2190 if (fmt_ctx
->iformat
->flags
& AVFMT_SHOW_IDS
) print_fmt ("id", "0x%x", stream
->id
);
2191 else print_str_opt("id", "N/A");
2192 print_q("r_frame_rate", stream
->r_frame_rate
, '/');
2193 print_q("avg_frame_rate", stream
->avg_frame_rate
, '/');
2194 print_q("time_base", stream
->time_base
, '/');
2195 print_ts ("start_pts", stream
->start_time
);
2196 print_time("start_time", stream
->start_time
, &stream
->time_base
);
2197 print_ts ("duration_ts", stream
->duration
);
2198 print_time("duration", stream
->duration
, &stream
->time_base
);
2199 if (dec_ctx
->bit_rate
> 0) print_val ("bit_rate", dec_ctx
->bit_rate
, unit_bit_per_second_str
);
2200 else print_str_opt("bit_rate", "N/A");
2201 if (dec_ctx
->rc_max_rate
> 0) print_val ("max_bit_rate", dec_ctx
->rc_max_rate
, unit_bit_per_second_str
);
2202 else print_str_opt("max_bit_rate", "N/A");
2203 if (dec_ctx
->bits_per_raw_sample
> 0) print_fmt("bits_per_raw_sample", "%d", dec_ctx
->bits_per_raw_sample
);
2204 else print_str_opt("bits_per_raw_sample", "N/A");
2205 if (stream
->nb_frames
) print_fmt ("nb_frames", "%"PRId64
, stream
->nb_frames
);
2206 else print_str_opt("nb_frames", "N/A");
2207 if (nb_streams_frames
[stream_idx
]) print_fmt ("nb_read_frames", "%"PRIu64
, nb_streams_frames
[stream_idx
]);
2208 else print_str_opt("nb_read_frames", "N/A");
2209 if (nb_streams_packets
[stream_idx
]) print_fmt ("nb_read_packets", "%"PRIu64
, nb_streams_packets
[stream_idx
]);
2210 else print_str_opt("nb_read_packets", "N/A");
2212 writer_print_data(w
, "extradata", dec_ctx
->extradata
,
2213 dec_ctx
->extradata_size
);
2214 writer_print_data_hash(w
, "extradata_hash", dec_ctx
->extradata
,
2215 dec_ctx
->extradata_size
);
2217 /* Print disposition information */
2218 #define PRINT_DISPOSITION(flagname, name) do { \
2219 print_int(name, !!(stream->disposition & AV_DISPOSITION_##flagname)); \
2222 if (do_show_stream_disposition
) {
2223 writer_print_section_header(w
, in_program
? SECTION_ID_PROGRAM_STREAM_DISPOSITION
: SECTION_ID_STREAM_DISPOSITION
);
2224 PRINT_DISPOSITION(DEFAULT
, "default");
2225 PRINT_DISPOSITION(DUB
, "dub");
2226 PRINT_DISPOSITION(ORIGINAL
, "original");
2227 PRINT_DISPOSITION(COMMENT
, "comment");
2228 PRINT_DISPOSITION(LYRICS
, "lyrics");
2229 PRINT_DISPOSITION(KARAOKE
, "karaoke");
2230 PRINT_DISPOSITION(FORCED
, "forced");
2231 PRINT_DISPOSITION(HEARING_IMPAIRED
, "hearing_impaired");
2232 PRINT_DISPOSITION(VISUAL_IMPAIRED
, "visual_impaired");
2233 PRINT_DISPOSITION(CLEAN_EFFECTS
, "clean_effects");
2234 PRINT_DISPOSITION(ATTACHED_PIC
, "attached_pic");
2235 writer_print_section_footer(w
);
2238 if (do_show_stream_tags
)
2239 ret
= show_tags(w
, stream
->metadata
, in_program
? SECTION_ID_PROGRAM_STREAM_TAGS
: SECTION_ID_STREAM_TAGS
);
2241 writer_print_section_footer(w
);
2242 av_bprint_finalize(&pbuf
, NULL
);
2248 static int show_streams(WriterContext
*w
, AVFormatContext
*fmt_ctx
)
2252 writer_print_section_header(w
, SECTION_ID_STREAMS
);
2253 for (i
= 0; i
< fmt_ctx
->nb_streams
; i
++)
2254 if (selected_streams
[i
]) {
2255 ret
= show_stream(w
, fmt_ctx
, i
, 0);
2259 writer_print_section_footer(w
);
2264 static int show_program(WriterContext
*w
, AVFormatContext
*fmt_ctx
, AVProgram
*program
)
2268 writer_print_section_header(w
, SECTION_ID_PROGRAM
);
2269 print_int("program_id", program
->id
);
2270 print_int("program_num", program
->program_num
);
2271 print_int("nb_streams", program
->nb_stream_indexes
);
2272 print_int("pmt_pid", program
->pmt_pid
);
2273 print_int("pcr_pid", program
->pcr_pid
);
2274 print_ts("start_pts", program
->start_time
);
2275 print_time("start_time", program
->start_time
, &AV_TIME_BASE_Q
);
2276 print_ts("end_pts", program
->end_time
);
2277 print_time("end_time", program
->end_time
, &AV_TIME_BASE_Q
);
2278 if (do_show_program_tags
)
2279 ret
= show_tags(w
, program
->metadata
, SECTION_ID_PROGRAM_TAGS
);
2283 writer_print_section_header(w
, SECTION_ID_PROGRAM_STREAMS
);
2284 for (i
= 0; i
< program
->nb_stream_indexes
; i
++) {
2285 if (selected_streams
[program
->stream_index
[i
]]) {
2286 ret
= show_stream(w
, fmt_ctx
, program
->stream_index
[i
], 1);
2291 writer_print_section_footer(w
);
2294 writer_print_section_footer(w
);
2298 static int show_programs(WriterContext
*w
, AVFormatContext
*fmt_ctx
)
2302 writer_print_section_header(w
, SECTION_ID_PROGRAMS
);
2303 for (i
= 0; i
< fmt_ctx
->nb_programs
; i
++) {
2304 AVProgram
*program
= fmt_ctx
->programs
[i
];
2307 ret
= show_program(w
, fmt_ctx
, program
);
2311 writer_print_section_footer(w
);
2315 static int show_chapters(WriterContext
*w
, AVFormatContext
*fmt_ctx
)
2319 writer_print_section_header(w
, SECTION_ID_CHAPTERS
);
2320 for (i
= 0; i
< fmt_ctx
->nb_chapters
; i
++) {
2321 AVChapter
*chapter
= fmt_ctx
->chapters
[i
];
2323 writer_print_section_header(w
, SECTION_ID_CHAPTER
);
2324 print_int("id", chapter
->id
);
2325 print_q ("time_base", chapter
->time_base
, '/');
2326 print_int("start", chapter
->start
);
2327 print_time("start_time", chapter
->start
, &chapter
->time_base
);
2328 print_int("end", chapter
->end
);
2329 print_time("end_time", chapter
->end
, &chapter
->time_base
);
2330 if (do_show_chapter_tags
)
2331 ret
= show_tags(w
, chapter
->metadata
, SECTION_ID_CHAPTER_TAGS
);
2332 writer_print_section_footer(w
);
2334 writer_print_section_footer(w
);
2339 static int show_format(WriterContext
*w
, AVFormatContext
*fmt_ctx
)
2342 int64_t size
= fmt_ctx
->pb
? avio_size(fmt_ctx
->pb
) : -1;
2345 writer_print_section_header(w
, SECTION_ID_FORMAT
);
2346 print_str_validate("filename", fmt_ctx
->filename
);
2347 print_int("nb_streams", fmt_ctx
->nb_streams
);
2348 print_int("nb_programs", fmt_ctx
->nb_programs
);
2349 print_str("format_name", fmt_ctx
->iformat
->name
);
2351 if (fmt_ctx
->iformat
->long_name
) print_str ("format_long_name", fmt_ctx
->iformat
->long_name
);
2352 else print_str_opt("format_long_name", "unknown");
2354 print_time("start_time", fmt_ctx
->start_time
, &AV_TIME_BASE_Q
);
2355 print_time("duration", fmt_ctx
->duration
, &AV_TIME_BASE_Q
);
2356 if (size
>= 0) print_val ("size", size
, unit_byte_str
);
2357 else print_str_opt("size", "N/A");
2358 if (fmt_ctx
->bit_rate
> 0) print_val ("bit_rate", fmt_ctx
->bit_rate
, unit_bit_per_second_str
);
2359 else print_str_opt("bit_rate", "N/A");
2360 print_int("probe_score", av_format_get_probe_score(fmt_ctx
));
2361 if (do_show_format_tags
)
2362 ret
= show_tags(w
, fmt_ctx
->metadata
, SECTION_ID_FORMAT_TAGS
);
2364 writer_print_section_footer(w
);
2369 static void show_error(WriterContext
*w
, int err
)
2372 const char *errbuf_ptr
= errbuf
;
2374 if (av_strerror(err
, errbuf
, sizeof(errbuf
)) < 0)
2375 errbuf_ptr
= strerror(AVUNERROR(err
));
2377 writer_print_section_header(w
, SECTION_ID_ERROR
);
2378 print_int("code", err
);
2379 print_str("string", errbuf_ptr
);
2380 writer_print_section_footer(w
);
2383 static int open_input_file(AVFormatContext
**fmt_ctx_ptr
, const char *filename
)
2385 int err
, i
, orig_nb_streams
;
2386 AVFormatContext
*fmt_ctx
= NULL
;
2387 AVDictionaryEntry
*t
;
2388 AVDictionary
**opts
;
2389 int scan_all_pmts_set
= 0;
2391 if (!av_dict_get(format_opts
, "scan_all_pmts", NULL
, AV_DICT_MATCH_CASE
)) {
2392 av_dict_set(&format_opts
, "scan_all_pmts", "1", AV_DICT_DONT_OVERWRITE
);
2393 scan_all_pmts_set
= 1;
2395 if ((err
= avformat_open_input(&fmt_ctx
, filename
,
2396 iformat
, &format_opts
)) < 0) {
2397 print_error(filename
, err
);
2400 if (scan_all_pmts_set
)
2401 av_dict_set(&format_opts
, "scan_all_pmts", NULL
, AV_DICT_MATCH_CASE
);
2402 if ((t
= av_dict_get(format_opts
, "", NULL
, AV_DICT_IGNORE_SUFFIX
))) {
2403 av_log(NULL
, AV_LOG_ERROR
, "Option %s not found.\n", t
->key
);
2404 return AVERROR_OPTION_NOT_FOUND
;
2407 /* fill the streams in the format context */
2408 opts
= setup_find_stream_info_opts(fmt_ctx
, codec_opts
);
2409 orig_nb_streams
= fmt_ctx
->nb_streams
;
2411 if ((err
= avformat_find_stream_info(fmt_ctx
, opts
)) < 0) {
2412 print_error(filename
, err
);
2415 for (i
= 0; i
< orig_nb_streams
; i
++)
2416 av_dict_free(&opts
[i
]);
2419 av_dump_format(fmt_ctx
, 0, filename
, 0);
2421 /* bind a decoder to each input stream */
2422 for (i
= 0; i
< fmt_ctx
->nb_streams
; i
++) {
2423 AVStream
*stream
= fmt_ctx
->streams
[i
];
2426 if (stream
->codec
->codec_id
== AV_CODEC_ID_PROBE
) {
2427 av_log(NULL
, AV_LOG_WARNING
,
2428 "Failed to probe codec for input stream %d\n",
2430 } else if (!(codec
= avcodec_find_decoder(stream
->codec
->codec_id
))) {
2431 av_log(NULL
, AV_LOG_WARNING
,
2432 "Unsupported codec with id %d for input stream %d\n",
2433 stream
->codec
->codec_id
, stream
->index
);
2435 AVDictionary
*opts
= filter_codec_opts(codec_opts
, stream
->codec
->codec_id
,
2436 fmt_ctx
, stream
, codec
);
2437 if (avcodec_open2(stream
->codec
, codec
, &opts
) < 0) {
2438 av_log(NULL
, AV_LOG_WARNING
, "Could not open codec for input stream %d\n",
2441 if ((t
= av_dict_get(opts
, "", NULL
, AV_DICT_IGNORE_SUFFIX
))) {
2442 av_log(NULL
, AV_LOG_ERROR
, "Option %s for input stream %d not found\n",
2443 t
->key
, stream
->index
);
2444 return AVERROR_OPTION_NOT_FOUND
;
2449 *fmt_ctx_ptr
= fmt_ctx
;
2453 static void close_input_file(AVFormatContext
**ctx_ptr
)
2456 AVFormatContext
*fmt_ctx
= *ctx_ptr
;
2458 /* close decoder for each stream */
2459 for (i
= 0; i
< fmt_ctx
->nb_streams
; i
++)
2460 if (fmt_ctx
->streams
[i
]->codec
->codec_id
!= AV_CODEC_ID_NONE
)
2461 avcodec_close(fmt_ctx
->streams
[i
]->codec
);
2463 avformat_close_input(ctx_ptr
);
2466 static int probe_file(WriterContext
*wctx
, const char *filename
)
2468 AVFormatContext
*fmt_ctx
;
2472 do_read_frames
= do_show_frames
|| do_count_frames
;
2473 do_read_packets
= do_show_packets
|| do_count_packets
;
2475 ret
= open_input_file(&fmt_ctx
, filename
);
2479 #define CHECK_END if (ret < 0) goto end
2481 nb_streams
= fmt_ctx
->nb_streams
;
2482 REALLOCZ_ARRAY_STREAM(nb_streams_frames
,0,fmt_ctx
->nb_streams
);
2483 REALLOCZ_ARRAY_STREAM(nb_streams_packets
,0,fmt_ctx
->nb_streams
);
2484 REALLOCZ_ARRAY_STREAM(selected_streams
,0,fmt_ctx
->nb_streams
);
2486 for (i
= 0; i
< fmt_ctx
->nb_streams
; i
++) {
2487 if (stream_specifier
) {
2488 ret
= avformat_match_stream_specifier(fmt_ctx
,
2489 fmt_ctx
->streams
[i
],
2493 selected_streams
[i
] = ret
;
2496 selected_streams
[i
] = 1;
2500 if (do_read_frames
|| do_read_packets
) {
2501 if (do_show_frames
&& do_show_packets
&&
2502 wctx
->writer
->flags
& WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER
)
2503 section_id
= SECTION_ID_PACKETS_AND_FRAMES
;
2504 else if (do_show_packets
&& !do_show_frames
)
2505 section_id
= SECTION_ID_PACKETS
;
2506 else // (!do_show_packets && do_show_frames)
2507 section_id
= SECTION_ID_FRAMES
;
2508 if (do_show_frames
|| do_show_packets
)
2509 writer_print_section_header(wctx
, section_id
);
2510 ret
= read_packets(wctx
, fmt_ctx
);
2511 if (do_show_frames
|| do_show_packets
)
2512 writer_print_section_footer(wctx
);
2516 if (do_show_programs
) {
2517 ret
= show_programs(wctx
, fmt_ctx
);
2521 if (do_show_streams
) {
2522 ret
= show_streams(wctx
, fmt_ctx
);
2525 if (do_show_chapters
) {
2526 ret
= show_chapters(wctx
, fmt_ctx
);
2529 if (do_show_format
) {
2530 ret
= show_format(wctx
, fmt_ctx
);
2535 close_input_file(&fmt_ctx
);
2536 av_freep(&nb_streams_frames
);
2537 av_freep(&nb_streams_packets
);
2538 av_freep(&selected_streams
);
2543 static void show_usage(void)
2545 av_log(NULL
, AV_LOG_INFO
, "Simple multimedia streams analyzer\n");
2546 av_log(NULL
, AV_LOG_INFO
, "usage: %s [OPTIONS] [INPUT_FILE]\n", program_name
);
2547 av_log(NULL
, AV_LOG_INFO
, "\n");
2550 static void ffprobe_show_program_version(WriterContext
*w
)
2553 av_bprint_init(&pbuf
, 1, AV_BPRINT_SIZE_UNLIMITED
);
2555 writer_print_section_header(w
, SECTION_ID_PROGRAM_VERSION
);
2556 print_str("version", FFMPEG_VERSION
);
2557 print_fmt("copyright", "Copyright (c) %d-%d the FFmpeg developers",
2558 program_birth_year
, CONFIG_THIS_YEAR
);
2559 print_str("build_date", __DATE__
);
2560 print_str("build_time", __TIME__
);
2561 print_str("compiler_ident", CC_IDENT
);
2562 print_str("configuration", FFMPEG_CONFIGURATION
);
2563 writer_print_section_footer(w
);
2565 av_bprint_finalize(&pbuf
, NULL
);
2568 #define SHOW_LIB_VERSION(libname, LIBNAME) \
2570 if (CONFIG_##LIBNAME) { \
2571 unsigned int version = libname##_version(); \
2572 writer_print_section_header(w, SECTION_ID_LIBRARY_VERSION); \
2573 print_str("name", "lib" #libname); \
2574 print_int("major", LIB##LIBNAME##_VERSION_MAJOR); \
2575 print_int("minor", LIB##LIBNAME##_VERSION_MINOR); \
2576 print_int("micro", LIB##LIBNAME##_VERSION_MICRO); \
2577 print_int("version", version); \
2578 print_str("ident", LIB##LIBNAME##_IDENT); \
2579 writer_print_section_footer(w); \
2583 static void ffprobe_show_library_versions(WriterContext
*w
)
2585 writer_print_section_header(w
, SECTION_ID_LIBRARY_VERSIONS
);
2586 SHOW_LIB_VERSION(avutil
, AVUTIL
);
2587 SHOW_LIB_VERSION(avcodec
, AVCODEC
);
2588 SHOW_LIB_VERSION(avformat
, AVFORMAT
);
2589 SHOW_LIB_VERSION(avdevice
, AVDEVICE
);
2590 SHOW_LIB_VERSION(avfilter
, AVFILTER
);
2591 SHOW_LIB_VERSION(swscale
, SWSCALE
);
2592 SHOW_LIB_VERSION(swresample
, SWRESAMPLE
);
2593 SHOW_LIB_VERSION(postproc
, POSTPROC
);
2594 writer_print_section_footer(w
);
2597 #define PRINT_PIX_FMT_FLAG(flagname, name) \
2599 print_int(name, !!(pixdesc->flags & AV_PIX_FMT_FLAG_##flagname)); \
2602 static void ffprobe_show_pixel_formats(WriterContext
*w
)
2604 const AVPixFmtDescriptor
*pixdesc
= NULL
;
2607 writer_print_section_header(w
, SECTION_ID_PIXEL_FORMATS
);
2608 while (pixdesc
= av_pix_fmt_desc_next(pixdesc
)) {
2609 writer_print_section_header(w
, SECTION_ID_PIXEL_FORMAT
);
2610 print_str("name", pixdesc
->name
);
2611 print_int("nb_components", pixdesc
->nb_components
);
2612 if ((pixdesc
->nb_components
>= 3) && !(pixdesc
->flags
& AV_PIX_FMT_FLAG_RGB
)) {
2613 print_int ("log2_chroma_w", pixdesc
->log2_chroma_w
);
2614 print_int ("log2_chroma_h", pixdesc
->log2_chroma_h
);
2616 print_str_opt("log2_chroma_w", "N/A");
2617 print_str_opt("log2_chroma_h", "N/A");
2619 n
= av_get_bits_per_pixel(pixdesc
);
2620 if (n
) print_int ("bits_per_pixel", n
);
2621 else print_str_opt("bits_per_pixel", "N/A");
2622 if (do_show_pixel_format_flags
) {
2623 writer_print_section_header(w
, SECTION_ID_PIXEL_FORMAT_FLAGS
);
2624 PRINT_PIX_FMT_FLAG(BE
, "big_endian");
2625 PRINT_PIX_FMT_FLAG(PAL
, "palette");
2626 PRINT_PIX_FMT_FLAG(BITSTREAM
, "bitstream");
2627 PRINT_PIX_FMT_FLAG(HWACCEL
, "hwaccel");
2628 PRINT_PIX_FMT_FLAG(PLANAR
, "planar");
2629 PRINT_PIX_FMT_FLAG(RGB
, "rgb");
2630 PRINT_PIX_FMT_FLAG(PSEUDOPAL
, "pseudopal");
2631 PRINT_PIX_FMT_FLAG(ALPHA
, "alpha");
2632 writer_print_section_footer(w
);
2634 if (do_show_pixel_format_components
&& (pixdesc
->nb_components
> 0)) {
2635 writer_print_section_header(w
, SECTION_ID_PIXEL_FORMAT_COMPONENTS
);
2636 for (i
= 0; i
< pixdesc
->nb_components
; i
++) {
2637 writer_print_section_header(w
, SECTION_ID_PIXEL_FORMAT_COMPONENT
);
2638 print_int("index", i
+ 1);
2639 print_int("bit_depth", pixdesc
->comp
[i
].depth_minus1
+ 1);
2640 writer_print_section_footer(w
);
2642 writer_print_section_footer(w
);
2644 writer_print_section_footer(w
);
2646 writer_print_section_footer(w
);
2649 static int opt_format(void *optctx
, const char *opt
, const char *arg
)
2651 iformat
= av_find_input_format(arg
);
2653 av_log(NULL
, AV_LOG_ERROR
, "Unknown input format: %s\n", arg
);
2654 return AVERROR(EINVAL
);
2659 static inline void mark_section_show_entries(SectionID section_id
,
2660 int show_all_entries
, AVDictionary
*entries
)
2662 struct section
*section
= §ions
[section_id
];
2664 section
->show_all_entries
= show_all_entries
;
2665 if (show_all_entries
) {
2667 for (id
= section
->children_ids
; *id
!= -1; id
++)
2668 mark_section_show_entries(*id
, show_all_entries
, entries
);
2670 av_dict_copy(§ion
->entries_to_show
, entries
, 0);
2674 static int match_section(const char *section_name
,
2675 int show_all_entries
, AVDictionary
*entries
)
2679 for (i
= 0; i
< FF_ARRAY_ELEMS(sections
); i
++) {
2680 const struct section
*section
= §ions
[i
];
2681 if (!strcmp(section_name
, section
->name
) ||
2682 (section
->unique_name
&& !strcmp(section_name
, section
->unique_name
))) {
2683 av_log(NULL
, AV_LOG_DEBUG
,
2684 "'%s' matches section with unique name '%s'\n", section_name
,
2685 (char *)av_x_if_null(section
->unique_name
, section
->name
));
2687 mark_section_show_entries(section
->id
, show_all_entries
, entries
);
2693 static int opt_show_entries(void *optctx
, const char *opt
, const char *arg
)
2695 const char *p
= arg
;
2699 AVDictionary
*entries
= NULL
;
2700 char *section_name
= av_get_token(&p
, "=:");
2701 int show_all_entries
= 0;
2703 if (!section_name
) {
2704 av_log(NULL
, AV_LOG_ERROR
,
2705 "Missing section name for option '%s'\n", opt
);
2706 return AVERROR(EINVAL
);
2711 while (*p
&& *p
!= ':') {
2712 char *entry
= av_get_token(&p
, ",:");
2715 av_log(NULL
, AV_LOG_VERBOSE
,
2716 "Adding '%s' to the entries to show in section '%s'\n",
2717 entry
, section_name
);
2718 av_dict_set(&entries
, entry
, "", AV_DICT_DONT_STRDUP_KEY
);
2723 show_all_entries
= 1;
2726 ret
= match_section(section_name
, show_all_entries
, entries
);
2728 av_log(NULL
, AV_LOG_ERROR
, "No match for section '%s'\n", section_name
);
2729 ret
= AVERROR(EINVAL
);
2731 av_dict_free(&entries
);
2732 av_free(section_name
);
2743 static int opt_show_format_entry(void *optctx
, const char *opt
, const char *arg
)
2745 char *buf
= av_asprintf("format=%s", arg
);
2748 av_log(NULL
, AV_LOG_WARNING
,
2749 "Option '%s' is deprecated, use '-show_entries format=%s' instead\n",
2751 ret
= opt_show_entries(optctx
, opt
, buf
);
2756 static void opt_input_file(void *optctx
, const char *arg
)
2758 if (input_filename
) {
2759 av_log(NULL
, AV_LOG_ERROR
,
2760 "Argument '%s' provided as input filename, but '%s' was already specified.\n",
2761 arg
, input_filename
);
2764 if (!strcmp(arg
, "-"))
2766 input_filename
= arg
;
2769 static int opt_input_file_i(void *optctx
, const char *opt
, const char *arg
)
2771 opt_input_file(optctx
, arg
);
2775 void show_help_default(const char *opt
, const char *arg
)
2777 av_log_set_callback(log_callback_help
);
2779 show_help_options(options
, "Main options:", 0, 0, 0);
2782 show_help_children(avformat_get_class(), AV_OPT_FLAG_DECODING_PARAM
);
2786 * Parse interval specification, according to the format:
2787 * INTERVAL ::= [START|+START_OFFSET][%[END|+END_OFFSET]]
2788 * INTERVALS ::= INTERVAL[,INTERVALS]
2790 static int parse_read_interval(const char *interval_spec
,
2791 ReadInterval
*interval
)
2794 char *next
, *p
, *spec
= av_strdup(interval_spec
);
2796 return AVERROR(ENOMEM
);
2799 av_log(NULL
, AV_LOG_ERROR
, "Invalid empty interval specification\n");
2800 ret
= AVERROR(EINVAL
);
2805 next
= strchr(spec
, '%');
2809 /* parse first part */
2811 interval
->has_start
= 1;
2814 interval
->start_is_offset
= 1;
2817 interval
->start_is_offset
= 0;
2820 ret
= av_parse_time(&interval
->start
, p
, 1);
2822 av_log(NULL
, AV_LOG_ERROR
, "Invalid interval start specification '%s'\n", p
);
2826 interval
->has_start
= 0;
2829 /* parse second part */
2833 interval
->has_end
= 1;
2836 interval
->end_is_offset
= 1;
2839 interval
->end_is_offset
= 0;
2842 if (interval
->end_is_offset
&& *p
== '#') {
2845 interval
->duration_frames
= 1;
2847 lli
= strtoll(p
, &tail
, 10);
2848 if (*tail
|| lli
< 0) {
2849 av_log(NULL
, AV_LOG_ERROR
,
2850 "Invalid or negative value '%s' for duration number of frames\n", p
);
2853 interval
->end
= lli
;
2855 ret
= av_parse_time(&us
, p
, 1);
2857 av_log(NULL
, AV_LOG_ERROR
, "Invalid interval end/duration specification '%s'\n", p
);
2863 interval
->has_end
= 0;
2871 static int parse_read_intervals(const char *intervals_spec
)
2874 char *p
, *spec
= av_strdup(intervals_spec
);
2876 return AVERROR(ENOMEM
);
2878 /* preparse specification, get number of intervals */
2879 for (n
= 0, p
= spec
; *p
; p
++)
2884 read_intervals
= av_malloc_array(n
, sizeof(*read_intervals
));
2885 if (!read_intervals
) {
2886 ret
= AVERROR(ENOMEM
);
2889 read_intervals_nb
= n
;
2891 /* parse intervals */
2893 for (i
= 0; p
; i
++) {
2896 av_assert0(i
< read_intervals_nb
);
2897 next
= strchr(p
, ',');
2901 read_intervals
[i
].id
= i
;
2902 ret
= parse_read_interval(p
, &read_intervals
[i
]);
2904 av_log(NULL
, AV_LOG_ERROR
, "Error parsing read interval #%d '%s'\n",
2908 av_log(NULL
, AV_LOG_VERBOSE
, "Parsed log interval ");
2909 log_read_interval(&read_intervals
[i
], NULL
, AV_LOG_VERBOSE
);
2912 av_assert0(i
== read_intervals_nb
);
2919 static int opt_read_intervals(void *optctx
, const char *opt
, const char *arg
)
2921 return parse_read_intervals(arg
);
2924 static int opt_pretty(void *optctx
, const char *opt
, const char *arg
)
2926 show_value_unit
= 1;
2927 use_value_prefix
= 1;
2928 use_byte_value_binary_prefix
= 1;
2929 use_value_sexagesimal_format
= 1;
2933 static void print_section(SectionID id
, int level
)
2935 const SectionID
*pid
;
2936 const struct section
*section
= §ions
[id
];
2938 section
->flags
& SECTION_FLAG_IS_WRAPPER
? 'W' : '.',
2939 section
->flags
& SECTION_FLAG_IS_ARRAY
? 'A' : '.',
2940 section
->flags
& SECTION_FLAG_HAS_VARIABLE_FIELDS
? 'V' : '.');
2941 printf("%*c %s", level
* 4, ' ', section
->name
);
2942 if (section
->unique_name
)
2943 printf("/%s", section
->unique_name
);
2946 for (pid
= section
->children_ids
; *pid
!= -1; pid
++)
2947 print_section(*pid
, level
+1);
2950 static int opt_sections(void *optctx
, const char *opt
, const char *arg
)
2952 printf("Sections:\n"
2953 "W.. = Section is a wrapper (contains other sections, no local entries)\n"
2954 ".A. = Section contains an array of elements of the same type\n"
2955 "..V = Section may contain a variable number of fields with variable keys\n"
2956 "FLAGS NAME/UNIQUE_NAME\n"
2958 print_section(SECTION_ID_ROOT
, 0);
2962 static int opt_show_versions(const char *opt
, const char *arg
)
2964 mark_section_show_entries(SECTION_ID_PROGRAM_VERSION
, 1, NULL
);
2965 mark_section_show_entries(SECTION_ID_LIBRARY_VERSION
, 1, NULL
);
2969 #define DEFINE_OPT_SHOW_SECTION(section, target_section_id) \
2970 static int opt_show_##section(const char *opt, const char *arg) \
2972 mark_section_show_entries(SECTION_ID_##target_section_id, 1, NULL); \
2976 DEFINE_OPT_SHOW_SECTION(chapters
, CHAPTERS
);
2977 DEFINE_OPT_SHOW_SECTION(error
, ERROR
);
2978 DEFINE_OPT_SHOW_SECTION(format
, FORMAT
);
2979 DEFINE_OPT_SHOW_SECTION(frames
, FRAMES
);
2980 DEFINE_OPT_SHOW_SECTION(library_versions
, LIBRARY_VERSIONS
);
2981 DEFINE_OPT_SHOW_SECTION(packets
, PACKETS
);
2982 DEFINE_OPT_SHOW_SECTION(pixel_formats
, PIXEL_FORMATS
);
2983 DEFINE_OPT_SHOW_SECTION(program_version
, PROGRAM_VERSION
);
2984 DEFINE_OPT_SHOW_SECTION(streams
, STREAMS
);
2985 DEFINE_OPT_SHOW_SECTION(programs
, PROGRAMS
);
2987 static const OptionDef real_options
[] = {
2988 #include "cmdutils_common_opts.h"
2989 { "f", HAS_ARG
, {.func_arg
= opt_format
}, "force format", "format" },
2990 { "unit", OPT_BOOL
, {&show_value_unit
}, "show unit of the displayed values" },
2991 { "prefix", OPT_BOOL
, {&use_value_prefix
}, "use SI prefixes for the displayed values" },
2992 { "byte_binary_prefix", OPT_BOOL
, {&use_byte_value_binary_prefix
},
2993 "use binary prefixes for byte units" },
2994 { "sexagesimal", OPT_BOOL
, {&use_value_sexagesimal_format
},
2995 "use sexagesimal format HOURS:MM:SS.MICROSECONDS for time units" },
2996 { "pretty", 0, {.func_arg
= opt_pretty
},
2997 "prettify the format of displayed values, make it more human readable" },
2998 { "print_format", OPT_STRING
| HAS_ARG
, {(void*)&print_format
},
2999 "set the output printing format (available formats are: default, compact, csv, flat, ini, json, xml)", "format" },
3000 { "of", OPT_STRING
| HAS_ARG
, {(void*)&print_format
}, "alias for -print_format", "format" },
3001 { "select_streams", OPT_STRING
| HAS_ARG
, {(void*)&stream_specifier
}, "select the specified streams", "stream_specifier" },
3002 { "sections", OPT_EXIT
, {.func_arg
= opt_sections
}, "print sections structure and section information, and exit" },
3003 { "show_data", OPT_BOOL
, {(void*)&do_show_data
}, "show packets data" },
3004 { "show_data_hash", OPT_STRING
| HAS_ARG
, {(void*)&show_data_hash
}, "show packets data hash" },
3005 { "show_error", 0, {(void*)&opt_show_error
}, "show probing error" },
3006 { "show_format", 0, {(void*)&opt_show_format
}, "show format/container info" },
3007 { "show_frames", 0, {(void*)&opt_show_frames
}, "show frames info" },
3008 { "show_format_entry", HAS_ARG
, {.func_arg
= opt_show_format_entry
},
3009 "show a particular entry from the format/container info", "entry" },
3010 { "show_entries", HAS_ARG
, {.func_arg
= opt_show_entries
},
3011 "show a set of specified entries", "entry_list" },
3012 { "show_packets", 0, {(void*)&opt_show_packets
}, "show packets info" },
3013 { "show_programs", 0, {(void*)&opt_show_programs
}, "show programs info" },
3014 { "show_streams", 0, {(void*)&opt_show_streams
}, "show streams info" },
3015 { "show_chapters", 0, {(void*)&opt_show_chapters
}, "show chapters info" },
3016 { "count_frames", OPT_BOOL
, {(void*)&do_count_frames
}, "count the number of frames per stream" },
3017 { "count_packets", OPT_BOOL
, {(void*)&do_count_packets
}, "count the number of packets per stream" },
3018 { "show_program_version", 0, {(void*)&opt_show_program_version
}, "show ffprobe version" },
3019 { "show_library_versions", 0, {(void*)&opt_show_library_versions
}, "show library versions" },
3020 { "show_versions", 0, {(void*)&opt_show_versions
}, "show program and library versions" },
3021 { "show_pixel_formats", 0, {(void*)&opt_show_pixel_formats
}, "show pixel format descriptions" },
3022 { "show_private_data", OPT_BOOL
, {(void*)&show_private_data
}, "show private data" },
3023 { "private", OPT_BOOL
, {(void*)&show_private_data
}, "same as show_private_data" },
3024 { "bitexact", OPT_BOOL
, {&do_bitexact
}, "force bitexact output" },
3025 { "read_intervals", HAS_ARG
, {.func_arg
= opt_read_intervals
}, "set read intervals", "read_intervals" },
3026 { "default", HAS_ARG
| OPT_AUDIO
| OPT_VIDEO
| OPT_EXPERT
, {.func_arg
= opt_default
}, "generic catch all option", "" },
3027 { "i", HAS_ARG
, {.func_arg
= opt_input_file_i
}, "read specified file", "input_file"},
3031 static inline int check_section_show_entries(int section_id
)
3034 struct section
*section
= §ions
[section_id
];
3035 if (sections
[section_id
].show_all_entries
|| sections
[section_id
].entries_to_show
)
3037 for (id
= section
->children_ids
; *id
!= -1; id
++)
3038 if (check_section_show_entries(*id
))
3043 #define SET_DO_SHOW(id, varname) do { \
3044 if (check_section_show_entries(SECTION_ID_##id)) \
3045 do_show_##varname = 1; \
3048 int main(int argc
, char **argv
)
3051 WriterContext
*wctx
;
3053 char *w_name
= NULL
, *w_args
= NULL
;
3056 av_log_set_flags(AV_LOG_SKIP_REPEATED
);
3057 register_exit(ffprobe_cleanup
);
3059 options
= real_options
;
3060 parse_loglevel(argc
, argv
, options
);
3062 avformat_network_init();
3065 avdevice_register_all();
3068 show_banner(argc
, argv
, options
);
3069 parse_options(NULL
, argc
, argv
, options
, opt_input_file
);
3071 /* mark things to show, based on -show_entries */
3072 SET_DO_SHOW(CHAPTERS
, chapters
);
3073 SET_DO_SHOW(ERROR
, error
);
3074 SET_DO_SHOW(FORMAT
, format
);
3075 SET_DO_SHOW(FRAMES
, frames
);
3076 SET_DO_SHOW(LIBRARY_VERSIONS
, library_versions
);
3077 SET_DO_SHOW(PACKETS
, packets
);
3078 SET_DO_SHOW(PIXEL_FORMATS
, pixel_formats
);
3079 SET_DO_SHOW(PIXEL_FORMAT_FLAGS
, pixel_format_flags
);
3080 SET_DO_SHOW(PIXEL_FORMAT_COMPONENTS
, pixel_format_components
);
3081 SET_DO_SHOW(PROGRAM_VERSION
, program_version
);
3082 SET_DO_SHOW(PROGRAMS
, programs
);
3083 SET_DO_SHOW(STREAMS
, streams
);
3084 SET_DO_SHOW(STREAM_DISPOSITION
, stream_disposition
);
3085 SET_DO_SHOW(PROGRAM_STREAM_DISPOSITION
, stream_disposition
);
3087 SET_DO_SHOW(CHAPTER_TAGS
, chapter_tags
);
3088 SET_DO_SHOW(FORMAT_TAGS
, format_tags
);
3089 SET_DO_SHOW(FRAME_TAGS
, frame_tags
);
3090 SET_DO_SHOW(PROGRAM_TAGS
, program_tags
);
3091 SET_DO_SHOW(STREAM_TAGS
, stream_tags
);
3093 if (do_bitexact
&& (do_show_program_version
|| do_show_library_versions
)) {
3094 av_log(NULL
, AV_LOG_ERROR
,
3095 "-bitexact and -show_program_version or -show_library_versions "
3096 "options are incompatible\n");
3097 ret
= AVERROR(EINVAL
);
3101 writer_register_all();
3104 print_format
= av_strdup("default");
3105 if (!print_format
) {
3106 ret
= AVERROR(ENOMEM
);
3109 w_name
= av_strtok(print_format
, "=", &buf
);
3112 if (show_data_hash
) {
3113 if ((ret
= av_hash_alloc(&hash
, show_data_hash
)) < 0) {
3114 if (ret
== AVERROR(EINVAL
)) {
3116 av_log(NULL
, AV_LOG_ERROR
,
3117 "Unknown hash algorithm '%s'\nKnown algorithms:",
3119 for (i
= 0; (n
= av_hash_names(i
)); i
++)
3120 av_log(NULL
, AV_LOG_ERROR
, " %s", n
);
3121 av_log(NULL
, AV_LOG_ERROR
, "\n");
3127 w
= writer_get_by_name(w_name
);
3129 av_log(NULL
, AV_LOG_ERROR
, "Unknown output format with name '%s'\n", w_name
);
3130 ret
= AVERROR(EINVAL
);
3134 if ((ret
= writer_open(&wctx
, w
, w_args
,
3135 sections
, FF_ARRAY_ELEMS(sections
))) >= 0) {
3136 if (w
== &xml_writer
)
3137 wctx
->string_validation_utf8_flags
|= AV_UTF8_FLAG_EXCLUDE_XML_INVALID_CONTROL_CODES
;
3139 writer_print_section_header(wctx
, SECTION_ID_ROOT
);
3141 if (do_show_program_version
)
3142 ffprobe_show_program_version(wctx
);
3143 if (do_show_library_versions
)
3144 ffprobe_show_library_versions(wctx
);
3145 if (do_show_pixel_formats
)
3146 ffprobe_show_pixel_formats(wctx
);
3148 if (!input_filename
&&
3149 ((do_show_format
|| do_show_programs
|| do_show_streams
|| do_show_chapters
|| do_show_packets
|| do_show_error
) ||
3150 (!do_show_program_version
&& !do_show_library_versions
&& !do_show_pixel_formats
))) {
3152 av_log(NULL
, AV_LOG_ERROR
, "You have to specify one input file.\n");
3153 av_log(NULL
, AV_LOG_ERROR
, "Use -h to get full help or, even better, run 'man %s'.\n", program_name
);
3154 ret
= AVERROR(EINVAL
);
3155 } else if (input_filename
) {
3156 ret
= probe_file(wctx
, input_filename
);
3157 if (ret
< 0 && do_show_error
)
3158 show_error(wctx
, ret
);
3161 writer_print_section_footer(wctx
);
3162 writer_close(&wctx
);
3166 av_freep(&print_format
);
3167 av_freep(&read_intervals
);
3168 av_hash_freep(&hash
);
3171 for (i
= 0; i
< FF_ARRAY_ELEMS(sections
); i
++)
3172 av_dict_free(&(sections
[i
].entries_to_show
));
3174 avformat_network_deinit();