]> git.sesse.net Git - ffmpeg/blob - ffprobe.c
lavf/avidec: Add blurb regarding the skipping of xxpc entries in the index
[ffmpeg] / ffprobe.c
1 /*
2  * Copyright (c) 2007-2010 Stefano Sabatini
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20
21 /**
22  * @file
23  * simple media prober based on the FFmpeg libraries
24  */
25
26 #include "config.h"
27 #include "libavutil/ffversion.h"
28
29 #include <string.h>
30
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/display.h"
37 #include "libavutil/hash.h"
38 #include "libavutil/opt.h"
39 #include "libavutil/pixdesc.h"
40 #include "libavutil/dict.h"
41 #include "libavutil/intreadwrite.h"
42 #include "libavutil/libm.h"
43 #include "libavutil/parseutils.h"
44 #include "libavutil/timecode.h"
45 #include "libavutil/timestamp.h"
46 #include "libavdevice/avdevice.h"
47 #include "libswscale/swscale.h"
48 #include "libswresample/swresample.h"
49 #include "libpostproc/postprocess.h"
50 #include "cmdutils.h"
51
52 const char program_name[] = "ffprobe";
53 const int program_birth_year = 2007;
54
55 static int do_bitexact = 0;
56 static int do_count_frames = 0;
57 static int do_count_packets = 0;
58 static int do_read_frames  = 0;
59 static int do_read_packets = 0;
60 static int do_show_chapters = 0;
61 static int do_show_error   = 0;
62 static int do_show_format  = 0;
63 static int do_show_frames  = 0;
64 static int do_show_packets = 0;
65 static int do_show_programs = 0;
66 static int do_show_streams = 0;
67 static int do_show_stream_disposition = 0;
68 static int do_show_data    = 0;
69 static int do_show_program_version  = 0;
70 static int do_show_library_versions = 0;
71 static int do_show_pixel_formats = 0;
72 static int do_show_pixel_format_flags = 0;
73 static int do_show_pixel_format_components = 0;
74
75 static int do_show_chapter_tags = 0;
76 static int do_show_format_tags = 0;
77 static int do_show_frame_tags = 0;
78 static int do_show_program_tags = 0;
79 static int do_show_stream_tags = 0;
80 static int do_show_packet_tags = 0;
81
82 static int show_value_unit              = 0;
83 static int use_value_prefix             = 0;
84 static int use_byte_value_binary_prefix = 0;
85 static int use_value_sexagesimal_format = 0;
86 static int show_private_data            = 1;
87
88 static char *print_format;
89 static char *stream_specifier;
90 static char *show_data_hash;
91
92 typedef struct ReadInterval {
93     int id;             ///< identifier
94     int64_t start, end; ///< start, end in second/AV_TIME_BASE units
95     int has_start, has_end;
96     int start_is_offset, end_is_offset;
97     int duration_frames;
98 } ReadInterval;
99
100 static ReadInterval *read_intervals;
101 static int read_intervals_nb = 0;
102
103 /* section structure definition */
104
105 #define SECTION_MAX_NB_CHILDREN 10
106
107 struct section {
108     int id;             ///< unique id identifying a section
109     const char *name;
110
111 #define SECTION_FLAG_IS_WRAPPER      1 ///< the section only contains other sections, but has no data at its own level
112 #define SECTION_FLAG_IS_ARRAY        2 ///< the section contains an array of elements of the same type
113 #define SECTION_FLAG_HAS_VARIABLE_FIELDS 4 ///< the section may contain a variable number of fields with variable keys.
114                                            ///  For these sections the element_name field is mandatory.
115     int flags;
116     int children_ids[SECTION_MAX_NB_CHILDREN+1]; ///< list of children section IDS, terminated by -1
117     const char *element_name; ///< name of the contained element, if provided
118     const char *unique_name;  ///< unique section name, in case the name is ambiguous
119     AVDictionary *entries_to_show;
120     int show_all_entries;
121 };
122
123 typedef enum {
124     SECTION_ID_NONE = -1,
125     SECTION_ID_CHAPTER,
126     SECTION_ID_CHAPTER_TAGS,
127     SECTION_ID_CHAPTERS,
128     SECTION_ID_ERROR,
129     SECTION_ID_FORMAT,
130     SECTION_ID_FORMAT_TAGS,
131     SECTION_ID_FRAME,
132     SECTION_ID_FRAMES,
133     SECTION_ID_FRAME_TAGS,
134     SECTION_ID_FRAME_SIDE_DATA_LIST,
135     SECTION_ID_FRAME_SIDE_DATA,
136     SECTION_ID_LIBRARY_VERSION,
137     SECTION_ID_LIBRARY_VERSIONS,
138     SECTION_ID_PACKET,
139     SECTION_ID_PACKET_TAGS,
140     SECTION_ID_PACKETS,
141     SECTION_ID_PACKETS_AND_FRAMES,
142     SECTION_ID_PACKET_SIDE_DATA_LIST,
143     SECTION_ID_PACKET_SIDE_DATA,
144     SECTION_ID_PIXEL_FORMAT,
145     SECTION_ID_PIXEL_FORMAT_FLAGS,
146     SECTION_ID_PIXEL_FORMAT_COMPONENT,
147     SECTION_ID_PIXEL_FORMAT_COMPONENTS,
148     SECTION_ID_PIXEL_FORMATS,
149     SECTION_ID_PROGRAM_STREAM_DISPOSITION,
150     SECTION_ID_PROGRAM_STREAM_TAGS,
151     SECTION_ID_PROGRAM,
152     SECTION_ID_PROGRAM_STREAMS,
153     SECTION_ID_PROGRAM_STREAM,
154     SECTION_ID_PROGRAM_TAGS,
155     SECTION_ID_PROGRAM_VERSION,
156     SECTION_ID_PROGRAMS,
157     SECTION_ID_ROOT,
158     SECTION_ID_STREAM,
159     SECTION_ID_STREAM_DISPOSITION,
160     SECTION_ID_STREAMS,
161     SECTION_ID_STREAM_TAGS,
162     SECTION_ID_STREAM_SIDE_DATA_LIST,
163     SECTION_ID_STREAM_SIDE_DATA,
164     SECTION_ID_SUBTITLE,
165 } SectionID;
166
167 static struct section sections[] = {
168     [SECTION_ID_CHAPTERS] =           { SECTION_ID_CHAPTERS, "chapters", SECTION_FLAG_IS_ARRAY, { SECTION_ID_CHAPTER, -1 } },
169     [SECTION_ID_CHAPTER] =            { SECTION_ID_CHAPTER, "chapter", 0, { SECTION_ID_CHAPTER_TAGS, -1 } },
170     [SECTION_ID_CHAPTER_TAGS] =       { SECTION_ID_CHAPTER_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "chapter_tags" },
171     [SECTION_ID_ERROR] =              { SECTION_ID_ERROR, "error", 0, { -1 } },
172     [SECTION_ID_FORMAT] =             { SECTION_ID_FORMAT, "format", 0, { SECTION_ID_FORMAT_TAGS, -1 } },
173     [SECTION_ID_FORMAT_TAGS] =        { SECTION_ID_FORMAT_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "format_tags" },
174     [SECTION_ID_FRAMES] =             { SECTION_ID_FRAMES, "frames", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME, SECTION_ID_SUBTITLE, -1 } },
175     [SECTION_ID_FRAME] =              { SECTION_ID_FRAME, "frame", 0, { SECTION_ID_FRAME_TAGS, SECTION_ID_FRAME_SIDE_DATA_LIST, -1 } },
176     [SECTION_ID_FRAME_TAGS] =         { SECTION_ID_FRAME_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "frame_tags" },
177     [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 } },
178     [SECTION_ID_FRAME_SIDE_DATA] =     { SECTION_ID_FRAME_SIDE_DATA, "side_data", 0, { -1 } },
179     [SECTION_ID_LIBRARY_VERSIONS] =   { SECTION_ID_LIBRARY_VERSIONS, "library_versions", SECTION_FLAG_IS_ARRAY, { SECTION_ID_LIBRARY_VERSION, -1 } },
180     [SECTION_ID_LIBRARY_VERSION] =    { SECTION_ID_LIBRARY_VERSION, "library_version", 0, { -1 } },
181     [SECTION_ID_PACKETS] =            { SECTION_ID_PACKETS, "packets", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET, -1} },
182     [SECTION_ID_PACKETS_AND_FRAMES] = { SECTION_ID_PACKETS_AND_FRAMES, "packets_and_frames", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET, -1} },
183     [SECTION_ID_PACKET] =             { SECTION_ID_PACKET, "packet", 0, { SECTION_ID_PACKET_TAGS, SECTION_ID_PACKET_SIDE_DATA_LIST, -1 } },
184     [SECTION_ID_PACKET_TAGS] =        { SECTION_ID_PACKET_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "packet_tags" },
185     [SECTION_ID_PACKET_SIDE_DATA_LIST] ={ SECTION_ID_PACKET_SIDE_DATA_LIST, "side_data_list", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET_SIDE_DATA, -1 } },
186     [SECTION_ID_PACKET_SIDE_DATA] =     { SECTION_ID_PACKET_SIDE_DATA, "side_data", 0, { -1 } },
187     [SECTION_ID_PIXEL_FORMATS] =      { SECTION_ID_PIXEL_FORMATS, "pixel_formats", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PIXEL_FORMAT, -1 } },
188     [SECTION_ID_PIXEL_FORMAT] =       { SECTION_ID_PIXEL_FORMAT, "pixel_format", 0, { SECTION_ID_PIXEL_FORMAT_FLAGS, SECTION_ID_PIXEL_FORMAT_COMPONENTS, -1 } },
189     [SECTION_ID_PIXEL_FORMAT_FLAGS] = { SECTION_ID_PIXEL_FORMAT_FLAGS, "flags", 0, { -1 }, .unique_name = "pixel_format_flags" },
190     [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" },
191     [SECTION_ID_PIXEL_FORMAT_COMPONENT]  = { SECTION_ID_PIXEL_FORMAT_COMPONENT, "component", 0, { -1 } },
192     [SECTION_ID_PROGRAM_STREAM_DISPOSITION] = { SECTION_ID_PROGRAM_STREAM_DISPOSITION, "disposition", 0, { -1 }, .unique_name = "program_stream_disposition" },
193     [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" },
194     [SECTION_ID_PROGRAM] =                    { SECTION_ID_PROGRAM, "program", 0, { SECTION_ID_PROGRAM_TAGS, SECTION_ID_PROGRAM_STREAMS, -1 } },
195     [SECTION_ID_PROGRAM_STREAMS] =            { SECTION_ID_PROGRAM_STREAMS, "streams", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PROGRAM_STREAM, -1 }, .unique_name = "program_streams" },
196     [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" },
197     [SECTION_ID_PROGRAM_TAGS] =               { SECTION_ID_PROGRAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "program_tags" },
198     [SECTION_ID_PROGRAM_VERSION] =    { SECTION_ID_PROGRAM_VERSION, "program_version", 0, { -1 } },
199     [SECTION_ID_PROGRAMS] =                   { SECTION_ID_PROGRAMS, "programs", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PROGRAM, -1 } },
200     [SECTION_ID_ROOT] =               { SECTION_ID_ROOT, "root", SECTION_FLAG_IS_WRAPPER,
201                                         { SECTION_ID_CHAPTERS, SECTION_ID_FORMAT, SECTION_ID_FRAMES, SECTION_ID_PROGRAMS, SECTION_ID_STREAMS,
202                                           SECTION_ID_PACKETS, SECTION_ID_ERROR, SECTION_ID_PROGRAM_VERSION, SECTION_ID_LIBRARY_VERSIONS,
203                                           SECTION_ID_PIXEL_FORMATS, -1} },
204     [SECTION_ID_STREAMS] =            { SECTION_ID_STREAMS, "streams", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM, -1 } },
205     [SECTION_ID_STREAM] =             { SECTION_ID_STREAM, "stream", 0, { SECTION_ID_STREAM_DISPOSITION, SECTION_ID_STREAM_TAGS, SECTION_ID_STREAM_SIDE_DATA_LIST, -1 } },
206     [SECTION_ID_STREAM_DISPOSITION] = { SECTION_ID_STREAM_DISPOSITION, "disposition", 0, { -1 }, .unique_name = "stream_disposition" },
207     [SECTION_ID_STREAM_TAGS] =        { SECTION_ID_STREAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "stream_tags" },
208     [SECTION_ID_STREAM_SIDE_DATA_LIST] ={ SECTION_ID_STREAM_SIDE_DATA_LIST, "side_data_list", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_SIDE_DATA, -1 } },
209     [SECTION_ID_STREAM_SIDE_DATA] =     { SECTION_ID_STREAM_SIDE_DATA, "side_data", 0, { -1 } },
210     [SECTION_ID_SUBTITLE] =           { SECTION_ID_SUBTITLE, "subtitle", 0, { -1 } },
211 };
212
213 static const OptionDef *options;
214
215 /* FFprobe context */
216 static const char *input_filename;
217 static AVInputFormat *iformat = NULL;
218
219 static struct AVHashContext *hash;
220
221 static const struct {
222     double bin_val;
223     double dec_val;
224     const char *bin_str;
225     const char *dec_str;
226 } si_prefixes[] = {
227     { 1.0, 1.0, "", "" },
228     { 1.024e3, 1e3, "Ki", "K" },
229     { 1.048576e6, 1e6, "Mi", "M" },
230     { 1.073741824e9, 1e9, "Gi", "G" },
231     { 1.099511627776e12, 1e12, "Ti", "T" },
232     { 1.125899906842624e15, 1e15, "Pi", "P" },
233 };
234
235 static const char unit_second_str[]         = "s"    ;
236 static const char unit_hertz_str[]          = "Hz"   ;
237 static const char unit_byte_str[]           = "byte" ;
238 static const char unit_bit_per_second_str[] = "bit/s";
239
240 static int nb_streams;
241 static uint64_t *nb_streams_packets;
242 static uint64_t *nb_streams_frames;
243 static int *selected_streams;
244
245 static void ffprobe_cleanup(int ret)
246 {
247     int i;
248     for (i = 0; i < FF_ARRAY_ELEMS(sections); i++)
249         av_dict_free(&(sections[i].entries_to_show));
250 }
251
252 struct unit_value {
253     union { double d; long long int i; } val;
254     const char *unit;
255 };
256
257 static char *value_string(char *buf, int buf_size, struct unit_value uv)
258 {
259     double vald;
260     long long int vali;
261     int show_float = 0;
262
263     if (uv.unit == unit_second_str) {
264         vald = uv.val.d;
265         show_float = 1;
266     } else {
267         vald = vali = uv.val.i;
268     }
269
270     if (uv.unit == unit_second_str && use_value_sexagesimal_format) {
271         double secs;
272         int hours, mins;
273         secs  = vald;
274         mins  = (int)secs / 60;
275         secs  = secs - mins * 60;
276         hours = mins / 60;
277         mins %= 60;
278         snprintf(buf, buf_size, "%d:%02d:%09.6f", hours, mins, secs);
279     } else {
280         const char *prefix_string = "";
281
282         if (use_value_prefix && vald > 1) {
283             long long int index;
284
285             if (uv.unit == unit_byte_str && use_byte_value_binary_prefix) {
286                 index = (long long int) (log2(vald)) / 10;
287                 index = av_clip(index, 0, FF_ARRAY_ELEMS(si_prefixes) - 1);
288                 vald /= si_prefixes[index].bin_val;
289                 prefix_string = si_prefixes[index].bin_str;
290             } else {
291                 index = (long long int) (log10(vald)) / 3;
292                 index = av_clip(index, 0, FF_ARRAY_ELEMS(si_prefixes) - 1);
293                 vald /= si_prefixes[index].dec_val;
294                 prefix_string = si_prefixes[index].dec_str;
295             }
296             vali = vald;
297         }
298
299         if (show_float || (use_value_prefix && vald != (long long int)vald))
300             snprintf(buf, buf_size, "%f", vald);
301         else
302             snprintf(buf, buf_size, "%lld", vali);
303         av_strlcatf(buf, buf_size, "%s%s%s", *prefix_string || show_value_unit ? " " : "",
304                  prefix_string, show_value_unit ? uv.unit : "");
305     }
306
307     return buf;
308 }
309
310 /* WRITERS API */
311
312 typedef struct WriterContext WriterContext;
313
314 #define WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS 1
315 #define WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER 2
316
317 typedef enum {
318     WRITER_STRING_VALIDATION_FAIL,
319     WRITER_STRING_VALIDATION_REPLACE,
320     WRITER_STRING_VALIDATION_IGNORE,
321     WRITER_STRING_VALIDATION_NB
322 } StringValidation;
323
324 typedef struct Writer {
325     const AVClass *priv_class;      ///< private class of the writer, if any
326     int priv_size;                  ///< private size for the writer context
327     const char *name;
328
329     int  (*init)  (WriterContext *wctx);
330     void (*uninit)(WriterContext *wctx);
331
332     void (*print_section_header)(WriterContext *wctx);
333     void (*print_section_footer)(WriterContext *wctx);
334     void (*print_integer)       (WriterContext *wctx, const char *, long long int);
335     void (*print_rational)      (WriterContext *wctx, AVRational *q, char *sep);
336     void (*print_string)        (WriterContext *wctx, const char *, const char *);
337     int flags;                  ///< a combination or WRITER_FLAG_*
338 } Writer;
339
340 #define SECTION_MAX_NB_LEVELS 10
341
342 struct WriterContext {
343     const AVClass *class;           ///< class of the writer
344     const Writer *writer;           ///< the Writer of which this is an instance
345     char *name;                     ///< name of this writer instance
346     void *priv;                     ///< private data for use by the filter
347
348     const struct section *sections; ///< array containing all sections
349     int nb_sections;                ///< number of sections
350
351     int level;                      ///< current level, starting from 0
352
353     /** number of the item printed in the given section, starting from 0 */
354     unsigned int nb_item[SECTION_MAX_NB_LEVELS];
355
356     /** section per each level */
357     const struct section *section[SECTION_MAX_NB_LEVELS];
358     AVBPrint section_pbuf[SECTION_MAX_NB_LEVELS]; ///< generic print buffer dedicated to each section,
359                                                   ///  used by various writers
360
361     unsigned int nb_section_packet; ///< number of the packet section in case we are in "packets_and_frames" section
362     unsigned int nb_section_frame;  ///< number of the frame  section in case we are in "packets_and_frames" section
363     unsigned int nb_section_packet_frame; ///< nb_section_packet or nb_section_frame according if is_packets_and_frames
364
365     int string_validation;
366     char *string_validation_replacement;
367     unsigned int string_validation_utf8_flags;
368 };
369
370 static const char *writer_get_name(void *p)
371 {
372     WriterContext *wctx = p;
373     return wctx->writer->name;
374 }
375
376 #define OFFSET(x) offsetof(WriterContext, x)
377
378 static const AVOption writer_options[] = {
379     { "string_validation", "set string validation mode",
380       OFFSET(string_validation), AV_OPT_TYPE_INT, {.i64=WRITER_STRING_VALIDATION_REPLACE}, 0, WRITER_STRING_VALIDATION_NB-1, .unit = "sv" },
381     { "sv", "set string validation mode",
382       OFFSET(string_validation), AV_OPT_TYPE_INT, {.i64=WRITER_STRING_VALIDATION_REPLACE}, 0, WRITER_STRING_VALIDATION_NB-1, .unit = "sv" },
383     { "ignore",  NULL, 0, AV_OPT_TYPE_CONST, {.i64 = WRITER_STRING_VALIDATION_IGNORE},  .unit = "sv" },
384     { "replace", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = WRITER_STRING_VALIDATION_REPLACE}, .unit = "sv" },
385     { "fail",    NULL, 0, AV_OPT_TYPE_CONST, {.i64 = WRITER_STRING_VALIDATION_FAIL},    .unit = "sv" },
386     { "string_validation_replacement", "set string validation replacement string", OFFSET(string_validation_replacement), AV_OPT_TYPE_STRING, {.str=""}},
387     { "svr", "set string validation replacement string", OFFSET(string_validation_replacement), AV_OPT_TYPE_STRING, {.str="\xEF\xBF\xBD"}},
388     { NULL }
389 };
390
391 static void *writer_child_next(void *obj, void *prev)
392 {
393     WriterContext *ctx = obj;
394     if (!prev && ctx->writer && ctx->writer->priv_class && ctx->priv)
395         return ctx->priv;
396     return NULL;
397 }
398
399 static const AVClass writer_class = {
400     .class_name = "Writer",
401     .item_name  = writer_get_name,
402     .option     = writer_options,
403     .version    = LIBAVUTIL_VERSION_INT,
404     .child_next = writer_child_next,
405 };
406
407 static void writer_close(WriterContext **wctx)
408 {
409     int i;
410
411     if (!*wctx)
412         return;
413
414     if ((*wctx)->writer->uninit)
415         (*wctx)->writer->uninit(*wctx);
416     for (i = 0; i < SECTION_MAX_NB_LEVELS; i++)
417         av_bprint_finalize(&(*wctx)->section_pbuf[i], NULL);
418     if ((*wctx)->writer->priv_class)
419         av_opt_free((*wctx)->priv);
420     av_freep(&((*wctx)->priv));
421     av_opt_free(*wctx);
422     av_freep(wctx);
423 }
424
425 static void bprint_bytes(AVBPrint *bp, const uint8_t *ubuf, size_t ubuf_size)
426 {
427     int i;
428     av_bprintf(bp, "0X");
429     for (i = 0; i < ubuf_size; i++)
430         av_bprintf(bp, "%02X", ubuf[i]);
431 }
432
433
434 static int writer_open(WriterContext **wctx, const Writer *writer, const char *args,
435                        const struct section *sections, int nb_sections)
436 {
437     int i, ret = 0;
438
439     if (!(*wctx = av_mallocz(sizeof(WriterContext)))) {
440         ret = AVERROR(ENOMEM);
441         goto fail;
442     }
443
444     if (!((*wctx)->priv = av_mallocz(writer->priv_size))) {
445         ret = AVERROR(ENOMEM);
446         goto fail;
447     }
448
449     (*wctx)->class = &writer_class;
450     (*wctx)->writer = writer;
451     (*wctx)->level = -1;
452     (*wctx)->sections = sections;
453     (*wctx)->nb_sections = nb_sections;
454
455     av_opt_set_defaults(*wctx);
456
457     if (writer->priv_class) {
458         void *priv_ctx = (*wctx)->priv;
459         *((const AVClass **)priv_ctx) = writer->priv_class;
460         av_opt_set_defaults(priv_ctx);
461     }
462
463     /* convert options to dictionary */
464     if (args) {
465         AVDictionary *opts = NULL;
466         AVDictionaryEntry *opt = NULL;
467
468         if ((ret = av_dict_parse_string(&opts, args, "=", ":", 0)) < 0) {
469             av_log(*wctx, AV_LOG_ERROR, "Failed to parse option string '%s' provided to writer context\n", args);
470             av_dict_free(&opts);
471             goto fail;
472         }
473
474         while ((opt = av_dict_get(opts, "", opt, AV_DICT_IGNORE_SUFFIX))) {
475             if ((ret = av_opt_set(*wctx, opt->key, opt->value, AV_OPT_SEARCH_CHILDREN)) < 0) {
476                 av_log(*wctx, AV_LOG_ERROR, "Failed to set option '%s' with value '%s' provided to writer context\n",
477                        opt->key, opt->value);
478                 av_dict_free(&opts);
479                 goto fail;
480             }
481         }
482
483         av_dict_free(&opts);
484     }
485
486     /* validate replace string */
487     {
488         const uint8_t *p = (*wctx)->string_validation_replacement;
489         const uint8_t *endp = p + strlen(p);
490         while (*p) {
491             const uint8_t *p0 = p;
492             int32_t code;
493             ret = av_utf8_decode(&code, &p, endp, (*wctx)->string_validation_utf8_flags);
494             if (ret < 0) {
495                 AVBPrint bp;
496                 av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC);
497                 bprint_bytes(&bp, p0, p-p0),
498                     av_log(wctx, AV_LOG_ERROR,
499                            "Invalid UTF8 sequence %s found in string validation replace '%s'\n",
500                            bp.str, (*wctx)->string_validation_replacement);
501                 return ret;
502             }
503         }
504     }
505
506     for (i = 0; i < SECTION_MAX_NB_LEVELS; i++)
507         av_bprint_init(&(*wctx)->section_pbuf[i], 1, AV_BPRINT_SIZE_UNLIMITED);
508
509     if ((*wctx)->writer->init)
510         ret = (*wctx)->writer->init(*wctx);
511     if (ret < 0)
512         goto fail;
513
514     return 0;
515
516 fail:
517     writer_close(wctx);
518     return ret;
519 }
520
521 static inline void writer_print_section_header(WriterContext *wctx,
522                                                int section_id)
523 {
524     int parent_section_id;
525     wctx->level++;
526     av_assert0(wctx->level < SECTION_MAX_NB_LEVELS);
527     parent_section_id = wctx->level ?
528         (wctx->section[wctx->level-1])->id : SECTION_ID_NONE;
529
530     wctx->nb_item[wctx->level] = 0;
531     wctx->section[wctx->level] = &wctx->sections[section_id];
532
533     if (section_id == SECTION_ID_PACKETS_AND_FRAMES) {
534         wctx->nb_section_packet = wctx->nb_section_frame =
535         wctx->nb_section_packet_frame = 0;
536     } else if (parent_section_id == SECTION_ID_PACKETS_AND_FRAMES) {
537         wctx->nb_section_packet_frame = section_id == SECTION_ID_PACKET ?
538             wctx->nb_section_packet : wctx->nb_section_frame;
539     }
540
541     if (wctx->writer->print_section_header)
542         wctx->writer->print_section_header(wctx);
543 }
544
545 static inline void writer_print_section_footer(WriterContext *wctx)
546 {
547     int section_id = wctx->section[wctx->level]->id;
548     int parent_section_id = wctx->level ?
549         wctx->section[wctx->level-1]->id : SECTION_ID_NONE;
550
551     if (parent_section_id != SECTION_ID_NONE)
552         wctx->nb_item[wctx->level-1]++;
553     if (parent_section_id == SECTION_ID_PACKETS_AND_FRAMES) {
554         if (section_id == SECTION_ID_PACKET) wctx->nb_section_packet++;
555         else                                     wctx->nb_section_frame++;
556     }
557     if (wctx->writer->print_section_footer)
558         wctx->writer->print_section_footer(wctx);
559     wctx->level--;
560 }
561
562 static inline void writer_print_integer(WriterContext *wctx,
563                                         const char *key, long long int val)
564 {
565     const struct section *section = wctx->section[wctx->level];
566
567     if (section->show_all_entries || av_dict_get(section->entries_to_show, key, NULL, 0)) {
568         wctx->writer->print_integer(wctx, key, val);
569         wctx->nb_item[wctx->level]++;
570     }
571 }
572
573 static inline int validate_string(WriterContext *wctx, char **dstp, const char *src)
574 {
575     const uint8_t *p, *endp;
576     AVBPrint dstbuf;
577     int invalid_chars_nb = 0, ret = 0;
578
579     av_bprint_init(&dstbuf, 0, AV_BPRINT_SIZE_UNLIMITED);
580
581     endp = src + strlen(src);
582     for (p = (uint8_t *)src; *p;) {
583         uint32_t code;
584         int invalid = 0;
585         const uint8_t *p0 = p;
586
587         if (av_utf8_decode(&code, &p, endp, wctx->string_validation_utf8_flags) < 0) {
588             AVBPrint bp;
589             av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC);
590             bprint_bytes(&bp, p0, p-p0);
591             av_log(wctx, AV_LOG_DEBUG,
592                    "Invalid UTF-8 sequence %s found in string '%s'\n", bp.str, src);
593             invalid = 1;
594         }
595
596         if (invalid) {
597             invalid_chars_nb++;
598
599             switch (wctx->string_validation) {
600             case WRITER_STRING_VALIDATION_FAIL:
601                 av_log(wctx, AV_LOG_ERROR,
602                        "Invalid UTF-8 sequence found in string '%s'\n", src);
603                 ret = AVERROR_INVALIDDATA;
604                 goto end;
605                 break;
606
607             case WRITER_STRING_VALIDATION_REPLACE:
608                 av_bprintf(&dstbuf, "%s", wctx->string_validation_replacement);
609                 break;
610             }
611         }
612
613         if (!invalid || wctx->string_validation == WRITER_STRING_VALIDATION_IGNORE)
614             av_bprint_append_data(&dstbuf, p0, p-p0);
615     }
616
617     if (invalid_chars_nb && wctx->string_validation == WRITER_STRING_VALIDATION_REPLACE) {
618         av_log(wctx, AV_LOG_WARNING,
619                "%d invalid UTF-8 sequence(s) found in string '%s', replaced with '%s'\n",
620                invalid_chars_nb, src, wctx->string_validation_replacement);
621     }
622
623 end:
624     av_bprint_finalize(&dstbuf, dstp);
625     return ret;
626 }
627
628 #define PRINT_STRING_OPT      1
629 #define PRINT_STRING_VALIDATE 2
630
631 static inline int writer_print_string(WriterContext *wctx,
632                                       const char *key, const char *val, int flags)
633 {
634     const struct section *section = wctx->section[wctx->level];
635     int ret = 0;
636
637     if ((flags & PRINT_STRING_OPT)
638         && !(wctx->writer->flags & WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS))
639         return 0;
640
641     if (section->show_all_entries || av_dict_get(section->entries_to_show, key, NULL, 0)) {
642         if (flags & PRINT_STRING_VALIDATE) {
643             char *key1 = NULL, *val1 = NULL;
644             ret = validate_string(wctx, &key1, key);
645             if (ret < 0) goto end;
646             ret = validate_string(wctx, &val1, val);
647             if (ret < 0) goto end;
648             wctx->writer->print_string(wctx, key1, val1);
649         end:
650             if (ret < 0) {
651                 av_log(wctx, AV_LOG_ERROR,
652                        "Invalid key=value string combination %s=%s in section %s\n",
653                        key, val, section->unique_name);
654             }
655             av_free(key1);
656             av_free(val1);
657         } else {
658             wctx->writer->print_string(wctx, key, val);
659         }
660
661         wctx->nb_item[wctx->level]++;
662     }
663
664     return ret;
665 }
666
667 static inline void writer_print_rational(WriterContext *wctx,
668                                          const char *key, AVRational q, char sep)
669 {
670     AVBPrint buf;
671     av_bprint_init(&buf, 0, AV_BPRINT_SIZE_AUTOMATIC);
672     av_bprintf(&buf, "%d%c%d", q.num, sep, q.den);
673     writer_print_string(wctx, key, buf.str, 0);
674 }
675
676 static void writer_print_time(WriterContext *wctx, const char *key,
677                               int64_t ts, const AVRational *time_base, int is_duration)
678 {
679     char buf[128];
680
681     if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0)) {
682         writer_print_string(wctx, key, "N/A", PRINT_STRING_OPT);
683     } else {
684         double d = ts * av_q2d(*time_base);
685         struct unit_value uv;
686         uv.val.d = d;
687         uv.unit = unit_second_str;
688         value_string(buf, sizeof(buf), uv);
689         writer_print_string(wctx, key, buf, 0);
690     }
691 }
692
693 static void writer_print_ts(WriterContext *wctx, const char *key, int64_t ts, int is_duration)
694 {
695     if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0)) {
696         writer_print_string(wctx, key, "N/A", PRINT_STRING_OPT);
697     } else {
698         writer_print_integer(wctx, key, ts);
699     }
700 }
701
702 static void writer_print_data(WriterContext *wctx, const char *name,
703                               uint8_t *data, int size)
704 {
705     AVBPrint bp;
706     int offset = 0, l, i;
707
708     av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED);
709     av_bprintf(&bp, "\n");
710     while (size) {
711         av_bprintf(&bp, "%08x: ", offset);
712         l = FFMIN(size, 16);
713         for (i = 0; i < l; i++) {
714             av_bprintf(&bp, "%02x", data[i]);
715             if (i & 1)
716                 av_bprintf(&bp, " ");
717         }
718         av_bprint_chars(&bp, ' ', 41 - 2 * i - i / 2);
719         for (i = 0; i < l; i++)
720             av_bprint_chars(&bp, data[i] - 32U < 95 ? data[i] : '.', 1);
721         av_bprintf(&bp, "\n");
722         offset += l;
723         data   += l;
724         size   -= l;
725     }
726     writer_print_string(wctx, name, bp.str, 0);
727     av_bprint_finalize(&bp, NULL);
728 }
729
730 static void writer_print_data_hash(WriterContext *wctx, const char *name,
731                                    uint8_t *data, int size)
732 {
733     char *p, buf[AV_HASH_MAX_SIZE * 2 + 64] = { 0 };
734
735     if (!hash)
736         return;
737     av_hash_init(hash);
738     av_hash_update(hash, data, size);
739     snprintf(buf, sizeof(buf), "%s:", av_hash_get_name(hash));
740     p = buf + strlen(buf);
741     av_hash_final_hex(hash, p, buf + sizeof(buf) - p);
742     writer_print_string(wctx, name, buf, 0);
743 }
744
745 static void writer_print_integers(WriterContext *wctx, const char *name,
746                                   uint8_t *data, int size, const char *format,
747                                   int columns, int bytes, int offset_add)
748 {
749     AVBPrint bp;
750     int offset = 0, l, i;
751
752     av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED);
753     av_bprintf(&bp, "\n");
754     while (size) {
755         av_bprintf(&bp, "%08x: ", offset);
756         l = FFMIN(size, columns);
757         for (i = 0; i < l; i++) {
758             if      (bytes == 1) av_bprintf(&bp, format, *data);
759             else if (bytes == 2) av_bprintf(&bp, format, AV_RN16(data));
760             else if (bytes == 4) av_bprintf(&bp, format, AV_RN32(data));
761             data += bytes;
762             size --;
763         }
764         av_bprintf(&bp, "\n");
765         offset += offset_add;
766     }
767     writer_print_string(wctx, name, bp.str, 0);
768     av_bprint_finalize(&bp, NULL);
769 }
770
771 #define MAX_REGISTERED_WRITERS_NB 64
772
773 static const Writer *registered_writers[MAX_REGISTERED_WRITERS_NB + 1];
774
775 static int writer_register(const Writer *writer)
776 {
777     static int next_registered_writer_idx = 0;
778
779     if (next_registered_writer_idx == MAX_REGISTERED_WRITERS_NB)
780         return AVERROR(ENOMEM);
781
782     registered_writers[next_registered_writer_idx++] = writer;
783     return 0;
784 }
785
786 static const Writer *writer_get_by_name(const char *name)
787 {
788     int i;
789
790     for (i = 0; registered_writers[i]; i++)
791         if (!strcmp(registered_writers[i]->name, name))
792             return registered_writers[i];
793
794     return NULL;
795 }
796
797
798 /* WRITERS */
799
800 #define DEFINE_WRITER_CLASS(name)                   \
801 static const char *name##_get_name(void *ctx)       \
802 {                                                   \
803     return #name ;                                  \
804 }                                                   \
805 static const AVClass name##_class = {               \
806     .class_name = #name,                            \
807     .item_name  = name##_get_name,                  \
808     .option     = name##_options                    \
809 }
810
811 /* Default output */
812
813 typedef struct DefaultContext {
814     const AVClass *class;
815     int nokey;
816     int noprint_wrappers;
817     int nested_section[SECTION_MAX_NB_LEVELS];
818 } DefaultContext;
819
820 #undef OFFSET
821 #define OFFSET(x) offsetof(DefaultContext, x)
822
823 static const AVOption default_options[] = {
824     { "noprint_wrappers", "do not print headers and footers", OFFSET(noprint_wrappers), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
825     { "nw",               "do not print headers and footers", OFFSET(noprint_wrappers), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
826     { "nokey",          "force no key printing",     OFFSET(nokey),          AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
827     { "nk",             "force no key printing",     OFFSET(nokey),          AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
828     {NULL},
829 };
830
831 DEFINE_WRITER_CLASS(default);
832
833 /* lame uppercasing routine, assumes the string is lower case ASCII */
834 static inline char *upcase_string(char *dst, size_t dst_size, const char *src)
835 {
836     int i;
837     for (i = 0; src[i] && i < dst_size-1; i++)
838         dst[i] = av_toupper(src[i]);
839     dst[i] = 0;
840     return dst;
841 }
842
843 static void default_print_section_header(WriterContext *wctx)
844 {
845     DefaultContext *def = wctx->priv;
846     char buf[32];
847     const struct section *section = wctx->section[wctx->level];
848     const struct section *parent_section = wctx->level ?
849         wctx->section[wctx->level-1] : NULL;
850
851     av_bprint_clear(&wctx->section_pbuf[wctx->level]);
852     if (parent_section &&
853         !(parent_section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))) {
854         def->nested_section[wctx->level] = 1;
855         av_bprintf(&wctx->section_pbuf[wctx->level], "%s%s:",
856                    wctx->section_pbuf[wctx->level-1].str,
857                    upcase_string(buf, sizeof(buf),
858                                  av_x_if_null(section->element_name, section->name)));
859     }
860
861     if (def->noprint_wrappers || def->nested_section[wctx->level])
862         return;
863
864     if (!(section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY)))
865         printf("[%s]\n", upcase_string(buf, sizeof(buf), section->name));
866 }
867
868 static void default_print_section_footer(WriterContext *wctx)
869 {
870     DefaultContext *def = wctx->priv;
871     const struct section *section = wctx->section[wctx->level];
872     char buf[32];
873
874     if (def->noprint_wrappers || def->nested_section[wctx->level])
875         return;
876
877     if (!(section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY)))
878         printf("[/%s]\n", upcase_string(buf, sizeof(buf), section->name));
879 }
880
881 static void default_print_str(WriterContext *wctx, const char *key, const char *value)
882 {
883     DefaultContext *def = wctx->priv;
884
885     if (!def->nokey)
886         printf("%s%s=", wctx->section_pbuf[wctx->level].str, key);
887     printf("%s\n", value);
888 }
889
890 static void default_print_int(WriterContext *wctx, const char *key, long long int value)
891 {
892     DefaultContext *def = wctx->priv;
893
894     if (!def->nokey)
895         printf("%s%s=", wctx->section_pbuf[wctx->level].str, key);
896     printf("%lld\n", value);
897 }
898
899 static const Writer default_writer = {
900     .name                  = "default",
901     .priv_size             = sizeof(DefaultContext),
902     .print_section_header  = default_print_section_header,
903     .print_section_footer  = default_print_section_footer,
904     .print_integer         = default_print_int,
905     .print_string          = default_print_str,
906     .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS,
907     .priv_class            = &default_class,
908 };
909
910 /* Compact output */
911
912 /**
913  * Apply C-language-like string escaping.
914  */
915 static const char *c_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
916 {
917     const char *p;
918
919     for (p = src; *p; p++) {
920         switch (*p) {
921         case '\b': av_bprintf(dst, "%s", "\\b");  break;
922         case '\f': av_bprintf(dst, "%s", "\\f");  break;
923         case '\n': av_bprintf(dst, "%s", "\\n");  break;
924         case '\r': av_bprintf(dst, "%s", "\\r");  break;
925         case '\\': av_bprintf(dst, "%s", "\\\\"); break;
926         default:
927             if (*p == sep)
928                 av_bprint_chars(dst, '\\', 1);
929             av_bprint_chars(dst, *p, 1);
930         }
931     }
932     return dst->str;
933 }
934
935 /**
936  * Quote fields containing special characters, check RFC4180.
937  */
938 static const char *csv_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
939 {
940     char meta_chars[] = { sep, '"', '\n', '\r', '\0' };
941     int needs_quoting = !!src[strcspn(src, meta_chars)];
942
943     if (needs_quoting)
944         av_bprint_chars(dst, '"', 1);
945
946     for (; *src; src++) {
947         if (*src == '"')
948             av_bprint_chars(dst, '"', 1);
949         av_bprint_chars(dst, *src, 1);
950     }
951     if (needs_quoting)
952         av_bprint_chars(dst, '"', 1);
953     return dst->str;
954 }
955
956 static const char *none_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
957 {
958     return src;
959 }
960
961 typedef struct CompactContext {
962     const AVClass *class;
963     char *item_sep_str;
964     char item_sep;
965     int nokey;
966     int print_section;
967     char *escape_mode_str;
968     const char * (*escape_str)(AVBPrint *dst, const char *src, const char sep, void *log_ctx);
969     int nested_section[SECTION_MAX_NB_LEVELS];
970     int has_nested_elems[SECTION_MAX_NB_LEVELS];
971     int terminate_line[SECTION_MAX_NB_LEVELS];
972 } CompactContext;
973
974 #undef OFFSET
975 #define OFFSET(x) offsetof(CompactContext, x)
976
977 static const AVOption compact_options[]= {
978     {"item_sep", "set item separator",    OFFSET(item_sep_str),    AV_OPT_TYPE_STRING, {.str="|"},  CHAR_MIN, CHAR_MAX },
979     {"s",        "set item separator",    OFFSET(item_sep_str),    AV_OPT_TYPE_STRING, {.str="|"},  CHAR_MIN, CHAR_MAX },
980     {"nokey",    "force no key printing", OFFSET(nokey),           AV_OPT_TYPE_BOOL,   {.i64=0},    0,        1        },
981     {"nk",       "force no key printing", OFFSET(nokey),           AV_OPT_TYPE_BOOL,   {.i64=0},    0,        1        },
982     {"escape",   "set escape mode",       OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="c"},  CHAR_MIN, CHAR_MAX },
983     {"e",        "set escape mode",       OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="c"},  CHAR_MIN, CHAR_MAX },
984     {"print_section", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL,   {.i64=1},    0,        1        },
985     {"p",             "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL,   {.i64=1},    0,        1        },
986     {NULL},
987 };
988
989 DEFINE_WRITER_CLASS(compact);
990
991 static av_cold int compact_init(WriterContext *wctx)
992 {
993     CompactContext *compact = wctx->priv;
994
995     if (strlen(compact->item_sep_str) != 1) {
996         av_log(wctx, AV_LOG_ERROR, "Item separator '%s' specified, but must contain a single character\n",
997                compact->item_sep_str);
998         return AVERROR(EINVAL);
999     }
1000     compact->item_sep = compact->item_sep_str[0];
1001
1002     if      (!strcmp(compact->escape_mode_str, "none")) compact->escape_str = none_escape_str;
1003     else if (!strcmp(compact->escape_mode_str, "c"   )) compact->escape_str = c_escape_str;
1004     else if (!strcmp(compact->escape_mode_str, "csv" )) compact->escape_str = csv_escape_str;
1005     else {
1006         av_log(wctx, AV_LOG_ERROR, "Unknown escape mode '%s'\n", compact->escape_mode_str);
1007         return AVERROR(EINVAL);
1008     }
1009
1010     return 0;
1011 }
1012
1013 static void compact_print_section_header(WriterContext *wctx)
1014 {
1015     CompactContext *compact = wctx->priv;
1016     const struct section *section = wctx->section[wctx->level];
1017     const struct section *parent_section = wctx->level ?
1018         wctx->section[wctx->level-1] : NULL;
1019     compact->terminate_line[wctx->level] = 1;
1020     compact->has_nested_elems[wctx->level] = 0;
1021
1022     av_bprint_clear(&wctx->section_pbuf[wctx->level]);
1023     if (!(section->flags & SECTION_FLAG_IS_ARRAY) && parent_section &&
1024         !(parent_section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))) {
1025         compact->nested_section[wctx->level] = 1;
1026         compact->has_nested_elems[wctx->level-1] = 1;
1027         av_bprintf(&wctx->section_pbuf[wctx->level], "%s%s:",
1028                    wctx->section_pbuf[wctx->level-1].str,
1029                    (char *)av_x_if_null(section->element_name, section->name));
1030         wctx->nb_item[wctx->level] = wctx->nb_item[wctx->level-1];
1031     } else {
1032         if (parent_section && compact->has_nested_elems[wctx->level-1] &&
1033             (section->flags & SECTION_FLAG_IS_ARRAY)) {
1034             compact->terminate_line[wctx->level-1] = 0;
1035             printf("\n");
1036         }
1037         if (compact->print_section &&
1038             !(section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY)))
1039             printf("%s%c", section->name, compact->item_sep);
1040     }
1041 }
1042
1043 static void compact_print_section_footer(WriterContext *wctx)
1044 {
1045     CompactContext *compact = wctx->priv;
1046
1047     if (!compact->nested_section[wctx->level] &&
1048         compact->terminate_line[wctx->level] &&
1049         !(wctx->section[wctx->level]->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY)))
1050         printf("\n");
1051 }
1052
1053 static void compact_print_str(WriterContext *wctx, const char *key, const char *value)
1054 {
1055     CompactContext *compact = wctx->priv;
1056     AVBPrint buf;
1057
1058     if (wctx->nb_item[wctx->level]) printf("%c", compact->item_sep);
1059     if (!compact->nokey)
1060         printf("%s%s=", wctx->section_pbuf[wctx->level].str, key);
1061     av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
1062     printf("%s", compact->escape_str(&buf, value, compact->item_sep, wctx));
1063     av_bprint_finalize(&buf, NULL);
1064 }
1065
1066 static void compact_print_int(WriterContext *wctx, const char *key, long long int value)
1067 {
1068     CompactContext *compact = wctx->priv;
1069
1070     if (wctx->nb_item[wctx->level]) printf("%c", compact->item_sep);
1071     if (!compact->nokey)
1072         printf("%s%s=", wctx->section_pbuf[wctx->level].str, key);
1073     printf("%lld", value);
1074 }
1075
1076 static const Writer compact_writer = {
1077     .name                 = "compact",
1078     .priv_size            = sizeof(CompactContext),
1079     .init                 = compact_init,
1080     .print_section_header = compact_print_section_header,
1081     .print_section_footer = compact_print_section_footer,
1082     .print_integer        = compact_print_int,
1083     .print_string         = compact_print_str,
1084     .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS,
1085     .priv_class           = &compact_class,
1086 };
1087
1088 /* CSV output */
1089
1090 #undef OFFSET
1091 #define OFFSET(x) offsetof(CompactContext, x)
1092
1093 static const AVOption csv_options[] = {
1094     {"item_sep", "set item separator",    OFFSET(item_sep_str),    AV_OPT_TYPE_STRING, {.str=","},  CHAR_MIN, CHAR_MAX },
1095     {"s",        "set item separator",    OFFSET(item_sep_str),    AV_OPT_TYPE_STRING, {.str=","},  CHAR_MIN, CHAR_MAX },
1096     {"nokey",    "force no key printing", OFFSET(nokey),           AV_OPT_TYPE_BOOL,   {.i64=1},    0,        1        },
1097     {"nk",       "force no key printing", OFFSET(nokey),           AV_OPT_TYPE_BOOL,   {.i64=1},    0,        1        },
1098     {"escape",   "set escape mode",       OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="csv"}, CHAR_MIN, CHAR_MAX },
1099     {"e",        "set escape mode",       OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="csv"}, CHAR_MIN, CHAR_MAX },
1100     {"print_section", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL,   {.i64=1},    0,        1        },
1101     {"p",             "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL,   {.i64=1},    0,        1        },
1102     {NULL},
1103 };
1104
1105 DEFINE_WRITER_CLASS(csv);
1106
1107 static const Writer csv_writer = {
1108     .name                 = "csv",
1109     .priv_size            = sizeof(CompactContext),
1110     .init                 = compact_init,
1111     .print_section_header = compact_print_section_header,
1112     .print_section_footer = compact_print_section_footer,
1113     .print_integer        = compact_print_int,
1114     .print_string         = compact_print_str,
1115     .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS,
1116     .priv_class           = &csv_class,
1117 };
1118
1119 /* Flat output */
1120
1121 typedef struct FlatContext {
1122     const AVClass *class;
1123     const char *sep_str;
1124     char sep;
1125     int hierarchical;
1126 } FlatContext;
1127
1128 #undef OFFSET
1129 #define OFFSET(x) offsetof(FlatContext, x)
1130
1131 static const AVOption flat_options[]= {
1132     {"sep_char", "set separator",    OFFSET(sep_str),    AV_OPT_TYPE_STRING, {.str="."},  CHAR_MIN, CHAR_MAX },
1133     {"s",        "set separator",    OFFSET(sep_str),    AV_OPT_TYPE_STRING, {.str="."},  CHAR_MIN, CHAR_MAX },
1134     {"hierarchical", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
1135     {"h",            "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
1136     {NULL},
1137 };
1138
1139 DEFINE_WRITER_CLASS(flat);
1140
1141 static av_cold int flat_init(WriterContext *wctx)
1142 {
1143     FlatContext *flat = wctx->priv;
1144
1145     if (strlen(flat->sep_str) != 1) {
1146         av_log(wctx, AV_LOG_ERROR, "Item separator '%s' specified, but must contain a single character\n",
1147                flat->sep_str);
1148         return AVERROR(EINVAL);
1149     }
1150     flat->sep = flat->sep_str[0];
1151
1152     return 0;
1153 }
1154
1155 static const char *flat_escape_key_str(AVBPrint *dst, const char *src, const char sep)
1156 {
1157     const char *p;
1158
1159     for (p = src; *p; p++) {
1160         if (!((*p >= '0' && *p <= '9') ||
1161               (*p >= 'a' && *p <= 'z') ||
1162               (*p >= 'A' && *p <= 'Z')))
1163             av_bprint_chars(dst, '_', 1);
1164         else
1165             av_bprint_chars(dst, *p, 1);
1166     }
1167     return dst->str;
1168 }
1169
1170 static const char *flat_escape_value_str(AVBPrint *dst, const char *src)
1171 {
1172     const char *p;
1173
1174     for (p = src; *p; p++) {
1175         switch (*p) {
1176         case '\n': av_bprintf(dst, "%s", "\\n");  break;
1177         case '\r': av_bprintf(dst, "%s", "\\r");  break;
1178         case '\\': av_bprintf(dst, "%s", "\\\\"); break;
1179         case '"':  av_bprintf(dst, "%s", "\\\""); break;
1180         case '`':  av_bprintf(dst, "%s", "\\`");  break;
1181         case '$':  av_bprintf(dst, "%s", "\\$");  break;
1182         default:   av_bprint_chars(dst, *p, 1);   break;
1183         }
1184     }
1185     return dst->str;
1186 }
1187
1188 static void flat_print_section_header(WriterContext *wctx)
1189 {
1190     FlatContext *flat = wctx->priv;
1191     AVBPrint *buf = &wctx->section_pbuf[wctx->level];
1192     const struct section *section = wctx->section[wctx->level];
1193     const struct section *parent_section = wctx->level ?
1194         wctx->section[wctx->level-1] : NULL;
1195
1196     /* build section header */
1197     av_bprint_clear(buf);
1198     if (!parent_section)
1199         return;
1200     av_bprintf(buf, "%s", wctx->section_pbuf[wctx->level-1].str);
1201
1202     if (flat->hierarchical ||
1203         !(section->flags & (SECTION_FLAG_IS_ARRAY|SECTION_FLAG_IS_WRAPPER))) {
1204         av_bprintf(buf, "%s%s", wctx->section[wctx->level]->name, flat->sep_str);
1205
1206         if (parent_section->flags & SECTION_FLAG_IS_ARRAY) {
1207             int n = parent_section->id == SECTION_ID_PACKETS_AND_FRAMES ?
1208                 wctx->nb_section_packet_frame : wctx->nb_item[wctx->level-1];
1209             av_bprintf(buf, "%d%s", n, flat->sep_str);
1210         }
1211     }
1212 }
1213
1214 static void flat_print_int(WriterContext *wctx, const char *key, long long int value)
1215 {
1216     printf("%s%s=%lld\n", wctx->section_pbuf[wctx->level].str, key, value);
1217 }
1218
1219 static void flat_print_str(WriterContext *wctx, const char *key, const char *value)
1220 {
1221     FlatContext *flat = wctx->priv;
1222     AVBPrint buf;
1223
1224     printf("%s", wctx->section_pbuf[wctx->level].str);
1225     av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
1226     printf("%s=", flat_escape_key_str(&buf, key, flat->sep));
1227     av_bprint_clear(&buf);
1228     printf("\"%s\"\n", flat_escape_value_str(&buf, value));
1229     av_bprint_finalize(&buf, NULL);
1230 }
1231
1232 static const Writer flat_writer = {
1233     .name                  = "flat",
1234     .priv_size             = sizeof(FlatContext),
1235     .init                  = flat_init,
1236     .print_section_header  = flat_print_section_header,
1237     .print_integer         = flat_print_int,
1238     .print_string          = flat_print_str,
1239     .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS|WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER,
1240     .priv_class            = &flat_class,
1241 };
1242
1243 /* INI format output */
1244
1245 typedef struct INIContext {
1246     const AVClass *class;
1247     int hierarchical;
1248 } INIContext;
1249
1250 #undef OFFSET
1251 #define OFFSET(x) offsetof(INIContext, x)
1252
1253 static const AVOption ini_options[] = {
1254     {"hierarchical", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
1255     {"h",            "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
1256     {NULL},
1257 };
1258
1259 DEFINE_WRITER_CLASS(ini);
1260
1261 static char *ini_escape_str(AVBPrint *dst, const char *src)
1262 {
1263     int i = 0;
1264     char c = 0;
1265
1266     while (c = src[i++]) {
1267         switch (c) {
1268         case '\b': av_bprintf(dst, "%s", "\\b"); break;
1269         case '\f': av_bprintf(dst, "%s", "\\f"); break;
1270         case '\n': av_bprintf(dst, "%s", "\\n"); break;
1271         case '\r': av_bprintf(dst, "%s", "\\r"); break;
1272         case '\t': av_bprintf(dst, "%s", "\\t"); break;
1273         case '\\':
1274         case '#' :
1275         case '=' :
1276         case ':' : av_bprint_chars(dst, '\\', 1);
1277         default:
1278             if ((unsigned char)c < 32)
1279                 av_bprintf(dst, "\\x00%02x", c & 0xff);
1280             else
1281                 av_bprint_chars(dst, c, 1);
1282             break;
1283         }
1284     }
1285     return dst->str;
1286 }
1287
1288 static void ini_print_section_header(WriterContext *wctx)
1289 {
1290     INIContext *ini = wctx->priv;
1291     AVBPrint *buf = &wctx->section_pbuf[wctx->level];
1292     const struct section *section = wctx->section[wctx->level];
1293     const struct section *parent_section = wctx->level ?
1294         wctx->section[wctx->level-1] : NULL;
1295
1296     av_bprint_clear(buf);
1297     if (!parent_section) {
1298         printf("# ffprobe output\n\n");
1299         return;
1300     }
1301
1302     if (wctx->nb_item[wctx->level-1])
1303         printf("\n");
1304
1305     av_bprintf(buf, "%s", wctx->section_pbuf[wctx->level-1].str);
1306     if (ini->hierarchical ||
1307         !(section->flags & (SECTION_FLAG_IS_ARRAY|SECTION_FLAG_IS_WRAPPER))) {
1308         av_bprintf(buf, "%s%s", buf->str[0] ? "." : "", wctx->section[wctx->level]->name);
1309
1310         if (parent_section->flags & SECTION_FLAG_IS_ARRAY) {
1311             int n = parent_section->id == SECTION_ID_PACKETS_AND_FRAMES ?
1312                 wctx->nb_section_packet_frame : wctx->nb_item[wctx->level-1];
1313             av_bprintf(buf, ".%d", n);
1314         }
1315     }
1316
1317     if (!(section->flags & (SECTION_FLAG_IS_ARRAY|SECTION_FLAG_IS_WRAPPER)))
1318         printf("[%s]\n", buf->str);
1319 }
1320
1321 static void ini_print_str(WriterContext *wctx, const char *key, const char *value)
1322 {
1323     AVBPrint buf;
1324
1325     av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
1326     printf("%s=", ini_escape_str(&buf, key));
1327     av_bprint_clear(&buf);
1328     printf("%s\n", ini_escape_str(&buf, value));
1329     av_bprint_finalize(&buf, NULL);
1330 }
1331
1332 static void ini_print_int(WriterContext *wctx, const char *key, long long int value)
1333 {
1334     printf("%s=%lld\n", key, value);
1335 }
1336
1337 static const Writer ini_writer = {
1338     .name                  = "ini",
1339     .priv_size             = sizeof(INIContext),
1340     .print_section_header  = ini_print_section_header,
1341     .print_integer         = ini_print_int,
1342     .print_string          = ini_print_str,
1343     .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS|WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER,
1344     .priv_class            = &ini_class,
1345 };
1346
1347 /* JSON output */
1348
1349 typedef struct JSONContext {
1350     const AVClass *class;
1351     int indent_level;
1352     int compact;
1353     const char *item_sep, *item_start_end;
1354 } JSONContext;
1355
1356 #undef OFFSET
1357 #define OFFSET(x) offsetof(JSONContext, x)
1358
1359 static const AVOption json_options[]= {
1360     { "compact", "enable compact output", OFFSET(compact), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
1361     { "c",       "enable compact output", OFFSET(compact), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
1362     { NULL }
1363 };
1364
1365 DEFINE_WRITER_CLASS(json);
1366
1367 static av_cold int json_init(WriterContext *wctx)
1368 {
1369     JSONContext *json = wctx->priv;
1370
1371     json->item_sep       = json->compact ? ", " : ",\n";
1372     json->item_start_end = json->compact ? " "  : "\n";
1373
1374     return 0;
1375 }
1376
1377 static const char *json_escape_str(AVBPrint *dst, const char *src, void *log_ctx)
1378 {
1379     static const char json_escape[] = {'"', '\\', '\b', '\f', '\n', '\r', '\t', 0};
1380     static const char json_subst[]  = {'"', '\\',  'b',  'f',  'n',  'r',  't', 0};
1381     const char *p;
1382
1383     for (p = src; *p; p++) {
1384         char *s = strchr(json_escape, *p);
1385         if (s) {
1386             av_bprint_chars(dst, '\\', 1);
1387             av_bprint_chars(dst, json_subst[s - json_escape], 1);
1388         } else if ((unsigned char)*p < 32) {
1389             av_bprintf(dst, "\\u00%02x", *p & 0xff);
1390         } else {
1391             av_bprint_chars(dst, *p, 1);
1392         }
1393     }
1394     return dst->str;
1395 }
1396
1397 #define JSON_INDENT() printf("%*c", json->indent_level * 4, ' ')
1398
1399 static void json_print_section_header(WriterContext *wctx)
1400 {
1401     JSONContext *json = wctx->priv;
1402     AVBPrint buf;
1403     const struct section *section = wctx->section[wctx->level];
1404     const struct section *parent_section = wctx->level ?
1405         wctx->section[wctx->level-1] : NULL;
1406
1407     if (wctx->level && wctx->nb_item[wctx->level-1])
1408         printf(",\n");
1409
1410     if (section->flags & SECTION_FLAG_IS_WRAPPER) {
1411         printf("{\n");
1412         json->indent_level++;
1413     } else {
1414         av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
1415         json_escape_str(&buf, section->name, wctx);
1416         JSON_INDENT();
1417
1418         json->indent_level++;
1419         if (section->flags & SECTION_FLAG_IS_ARRAY) {
1420             printf("\"%s\": [\n", buf.str);
1421         } else if (parent_section && !(parent_section->flags & SECTION_FLAG_IS_ARRAY)) {
1422             printf("\"%s\": {%s", buf.str, json->item_start_end);
1423         } else {
1424             printf("{%s", json->item_start_end);
1425
1426             /* this is required so the parser can distinguish between packets and frames */
1427             if (parent_section && parent_section->id == SECTION_ID_PACKETS_AND_FRAMES) {
1428                 if (!json->compact)
1429                     JSON_INDENT();
1430                 printf("\"type\": \"%s\"%s", section->name, json->item_sep);
1431             }
1432         }
1433         av_bprint_finalize(&buf, NULL);
1434     }
1435 }
1436
1437 static void json_print_section_footer(WriterContext *wctx)
1438 {
1439     JSONContext *json = wctx->priv;
1440     const struct section *section = wctx->section[wctx->level];
1441
1442     if (wctx->level == 0) {
1443         json->indent_level--;
1444         printf("\n}\n");
1445     } else if (section->flags & SECTION_FLAG_IS_ARRAY) {
1446         printf("\n");
1447         json->indent_level--;
1448         JSON_INDENT();
1449         printf("]");
1450     } else {
1451         printf("%s", json->item_start_end);
1452         json->indent_level--;
1453         if (!json->compact)
1454             JSON_INDENT();
1455         printf("}");
1456     }
1457 }
1458
1459 static inline void json_print_item_str(WriterContext *wctx,
1460                                        const char *key, const char *value)
1461 {
1462     AVBPrint buf;
1463
1464     av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
1465     printf("\"%s\":", json_escape_str(&buf, key,   wctx));
1466     av_bprint_clear(&buf);
1467     printf(" \"%s\"", json_escape_str(&buf, value, wctx));
1468     av_bprint_finalize(&buf, NULL);
1469 }
1470
1471 static void json_print_str(WriterContext *wctx, const char *key, const char *value)
1472 {
1473     JSONContext *json = wctx->priv;
1474
1475     if (wctx->nb_item[wctx->level])
1476         printf("%s", json->item_sep);
1477     if (!json->compact)
1478         JSON_INDENT();
1479     json_print_item_str(wctx, key, value);
1480 }
1481
1482 static void json_print_int(WriterContext *wctx, const char *key, long long int value)
1483 {
1484     JSONContext *json = wctx->priv;
1485     AVBPrint buf;
1486
1487     if (wctx->nb_item[wctx->level])
1488         printf("%s", json->item_sep);
1489     if (!json->compact)
1490         JSON_INDENT();
1491
1492     av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
1493     printf("\"%s\": %lld", json_escape_str(&buf, key, wctx), value);
1494     av_bprint_finalize(&buf, NULL);
1495 }
1496
1497 static const Writer json_writer = {
1498     .name                 = "json",
1499     .priv_size            = sizeof(JSONContext),
1500     .init                 = json_init,
1501     .print_section_header = json_print_section_header,
1502     .print_section_footer = json_print_section_footer,
1503     .print_integer        = json_print_int,
1504     .print_string         = json_print_str,
1505     .flags = WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER,
1506     .priv_class           = &json_class,
1507 };
1508
1509 /* XML output */
1510
1511 typedef struct XMLContext {
1512     const AVClass *class;
1513     int within_tag;
1514     int indent_level;
1515     int fully_qualified;
1516     int xsd_strict;
1517 } XMLContext;
1518
1519 #undef OFFSET
1520 #define OFFSET(x) offsetof(XMLContext, x)
1521
1522 static const AVOption xml_options[] = {
1523     {"fully_qualified", "specify if the output should be fully qualified", OFFSET(fully_qualified), AV_OPT_TYPE_BOOL, {.i64=0},  0, 1 },
1524     {"q",               "specify if the output should be fully qualified", OFFSET(fully_qualified), AV_OPT_TYPE_BOOL, {.i64=0},  0, 1 },
1525     {"xsd_strict",      "ensure that the output is XSD compliant",         OFFSET(xsd_strict),      AV_OPT_TYPE_BOOL, {.i64=0},  0, 1 },
1526     {"x",               "ensure that the output is XSD compliant",         OFFSET(xsd_strict),      AV_OPT_TYPE_BOOL, {.i64=0},  0, 1 },
1527     {NULL},
1528 };
1529
1530 DEFINE_WRITER_CLASS(xml);
1531
1532 static av_cold int xml_init(WriterContext *wctx)
1533 {
1534     XMLContext *xml = wctx->priv;
1535
1536     if (xml->xsd_strict) {
1537         xml->fully_qualified = 1;
1538 #define CHECK_COMPLIANCE(opt, opt_name)                                 \
1539         if (opt) {                                                      \
1540             av_log(wctx, AV_LOG_ERROR,                                  \
1541                    "XSD-compliant output selected but option '%s' was selected, XML output may be non-compliant.\n" \
1542                    "You need to disable such option with '-no%s'\n", opt_name, opt_name); \
1543             return AVERROR(EINVAL);                                     \
1544         }
1545         CHECK_COMPLIANCE(show_private_data, "private");
1546         CHECK_COMPLIANCE(show_value_unit,   "unit");
1547         CHECK_COMPLIANCE(use_value_prefix,  "prefix");
1548
1549         if (do_show_frames && do_show_packets) {
1550             av_log(wctx, AV_LOG_ERROR,
1551                    "Interleaved frames and packets are not allowed in XSD. "
1552                    "Select only one between the -show_frames and the -show_packets options.\n");
1553             return AVERROR(EINVAL);
1554         }
1555     }
1556
1557     return 0;
1558 }
1559
1560 static const char *xml_escape_str(AVBPrint *dst, const char *src, void *log_ctx)
1561 {
1562     const char *p;
1563
1564     for (p = src; *p; p++) {
1565         switch (*p) {
1566         case '&' : av_bprintf(dst, "%s", "&amp;");  break;
1567         case '<' : av_bprintf(dst, "%s", "&lt;");   break;
1568         case '>' : av_bprintf(dst, "%s", "&gt;");   break;
1569         case '"' : av_bprintf(dst, "%s", "&quot;"); break;
1570         case '\'': av_bprintf(dst, "%s", "&apos;"); break;
1571         default: av_bprint_chars(dst, *p, 1);
1572         }
1573     }
1574
1575     return dst->str;
1576 }
1577
1578 #define XML_INDENT() printf("%*c", xml->indent_level * 4, ' ')
1579
1580 static void xml_print_section_header(WriterContext *wctx)
1581 {
1582     XMLContext *xml = wctx->priv;
1583     const struct section *section = wctx->section[wctx->level];
1584     const struct section *parent_section = wctx->level ?
1585         wctx->section[wctx->level-1] : NULL;
1586
1587     if (wctx->level == 0) {
1588         const char *qual = " xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' "
1589             "xmlns:ffprobe='http://www.ffmpeg.org/schema/ffprobe' "
1590             "xsi:schemaLocation='http://www.ffmpeg.org/schema/ffprobe ffprobe.xsd'";
1591
1592         printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1593         printf("<%sffprobe%s>\n",
1594                xml->fully_qualified ? "ffprobe:" : "",
1595                xml->fully_qualified ? qual : "");
1596         return;
1597     }
1598
1599     if (xml->within_tag) {
1600         xml->within_tag = 0;
1601         printf(">\n");
1602     }
1603     if (section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS) {
1604         xml->indent_level++;
1605     } else {
1606         if (parent_section && (parent_section->flags & SECTION_FLAG_IS_WRAPPER) &&
1607             wctx->level && wctx->nb_item[wctx->level-1])
1608             printf("\n");
1609         xml->indent_level++;
1610
1611         if (section->flags & SECTION_FLAG_IS_ARRAY) {
1612             XML_INDENT(); printf("<%s>\n", section->name);
1613         } else {
1614             XML_INDENT(); printf("<%s ", section->name);
1615             xml->within_tag = 1;
1616         }
1617     }
1618 }
1619
1620 static void xml_print_section_footer(WriterContext *wctx)
1621 {
1622     XMLContext *xml = wctx->priv;
1623     const struct section *section = wctx->section[wctx->level];
1624
1625     if (wctx->level == 0) {
1626         printf("</%sffprobe>\n", xml->fully_qualified ? "ffprobe:" : "");
1627     } else if (xml->within_tag) {
1628         xml->within_tag = 0;
1629         printf("/>\n");
1630         xml->indent_level--;
1631     } else if (section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS) {
1632         xml->indent_level--;
1633     } else {
1634         XML_INDENT(); printf("</%s>\n", section->name);
1635         xml->indent_level--;
1636     }
1637 }
1638
1639 static void xml_print_str(WriterContext *wctx, const char *key, const char *value)
1640 {
1641     AVBPrint buf;
1642     XMLContext *xml = wctx->priv;
1643     const struct section *section = wctx->section[wctx->level];
1644
1645     av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
1646
1647     if (section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS) {
1648         XML_INDENT();
1649         printf("<%s key=\"%s\"",
1650                section->element_name, xml_escape_str(&buf, key, wctx));
1651         av_bprint_clear(&buf);
1652         printf(" value=\"%s\"/>\n", xml_escape_str(&buf, value, wctx));
1653     } else {
1654         if (wctx->nb_item[wctx->level])
1655             printf(" ");
1656         printf("%s=\"%s\"", key, xml_escape_str(&buf, value, wctx));
1657     }
1658
1659     av_bprint_finalize(&buf, NULL);
1660 }
1661
1662 static void xml_print_int(WriterContext *wctx, const char *key, long long int value)
1663 {
1664     if (wctx->nb_item[wctx->level])
1665         printf(" ");
1666     printf("%s=\"%lld\"", key, value);
1667 }
1668
1669 static Writer xml_writer = {
1670     .name                 = "xml",
1671     .priv_size            = sizeof(XMLContext),
1672     .init                 = xml_init,
1673     .print_section_header = xml_print_section_header,
1674     .print_section_footer = xml_print_section_footer,
1675     .print_integer        = xml_print_int,
1676     .print_string         = xml_print_str,
1677     .flags = WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER,
1678     .priv_class           = &xml_class,
1679 };
1680
1681 static void writer_register_all(void)
1682 {
1683     static int initialized;
1684
1685     if (initialized)
1686         return;
1687     initialized = 1;
1688
1689     writer_register(&default_writer);
1690     writer_register(&compact_writer);
1691     writer_register(&csv_writer);
1692     writer_register(&flat_writer);
1693     writer_register(&ini_writer);
1694     writer_register(&json_writer);
1695     writer_register(&xml_writer);
1696 }
1697
1698 #define print_fmt(k, f, ...) do {              \
1699     av_bprint_clear(&pbuf);                    \
1700     av_bprintf(&pbuf, f, __VA_ARGS__);         \
1701     writer_print_string(w, k, pbuf.str, 0);    \
1702 } while (0)
1703
1704 #define print_int(k, v)         writer_print_integer(w, k, v)
1705 #define print_q(k, v, s)        writer_print_rational(w, k, v, s)
1706 #define print_str(k, v)         writer_print_string(w, k, v, 0)
1707 #define print_str_opt(k, v)     writer_print_string(w, k, v, PRINT_STRING_OPT)
1708 #define print_str_validate(k, v) writer_print_string(w, k, v, PRINT_STRING_VALIDATE)
1709 #define print_time(k, v, tb)    writer_print_time(w, k, v, tb, 0)
1710 #define print_ts(k, v)          writer_print_ts(w, k, v, 0)
1711 #define print_duration_time(k, v, tb) writer_print_time(w, k, v, tb, 1)
1712 #define print_duration_ts(k, v)       writer_print_ts(w, k, v, 1)
1713 #define print_val(k, v, u) do {                                     \
1714     struct unit_value uv;                                           \
1715     uv.val.i = v;                                                   \
1716     uv.unit = u;                                                    \
1717     writer_print_string(w, k, value_string(val_str, sizeof(val_str), uv), 0); \
1718 } while (0)
1719
1720 #define print_section_header(s) writer_print_section_header(w, s)
1721 #define print_section_footer(s) writer_print_section_footer(w, s)
1722
1723 #define REALLOCZ_ARRAY_STREAM(ptr, cur_n, new_n)                        \
1724 {                                                                       \
1725     ret = av_reallocp_array(&(ptr), (new_n), sizeof(*(ptr)));           \
1726     if (ret < 0)                                                        \
1727         goto end;                                                       \
1728     memset( (ptr) + (cur_n), 0, ((new_n) - (cur_n)) * sizeof(*(ptr)) ); \
1729 }
1730
1731 static inline int show_tags(WriterContext *w, AVDictionary *tags, int section_id)
1732 {
1733     AVDictionaryEntry *tag = NULL;
1734     int ret = 0;
1735
1736     if (!tags)
1737         return 0;
1738     writer_print_section_header(w, section_id);
1739
1740     while ((tag = av_dict_get(tags, "", tag, AV_DICT_IGNORE_SUFFIX))) {
1741         if ((ret = print_str_validate(tag->key, tag->value)) < 0)
1742             break;
1743     }
1744     writer_print_section_footer(w);
1745
1746     return ret;
1747 }
1748
1749 static void show_packet(WriterContext *w, AVFormatContext *fmt_ctx, AVPacket *pkt, int packet_idx)
1750 {
1751     char val_str[128];
1752     AVStream *st = fmt_ctx->streams[pkt->stream_index];
1753     AVBPrint pbuf;
1754     const char *s;
1755
1756     av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
1757
1758     writer_print_section_header(w, SECTION_ID_PACKET);
1759
1760     s = av_get_media_type_string(st->codec->codec_type);
1761     if (s) print_str    ("codec_type", s);
1762     else   print_str_opt("codec_type", "unknown");
1763     print_int("stream_index",     pkt->stream_index);
1764     print_ts  ("pts",             pkt->pts);
1765     print_time("pts_time",        pkt->pts, &st->time_base);
1766     print_ts  ("dts",             pkt->dts);
1767     print_time("dts_time",        pkt->dts, &st->time_base);
1768     print_duration_ts("duration",        pkt->duration);
1769     print_duration_time("duration_time", pkt->duration, &st->time_base);
1770     print_duration_ts("convergence_duration", pkt->convergence_duration);
1771     print_duration_time("convergence_duration_time", pkt->convergence_duration, &st->time_base);
1772     print_val("size",             pkt->size, unit_byte_str);
1773     if (pkt->pos != -1) print_fmt    ("pos", "%"PRId64, pkt->pos);
1774     else                print_str_opt("pos", "N/A");
1775     print_fmt("flags", "%c",      pkt->flags & AV_PKT_FLAG_KEY ? 'K' : '_');
1776
1777     if (pkt->side_data_elems) {
1778         int i;
1779         int size;
1780         const uint8_t *side_metadata;
1781
1782         side_metadata = av_packet_get_side_data(pkt, AV_PKT_DATA_STRINGS_METADATA, &size);
1783         if (side_metadata && size && do_show_packet_tags) {
1784             AVDictionary *dict = NULL;
1785             if (av_packet_unpack_dictionary(side_metadata, size, &dict) >= 0)
1786                 show_tags(w, dict, SECTION_ID_PACKET_TAGS);
1787             av_dict_free(&dict);
1788         }
1789         writer_print_section_header(w, SECTION_ID_PACKET_SIDE_DATA_LIST);
1790         for (i = 0; i < pkt->side_data_elems; i++) {
1791             AVPacketSideData *sd = &pkt->side_data[i];
1792             const char *name = av_packet_side_data_name(sd->type);
1793             writer_print_section_header(w, SECTION_ID_PACKET_SIDE_DATA);
1794             print_str("side_data_type", name ? name : "unknown");
1795             print_int("side_data_size", sd->size);
1796             if (sd->type == AV_PKT_DATA_DISPLAYMATRIX && sd->size >= 9*4) {
1797                 writer_print_integers(w, "displaymatrix", sd->data, 9, " %11d", 3, 4, 1);
1798                 print_int("rotation", av_display_rotation_get((int32_t *)sd->data));
1799             }
1800             writer_print_section_footer(w);
1801         }
1802         writer_print_section_footer(w);
1803     }
1804
1805     if (do_show_data)
1806         writer_print_data(w, "data", pkt->data, pkt->size);
1807     writer_print_data_hash(w, "data_hash", pkt->data, pkt->size);
1808     writer_print_section_footer(w);
1809
1810     av_bprint_finalize(&pbuf, NULL);
1811     fflush(stdout);
1812 }
1813
1814 static void show_subtitle(WriterContext *w, AVSubtitle *sub, AVStream *stream,
1815                           AVFormatContext *fmt_ctx)
1816 {
1817     AVBPrint pbuf;
1818
1819     av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
1820
1821     writer_print_section_header(w, SECTION_ID_SUBTITLE);
1822
1823     print_str ("media_type",         "subtitle");
1824     print_ts  ("pts",                 sub->pts);
1825     print_time("pts_time",            sub->pts, &AV_TIME_BASE_Q);
1826     print_int ("format",              sub->format);
1827     print_int ("start_display_time",  sub->start_display_time);
1828     print_int ("end_display_time",    sub->end_display_time);
1829     print_int ("num_rects",           sub->num_rects);
1830
1831     writer_print_section_footer(w);
1832
1833     av_bprint_finalize(&pbuf, NULL);
1834     fflush(stdout);
1835 }
1836
1837 static void show_frame(WriterContext *w, AVFrame *frame, AVStream *stream,
1838                        AVFormatContext *fmt_ctx)
1839 {
1840     AVBPrint pbuf;
1841     char val_str[128];
1842     const char *s;
1843     int i;
1844
1845     av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
1846
1847     writer_print_section_header(w, SECTION_ID_FRAME);
1848
1849     s = av_get_media_type_string(stream->codec->codec_type);
1850     if (s) print_str    ("media_type", s);
1851     else   print_str_opt("media_type", "unknown");
1852     print_int("stream_index",           stream->index);
1853     print_int("key_frame",              frame->key_frame);
1854     print_ts  ("pkt_pts",               frame->pkt_pts);
1855     print_time("pkt_pts_time",          frame->pkt_pts, &stream->time_base);
1856     print_ts  ("pkt_dts",               frame->pkt_dts);
1857     print_time("pkt_dts_time",          frame->pkt_dts, &stream->time_base);
1858     print_ts  ("best_effort_timestamp", av_frame_get_best_effort_timestamp(frame));
1859     print_time("best_effort_timestamp_time", av_frame_get_best_effort_timestamp(frame), &stream->time_base);
1860     print_duration_ts  ("pkt_duration",      av_frame_get_pkt_duration(frame));
1861     print_duration_time("pkt_duration_time", av_frame_get_pkt_duration(frame), &stream->time_base);
1862     if (av_frame_get_pkt_pos (frame) != -1) print_fmt    ("pkt_pos", "%"PRId64, av_frame_get_pkt_pos(frame));
1863     else                      print_str_opt("pkt_pos", "N/A");
1864     if (av_frame_get_pkt_size(frame) != -1) print_val    ("pkt_size", av_frame_get_pkt_size(frame), unit_byte_str);
1865     else                       print_str_opt("pkt_size", "N/A");
1866
1867     switch (stream->codec->codec_type) {
1868         AVRational sar;
1869
1870     case AVMEDIA_TYPE_VIDEO:
1871         print_int("width",                  frame->width);
1872         print_int("height",                 frame->height);
1873         s = av_get_pix_fmt_name(frame->format);
1874         if (s) print_str    ("pix_fmt", s);
1875         else   print_str_opt("pix_fmt", "unknown");
1876         sar = av_guess_sample_aspect_ratio(fmt_ctx, stream, frame);
1877         if (sar.num) {
1878             print_q("sample_aspect_ratio", sar, ':');
1879         } else {
1880             print_str_opt("sample_aspect_ratio", "N/A");
1881         }
1882         print_fmt("pict_type",              "%c", av_get_picture_type_char(frame->pict_type));
1883         print_int("coded_picture_number",   frame->coded_picture_number);
1884         print_int("display_picture_number", frame->display_picture_number);
1885         print_int("interlaced_frame",       frame->interlaced_frame);
1886         print_int("top_field_first",        frame->top_field_first);
1887         print_int("repeat_pict",            frame->repeat_pict);
1888         break;
1889
1890     case AVMEDIA_TYPE_AUDIO:
1891         s = av_get_sample_fmt_name(frame->format);
1892         if (s) print_str    ("sample_fmt", s);
1893         else   print_str_opt("sample_fmt", "unknown");
1894         print_int("nb_samples",         frame->nb_samples);
1895         print_int("channels", av_frame_get_channels(frame));
1896         if (av_frame_get_channel_layout(frame)) {
1897             av_bprint_clear(&pbuf);
1898             av_bprint_channel_layout(&pbuf, av_frame_get_channels(frame),
1899                                      av_frame_get_channel_layout(frame));
1900             print_str    ("channel_layout", pbuf.str);
1901         } else
1902             print_str_opt("channel_layout", "unknown");
1903         break;
1904     }
1905     if (do_show_frame_tags)
1906         show_tags(w, av_frame_get_metadata(frame), SECTION_ID_FRAME_TAGS);
1907     if (frame->nb_side_data) {
1908         writer_print_section_header(w, SECTION_ID_FRAME_SIDE_DATA_LIST);
1909         for (i = 0; i < frame->nb_side_data; i++) {
1910             AVFrameSideData *sd = frame->side_data[i];
1911             const char *name;
1912
1913             writer_print_section_header(w, SECTION_ID_FRAME_SIDE_DATA);
1914             name = av_frame_side_data_name(sd->type);
1915             print_str("side_data_type", name ? name : "unknown");
1916             print_int("side_data_size", sd->size);
1917             if (sd->type == AV_FRAME_DATA_DISPLAYMATRIX && sd->size >= 9*4) {
1918                 writer_print_integers(w, "displaymatrix", sd->data, 9, " %11d", 3, 4, 1);
1919                 print_int("rotation", av_display_rotation_get((int32_t *)sd->data));
1920             } else if (sd->type == AV_FRAME_DATA_GOP_TIMECODE && sd->size >= 8) {
1921                 char tcbuf[AV_TIMECODE_STR_SIZE];
1922                 av_timecode_make_mpeg_tc_string(tcbuf, *(int64_t *)(sd->data));
1923                 print_str("timecode", tcbuf);
1924             }
1925             writer_print_section_footer(w);
1926         }
1927         writer_print_section_footer(w);
1928     }
1929
1930     writer_print_section_footer(w);
1931
1932     av_bprint_finalize(&pbuf, NULL);
1933     fflush(stdout);
1934 }
1935
1936 static av_always_inline int process_frame(WriterContext *w,
1937                                           AVFormatContext *fmt_ctx,
1938                                           AVFrame *frame, AVPacket *pkt)
1939 {
1940     AVCodecContext *dec_ctx = fmt_ctx->streams[pkt->stream_index]->codec;
1941     AVSubtitle sub;
1942     int ret = 0, got_frame = 0;
1943
1944     if (dec_ctx->codec) {
1945         switch (dec_ctx->codec_type) {
1946         case AVMEDIA_TYPE_VIDEO:
1947             ret = avcodec_decode_video2(dec_ctx, frame, &got_frame, pkt);
1948             break;
1949
1950         case AVMEDIA_TYPE_AUDIO:
1951             ret = avcodec_decode_audio4(dec_ctx, frame, &got_frame, pkt);
1952             break;
1953
1954         case AVMEDIA_TYPE_SUBTITLE:
1955             ret = avcodec_decode_subtitle2(dec_ctx, &sub, &got_frame, pkt);
1956             break;
1957         }
1958     }
1959
1960     if (ret < 0)
1961         return ret;
1962     ret = FFMIN(ret, pkt->size); /* guard against bogus return values */
1963     pkt->data += ret;
1964     pkt->size -= ret;
1965     if (got_frame) {
1966         int is_sub = (dec_ctx->codec_type == AVMEDIA_TYPE_SUBTITLE);
1967         nb_streams_frames[pkt->stream_index]++;
1968         if (do_show_frames)
1969             if (is_sub)
1970                 show_subtitle(w, &sub, fmt_ctx->streams[pkt->stream_index], fmt_ctx);
1971             else
1972                 show_frame(w, frame, fmt_ctx->streams[pkt->stream_index], fmt_ctx);
1973         if (is_sub)
1974             avsubtitle_free(&sub);
1975     }
1976     return got_frame;
1977 }
1978
1979 static void log_read_interval(const ReadInterval *interval, void *log_ctx, int log_level)
1980 {
1981     av_log(log_ctx, log_level, "id:%d", interval->id);
1982
1983     if (interval->has_start) {
1984         av_log(log_ctx, log_level, " start:%s%s", interval->start_is_offset ? "+" : "",
1985                av_ts2timestr(interval->start, &AV_TIME_BASE_Q));
1986     } else {
1987         av_log(log_ctx, log_level, " start:N/A");
1988     }
1989
1990     if (interval->has_end) {
1991         av_log(log_ctx, log_level, " end:%s", interval->end_is_offset ? "+" : "");
1992         if (interval->duration_frames)
1993             av_log(log_ctx, log_level, "#%"PRId64, interval->end);
1994         else
1995             av_log(log_ctx, log_level, "%s", av_ts2timestr(interval->end, &AV_TIME_BASE_Q));
1996     } else {
1997         av_log(log_ctx, log_level, " end:N/A");
1998     }
1999
2000     av_log(log_ctx, log_level, "\n");
2001 }
2002
2003 static int read_interval_packets(WriterContext *w, AVFormatContext *fmt_ctx,
2004                                  const ReadInterval *interval, int64_t *cur_ts)
2005 {
2006     AVPacket pkt, pkt1;
2007     AVFrame *frame = NULL;
2008     int ret = 0, i = 0, frame_count = 0;
2009     int64_t start = -INT64_MAX, end = interval->end;
2010     int has_start = 0, has_end = interval->has_end && !interval->end_is_offset;
2011
2012     av_init_packet(&pkt);
2013
2014     av_log(NULL, AV_LOG_VERBOSE, "Processing read interval ");
2015     log_read_interval(interval, NULL, AV_LOG_VERBOSE);
2016
2017     if (interval->has_start) {
2018         int64_t target;
2019         if (interval->start_is_offset) {
2020             if (*cur_ts == AV_NOPTS_VALUE) {
2021                 av_log(NULL, AV_LOG_ERROR,
2022                        "Could not seek to relative position since current "
2023                        "timestamp is not defined\n");
2024                 ret = AVERROR(EINVAL);
2025                 goto end;
2026             }
2027             target = *cur_ts + interval->start;
2028         } else {
2029             target = interval->start;
2030         }
2031
2032         av_log(NULL, AV_LOG_VERBOSE, "Seeking to read interval start point %s\n",
2033                av_ts2timestr(target, &AV_TIME_BASE_Q));
2034         if ((ret = avformat_seek_file(fmt_ctx, -1, -INT64_MAX, target, INT64_MAX, 0)) < 0) {
2035             av_log(NULL, AV_LOG_ERROR, "Could not seek to position %"PRId64": %s\n",
2036                    interval->start, av_err2str(ret));
2037             goto end;
2038         }
2039     }
2040
2041     frame = av_frame_alloc();
2042     if (!frame) {
2043         ret = AVERROR(ENOMEM);
2044         goto end;
2045     }
2046     while (!av_read_frame(fmt_ctx, &pkt)) {
2047         if (fmt_ctx->nb_streams > nb_streams) {
2048             REALLOCZ_ARRAY_STREAM(nb_streams_frames,  nb_streams, fmt_ctx->nb_streams);
2049             REALLOCZ_ARRAY_STREAM(nb_streams_packets, nb_streams, fmt_ctx->nb_streams);
2050             REALLOCZ_ARRAY_STREAM(selected_streams,   nb_streams, fmt_ctx->nb_streams);
2051             nb_streams = fmt_ctx->nb_streams;
2052         }
2053         if (selected_streams[pkt.stream_index]) {
2054             AVRational tb = fmt_ctx->streams[pkt.stream_index]->time_base;
2055
2056             if (pkt.pts != AV_NOPTS_VALUE)
2057                 *cur_ts = av_rescale_q(pkt.pts, tb, AV_TIME_BASE_Q);
2058
2059             if (!has_start && *cur_ts != AV_NOPTS_VALUE) {
2060                 start = *cur_ts;
2061                 has_start = 1;
2062             }
2063
2064             if (has_start && !has_end && interval->end_is_offset) {
2065                 end = start + interval->end;
2066                 has_end = 1;
2067             }
2068
2069             if (interval->end_is_offset && interval->duration_frames) {
2070                 if (frame_count >= interval->end)
2071                     break;
2072             } else if (has_end && *cur_ts != AV_NOPTS_VALUE && *cur_ts >= end) {
2073                 break;
2074             }
2075
2076             frame_count++;
2077             if (do_read_packets) {
2078                 if (do_show_packets)
2079                     show_packet(w, fmt_ctx, &pkt, i++);
2080                 nb_streams_packets[pkt.stream_index]++;
2081             }
2082             if (do_read_frames) {
2083                 pkt1 = pkt;
2084                 while (pkt1.size && process_frame(w, fmt_ctx, frame, &pkt1) > 0);
2085             }
2086         }
2087         av_packet_unref(&pkt);
2088     }
2089     av_init_packet(&pkt);
2090     pkt.data = NULL;
2091     pkt.size = 0;
2092     //Flush remaining frames that are cached in the decoder
2093     for (i = 0; i < fmt_ctx->nb_streams; i++) {
2094         pkt.stream_index = i;
2095         if (do_read_frames)
2096             while (process_frame(w, fmt_ctx, frame, &pkt) > 0);
2097     }
2098
2099 end:
2100     av_frame_free(&frame);
2101     if (ret < 0) {
2102         av_log(NULL, AV_LOG_ERROR, "Could not read packets in interval ");
2103         log_read_interval(interval, NULL, AV_LOG_ERROR);
2104     }
2105     return ret;
2106 }
2107
2108 static int read_packets(WriterContext *w, AVFormatContext *fmt_ctx)
2109 {
2110     int i, ret = 0;
2111     int64_t cur_ts = fmt_ctx->start_time;
2112
2113     if (read_intervals_nb == 0) {
2114         ReadInterval interval = (ReadInterval) { .has_start = 0, .has_end = 0 };
2115         ret = read_interval_packets(w, fmt_ctx, &interval, &cur_ts);
2116     } else {
2117         for (i = 0; i < read_intervals_nb; i++) {
2118             ret = read_interval_packets(w, fmt_ctx, &read_intervals[i], &cur_ts);
2119             if (ret < 0)
2120                 break;
2121         }
2122     }
2123
2124     return ret;
2125 }
2126
2127 static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_idx, int in_program)
2128 {
2129     AVStream *stream = fmt_ctx->streams[stream_idx];
2130     AVCodecContext *dec_ctx;
2131     const AVCodec *dec;
2132     char val_str[128];
2133     const char *s;
2134     AVRational sar, dar;
2135     AVBPrint pbuf;
2136     const AVCodecDescriptor *cd;
2137     int ret = 0;
2138
2139     av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
2140
2141     writer_print_section_header(w, in_program ? SECTION_ID_PROGRAM_STREAM : SECTION_ID_STREAM);
2142
2143     print_int("index", stream->index);
2144
2145     if ((dec_ctx = stream->codec)) {
2146         const char *profile = NULL;
2147         dec = dec_ctx->codec;
2148         if (dec) {
2149             print_str("codec_name", dec->name);
2150             if (!do_bitexact) {
2151                 if (dec->long_name) print_str    ("codec_long_name", dec->long_name);
2152                 else                print_str_opt("codec_long_name", "unknown");
2153             }
2154         } else if ((cd = avcodec_descriptor_get(stream->codec->codec_id))) {
2155             print_str_opt("codec_name", cd->name);
2156             if (!do_bitexact) {
2157                 print_str_opt("codec_long_name",
2158                               cd->long_name ? cd->long_name : "unknown");
2159             }
2160         } else {
2161             print_str_opt("codec_name", "unknown");
2162             if (!do_bitexact) {
2163                 print_str_opt("codec_long_name", "unknown");
2164             }
2165         }
2166
2167         if (!do_bitexact && dec && (profile = av_get_profile_name(dec, dec_ctx->profile)))
2168             print_str("profile", profile);
2169         else {
2170             if (dec_ctx->profile != FF_PROFILE_UNKNOWN) {
2171                 char profile_num[12];
2172                 snprintf(profile_num, sizeof(profile_num), "%d", dec_ctx->profile);
2173                 print_str("profile", profile_num);
2174             } else
2175                 print_str_opt("profile", "unknown");
2176         }
2177
2178         s = av_get_media_type_string(dec_ctx->codec_type);
2179         if (s) print_str    ("codec_type", s);
2180         else   print_str_opt("codec_type", "unknown");
2181         print_q("codec_time_base", dec_ctx->time_base, '/');
2182
2183         /* print AVI/FourCC tag */
2184         av_get_codec_tag_string(val_str, sizeof(val_str), dec_ctx->codec_tag);
2185         print_str("codec_tag_string",    val_str);
2186         print_fmt("codec_tag", "0x%04x", dec_ctx->codec_tag);
2187
2188         switch (dec_ctx->codec_type) {
2189         case AVMEDIA_TYPE_VIDEO:
2190             print_int("width",        dec_ctx->width);
2191             print_int("height",       dec_ctx->height);
2192             print_int("coded_width",  dec_ctx->coded_width);
2193             print_int("coded_height", dec_ctx->coded_height);
2194             print_int("has_b_frames", dec_ctx->has_b_frames);
2195             sar = av_guess_sample_aspect_ratio(fmt_ctx, stream, NULL);
2196             if (sar.den) {
2197                 print_q("sample_aspect_ratio", sar, ':');
2198                 av_reduce(&dar.num, &dar.den,
2199                           dec_ctx->width  * sar.num,
2200                           dec_ctx->height * sar.den,
2201                           1024*1024);
2202                 print_q("display_aspect_ratio", dar, ':');
2203             } else {
2204                 print_str_opt("sample_aspect_ratio", "N/A");
2205                 print_str_opt("display_aspect_ratio", "N/A");
2206             }
2207             s = av_get_pix_fmt_name(dec_ctx->pix_fmt);
2208             if (s) print_str    ("pix_fmt", s);
2209             else   print_str_opt("pix_fmt", "unknown");
2210             print_int("level",   dec_ctx->level);
2211             if (dec_ctx->color_range != AVCOL_RANGE_UNSPECIFIED)
2212                 print_str    ("color_range", av_color_range_name(dec_ctx->color_range));
2213             else
2214                 print_str_opt("color_range", "N/A");
2215             s = av_get_colorspace_name(dec_ctx->colorspace);
2216             if (s) print_str    ("color_space", s);
2217             else   print_str_opt("color_space", "unknown");
2218
2219             if (dec_ctx->color_trc != AVCOL_TRC_UNSPECIFIED)
2220                 print_str("color_transfer", av_color_transfer_name(dec_ctx->color_trc));
2221             else
2222                 print_str_opt("color_transfer", av_color_transfer_name(dec_ctx->color_trc));
2223
2224             if (dec_ctx->color_primaries != AVCOL_PRI_UNSPECIFIED)
2225                 print_str("color_primaries", av_color_primaries_name(dec_ctx->color_primaries));
2226             else
2227                 print_str_opt("color_primaries", av_color_primaries_name(dec_ctx->color_primaries));
2228
2229             if (dec_ctx->chroma_sample_location != AVCHROMA_LOC_UNSPECIFIED)
2230                 print_str("chroma_location", av_chroma_location_name(dec_ctx->chroma_sample_location));
2231             else
2232                 print_str_opt("chroma_location", av_chroma_location_name(dec_ctx->chroma_sample_location));
2233
2234 #if FF_API_PRIVATE_OPT
2235             if (dec_ctx->timecode_frame_start >= 0) {
2236                 char tcbuf[AV_TIMECODE_STR_SIZE];
2237                 av_timecode_make_mpeg_tc_string(tcbuf, dec_ctx->timecode_frame_start);
2238                 print_str("timecode", tcbuf);
2239             } else {
2240                 print_str_opt("timecode", "N/A");
2241             }
2242 #endif
2243             print_int("refs", dec_ctx->refs);
2244             break;
2245
2246         case AVMEDIA_TYPE_AUDIO:
2247             s = av_get_sample_fmt_name(dec_ctx->sample_fmt);
2248             if (s) print_str    ("sample_fmt", s);
2249             else   print_str_opt("sample_fmt", "unknown");
2250             print_val("sample_rate",     dec_ctx->sample_rate, unit_hertz_str);
2251             print_int("channels",        dec_ctx->channels);
2252
2253             if (dec_ctx->channel_layout) {
2254                 av_bprint_clear(&pbuf);
2255                 av_bprint_channel_layout(&pbuf, dec_ctx->channels, dec_ctx->channel_layout);
2256                 print_str    ("channel_layout", pbuf.str);
2257             } else {
2258                 print_str_opt("channel_layout", "unknown");
2259             }
2260
2261             print_int("bits_per_sample", av_get_bits_per_sample(dec_ctx->codec_id));
2262             break;
2263
2264         case AVMEDIA_TYPE_SUBTITLE:
2265             if (dec_ctx->width)
2266                 print_int("width",       dec_ctx->width);
2267             else
2268                 print_str_opt("width",   "N/A");
2269             if (dec_ctx->height)
2270                 print_int("height",      dec_ctx->height);
2271             else
2272                 print_str_opt("height",  "N/A");
2273             break;
2274         }
2275     } else {
2276         print_str_opt("codec_type", "unknown");
2277     }
2278     if (dec_ctx->codec && dec_ctx->codec->priv_class && show_private_data) {
2279         const AVOption *opt = NULL;
2280         while (opt = av_opt_next(dec_ctx->priv_data,opt)) {
2281             uint8_t *str;
2282             if (opt->flags) continue;
2283             if (av_opt_get(dec_ctx->priv_data, opt->name, 0, &str) >= 0) {
2284                 print_str(opt->name, str);
2285                 av_free(str);
2286             }
2287         }
2288     }
2289
2290     if (fmt_ctx->iformat->flags & AVFMT_SHOW_IDS) print_fmt    ("id", "0x%x", stream->id);
2291     else                                          print_str_opt("id", "N/A");
2292     print_q("r_frame_rate",   stream->r_frame_rate,   '/');
2293     print_q("avg_frame_rate", stream->avg_frame_rate, '/');
2294     print_q("time_base",      stream->time_base,      '/');
2295     print_ts  ("start_pts",   stream->start_time);
2296     print_time("start_time",  stream->start_time, &stream->time_base);
2297     print_ts  ("duration_ts", stream->duration);
2298     print_time("duration",    stream->duration, &stream->time_base);
2299     if (dec_ctx->bit_rate > 0) print_val    ("bit_rate", dec_ctx->bit_rate, unit_bit_per_second_str);
2300     else                       print_str_opt("bit_rate", "N/A");
2301     if (dec_ctx->rc_max_rate > 0) print_val ("max_bit_rate", dec_ctx->rc_max_rate, unit_bit_per_second_str);
2302     else                       print_str_opt("max_bit_rate", "N/A");
2303     if (dec_ctx->bits_per_raw_sample > 0) print_fmt("bits_per_raw_sample", "%d", dec_ctx->bits_per_raw_sample);
2304     else                       print_str_opt("bits_per_raw_sample", "N/A");
2305     if (stream->nb_frames) print_fmt    ("nb_frames", "%"PRId64, stream->nb_frames);
2306     else                   print_str_opt("nb_frames", "N/A");
2307     if (nb_streams_frames[stream_idx])  print_fmt    ("nb_read_frames", "%"PRIu64, nb_streams_frames[stream_idx]);
2308     else                                print_str_opt("nb_read_frames", "N/A");
2309     if (nb_streams_packets[stream_idx]) print_fmt    ("nb_read_packets", "%"PRIu64, nb_streams_packets[stream_idx]);
2310     else                                print_str_opt("nb_read_packets", "N/A");
2311     if (do_show_data)
2312         writer_print_data(w, "extradata", dec_ctx->extradata,
2313                                           dec_ctx->extradata_size);
2314     writer_print_data_hash(w, "extradata_hash", dec_ctx->extradata,
2315                                                 dec_ctx->extradata_size);
2316
2317     /* Print disposition information */
2318 #define PRINT_DISPOSITION(flagname, name) do {                                \
2319         print_int(name, !!(stream->disposition & AV_DISPOSITION_##flagname)); \
2320     } while (0)
2321
2322     if (do_show_stream_disposition) {
2323     writer_print_section_header(w, in_program ? SECTION_ID_PROGRAM_STREAM_DISPOSITION : SECTION_ID_STREAM_DISPOSITION);
2324     PRINT_DISPOSITION(DEFAULT,          "default");
2325     PRINT_DISPOSITION(DUB,              "dub");
2326     PRINT_DISPOSITION(ORIGINAL,         "original");
2327     PRINT_DISPOSITION(COMMENT,          "comment");
2328     PRINT_DISPOSITION(LYRICS,           "lyrics");
2329     PRINT_DISPOSITION(KARAOKE,          "karaoke");
2330     PRINT_DISPOSITION(FORCED,           "forced");
2331     PRINT_DISPOSITION(HEARING_IMPAIRED, "hearing_impaired");
2332     PRINT_DISPOSITION(VISUAL_IMPAIRED,  "visual_impaired");
2333     PRINT_DISPOSITION(CLEAN_EFFECTS,    "clean_effects");
2334     PRINT_DISPOSITION(ATTACHED_PIC,     "attached_pic");
2335     writer_print_section_footer(w);
2336     }
2337
2338     if (do_show_stream_tags)
2339         ret = show_tags(w, stream->metadata, in_program ? SECTION_ID_PROGRAM_STREAM_TAGS : SECTION_ID_STREAM_TAGS);
2340
2341     if (stream->nb_side_data) {
2342         int i;
2343         writer_print_section_header(w, SECTION_ID_STREAM_SIDE_DATA_LIST);
2344         for (i = 0; i < stream->nb_side_data; i++) {
2345             AVPacketSideData *sd = &stream->side_data[i];
2346             const char *name = av_packet_side_data_name(sd->type);
2347
2348             writer_print_section_header(w, SECTION_ID_STREAM_SIDE_DATA);
2349             print_str("side_data_type", name ? name : "unknown");
2350             print_int("side_data_size", sd->size);
2351             if (sd->type == AV_PKT_DATA_DISPLAYMATRIX && sd->size >= 9*4) {
2352                 writer_print_integers(w, "displaymatrix", sd->data, 9, " %11d", 3, 4, 1);
2353                 print_int("rotation", av_display_rotation_get((int32_t *)sd->data));
2354             }
2355             writer_print_section_footer(w);
2356         }
2357         writer_print_section_footer(w);
2358     }
2359
2360     writer_print_section_footer(w);
2361     av_bprint_finalize(&pbuf, NULL);
2362     fflush(stdout);
2363
2364     return ret;
2365 }
2366
2367 static int show_streams(WriterContext *w, AVFormatContext *fmt_ctx)
2368 {
2369     int i, ret = 0;
2370
2371     writer_print_section_header(w, SECTION_ID_STREAMS);
2372     for (i = 0; i < fmt_ctx->nb_streams; i++)
2373         if (selected_streams[i]) {
2374             ret = show_stream(w, fmt_ctx, i, 0);
2375             if (ret < 0)
2376                 break;
2377         }
2378     writer_print_section_footer(w);
2379
2380     return ret;
2381 }
2382
2383 static int show_program(WriterContext *w, AVFormatContext *fmt_ctx, AVProgram *program)
2384 {
2385     int i, ret = 0;
2386
2387     writer_print_section_header(w, SECTION_ID_PROGRAM);
2388     print_int("program_id", program->id);
2389     print_int("program_num", program->program_num);
2390     print_int("nb_streams", program->nb_stream_indexes);
2391     print_int("pmt_pid", program->pmt_pid);
2392     print_int("pcr_pid", program->pcr_pid);
2393     print_ts("start_pts", program->start_time);
2394     print_time("start_time", program->start_time, &AV_TIME_BASE_Q);
2395     print_ts("end_pts", program->end_time);
2396     print_time("end_time", program->end_time, &AV_TIME_BASE_Q);
2397     if (do_show_program_tags)
2398         ret = show_tags(w, program->metadata, SECTION_ID_PROGRAM_TAGS);
2399     if (ret < 0)
2400         goto end;
2401
2402     writer_print_section_header(w, SECTION_ID_PROGRAM_STREAMS);
2403     for (i = 0; i < program->nb_stream_indexes; i++) {
2404         if (selected_streams[program->stream_index[i]]) {
2405             ret = show_stream(w, fmt_ctx, program->stream_index[i], 1);
2406             if (ret < 0)
2407                 break;
2408         }
2409     }
2410     writer_print_section_footer(w);
2411
2412 end:
2413     writer_print_section_footer(w);
2414     return ret;
2415 }
2416
2417 static int show_programs(WriterContext *w, AVFormatContext *fmt_ctx)
2418 {
2419     int i, ret = 0;
2420
2421     writer_print_section_header(w, SECTION_ID_PROGRAMS);
2422     for (i = 0; i < fmt_ctx->nb_programs; i++) {
2423         AVProgram *program = fmt_ctx->programs[i];
2424         if (!program)
2425             continue;
2426         ret = show_program(w, fmt_ctx, program);
2427         if (ret < 0)
2428             break;
2429     }
2430     writer_print_section_footer(w);
2431     return ret;
2432 }
2433
2434 static int show_chapters(WriterContext *w, AVFormatContext *fmt_ctx)
2435 {
2436     int i, ret = 0;
2437
2438     writer_print_section_header(w, SECTION_ID_CHAPTERS);
2439     for (i = 0; i < fmt_ctx->nb_chapters; i++) {
2440         AVChapter *chapter = fmt_ctx->chapters[i];
2441
2442         writer_print_section_header(w, SECTION_ID_CHAPTER);
2443         print_int("id", chapter->id);
2444         print_q  ("time_base", chapter->time_base, '/');
2445         print_int("start", chapter->start);
2446         print_time("start_time", chapter->start, &chapter->time_base);
2447         print_int("end", chapter->end);
2448         print_time("end_time", chapter->end, &chapter->time_base);
2449         if (do_show_chapter_tags)
2450             ret = show_tags(w, chapter->metadata, SECTION_ID_CHAPTER_TAGS);
2451         writer_print_section_footer(w);
2452     }
2453     writer_print_section_footer(w);
2454
2455     return ret;
2456 }
2457
2458 static int show_format(WriterContext *w, AVFormatContext *fmt_ctx)
2459 {
2460     char val_str[128];
2461     int64_t size = fmt_ctx->pb ? avio_size(fmt_ctx->pb) : -1;
2462     int ret = 0;
2463
2464     writer_print_section_header(w, SECTION_ID_FORMAT);
2465     print_str_validate("filename", fmt_ctx->filename);
2466     print_int("nb_streams",       fmt_ctx->nb_streams);
2467     print_int("nb_programs",      fmt_ctx->nb_programs);
2468     print_str("format_name",      fmt_ctx->iformat->name);
2469     if (!do_bitexact) {
2470         if (fmt_ctx->iformat->long_name) print_str    ("format_long_name", fmt_ctx->iformat->long_name);
2471         else                             print_str_opt("format_long_name", "unknown");
2472     }
2473     print_time("start_time",      fmt_ctx->start_time, &AV_TIME_BASE_Q);
2474     print_time("duration",        fmt_ctx->duration,   &AV_TIME_BASE_Q);
2475     if (size >= 0) print_val    ("size", size, unit_byte_str);
2476     else           print_str_opt("size", "N/A");
2477     if (fmt_ctx->bit_rate > 0) print_val    ("bit_rate", fmt_ctx->bit_rate, unit_bit_per_second_str);
2478     else                       print_str_opt("bit_rate", "N/A");
2479     print_int("probe_score", av_format_get_probe_score(fmt_ctx));
2480     if (do_show_format_tags)
2481         ret = show_tags(w, fmt_ctx->metadata, SECTION_ID_FORMAT_TAGS);
2482
2483     writer_print_section_footer(w);
2484     fflush(stdout);
2485     return ret;
2486 }
2487
2488 static void show_error(WriterContext *w, int err)
2489 {
2490     char errbuf[128];
2491     const char *errbuf_ptr = errbuf;
2492
2493     if (av_strerror(err, errbuf, sizeof(errbuf)) < 0)
2494         errbuf_ptr = strerror(AVUNERROR(err));
2495
2496     writer_print_section_header(w, SECTION_ID_ERROR);
2497     print_int("code", err);
2498     print_str("string", errbuf_ptr);
2499     writer_print_section_footer(w);
2500 }
2501
2502 static int open_input_file(AVFormatContext **fmt_ctx_ptr, const char *filename)
2503 {
2504     int err, i, orig_nb_streams;
2505     AVFormatContext *fmt_ctx = NULL;
2506     AVDictionaryEntry *t;
2507     AVDictionary **opts;
2508     int scan_all_pmts_set = 0;
2509
2510     if (!av_dict_get(format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE)) {
2511         av_dict_set(&format_opts, "scan_all_pmts", "1", AV_DICT_DONT_OVERWRITE);
2512         scan_all_pmts_set = 1;
2513     }
2514     if ((err = avformat_open_input(&fmt_ctx, filename,
2515                                    iformat, &format_opts)) < 0) {
2516         print_error(filename, err);
2517         return err;
2518     }
2519     *fmt_ctx_ptr = fmt_ctx;
2520     if (scan_all_pmts_set)
2521         av_dict_set(&format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE);
2522     if ((t = av_dict_get(format_opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
2523         av_log(NULL, AV_LOG_ERROR, "Option %s not found.\n", t->key);
2524         return AVERROR_OPTION_NOT_FOUND;
2525     }
2526
2527     /* fill the streams in the format context */
2528     opts = setup_find_stream_info_opts(fmt_ctx, codec_opts);
2529     orig_nb_streams = fmt_ctx->nb_streams;
2530
2531     err = avformat_find_stream_info(fmt_ctx, opts);
2532
2533     for (i = 0; i < orig_nb_streams; i++)
2534         av_dict_free(&opts[i]);
2535     av_freep(&opts);
2536
2537     if (err < 0) {
2538         print_error(filename, err);
2539         return err;
2540     }
2541
2542     av_dump_format(fmt_ctx, 0, filename, 0);
2543
2544     /* bind a decoder to each input stream */
2545     for (i = 0; i < fmt_ctx->nb_streams; i++) {
2546         AVStream *stream = fmt_ctx->streams[i];
2547         AVCodec *codec;
2548
2549         if (stream->codec->codec_id == AV_CODEC_ID_PROBE) {
2550             av_log(NULL, AV_LOG_WARNING,
2551                    "Failed to probe codec for input stream %d\n",
2552                     stream->index);
2553         } else if (!(codec = avcodec_find_decoder(stream->codec->codec_id))) {
2554             av_log(NULL, AV_LOG_WARNING,
2555                     "Unsupported codec with id %d for input stream %d\n",
2556                     stream->codec->codec_id, stream->index);
2557         } else {
2558             AVDictionary *opts = filter_codec_opts(codec_opts, stream->codec->codec_id,
2559                                                    fmt_ctx, stream, codec);
2560             if (avcodec_open2(stream->codec, codec, &opts) < 0) {
2561                 av_log(NULL, AV_LOG_WARNING, "Could not open codec for input stream %d\n",
2562                        stream->index);
2563             }
2564             if ((t = av_dict_get(opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
2565                 av_log(NULL, AV_LOG_ERROR, "Option %s for input stream %d not found\n",
2566                        t->key, stream->index);
2567                 return AVERROR_OPTION_NOT_FOUND;
2568             }
2569         }
2570     }
2571
2572     *fmt_ctx_ptr = fmt_ctx;
2573     return 0;
2574 }
2575
2576 static void close_input_file(AVFormatContext **ctx_ptr)
2577 {
2578     int i;
2579     AVFormatContext *fmt_ctx = *ctx_ptr;
2580
2581     /* close decoder for each stream */
2582     for (i = 0; i < fmt_ctx->nb_streams; i++)
2583         if (fmt_ctx->streams[i]->codec->codec_id != AV_CODEC_ID_NONE)
2584             avcodec_close(fmt_ctx->streams[i]->codec);
2585
2586     avformat_close_input(ctx_ptr);
2587 }
2588
2589 static int probe_file(WriterContext *wctx, const char *filename)
2590 {
2591     AVFormatContext *fmt_ctx = NULL;
2592     int ret, i;
2593     int section_id;
2594
2595     do_read_frames = do_show_frames || do_count_frames;
2596     do_read_packets = do_show_packets || do_count_packets;
2597
2598     ret = open_input_file(&fmt_ctx, filename);
2599     if (ret < 0)
2600         goto end;
2601
2602 #define CHECK_END if (ret < 0) goto end
2603
2604     nb_streams = fmt_ctx->nb_streams;
2605     REALLOCZ_ARRAY_STREAM(nb_streams_frames,0,fmt_ctx->nb_streams);
2606     REALLOCZ_ARRAY_STREAM(nb_streams_packets,0,fmt_ctx->nb_streams);
2607     REALLOCZ_ARRAY_STREAM(selected_streams,0,fmt_ctx->nb_streams);
2608
2609     for (i = 0; i < fmt_ctx->nb_streams; i++) {
2610         if (stream_specifier) {
2611             ret = avformat_match_stream_specifier(fmt_ctx,
2612                                                   fmt_ctx->streams[i],
2613                                                   stream_specifier);
2614             CHECK_END;
2615             else
2616                 selected_streams[i] = ret;
2617             ret = 0;
2618         } else {
2619             selected_streams[i] = 1;
2620         }
2621     }
2622
2623     if (do_read_frames || do_read_packets) {
2624         if (do_show_frames && do_show_packets &&
2625             wctx->writer->flags & WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER)
2626             section_id = SECTION_ID_PACKETS_AND_FRAMES;
2627         else if (do_show_packets && !do_show_frames)
2628             section_id = SECTION_ID_PACKETS;
2629         else // (!do_show_packets && do_show_frames)
2630             section_id = SECTION_ID_FRAMES;
2631         if (do_show_frames || do_show_packets)
2632             writer_print_section_header(wctx, section_id);
2633         ret = read_packets(wctx, fmt_ctx);
2634         if (do_show_frames || do_show_packets)
2635             writer_print_section_footer(wctx);
2636         CHECK_END;
2637     }
2638
2639     if (do_show_programs) {
2640         ret = show_programs(wctx, fmt_ctx);
2641         CHECK_END;
2642     }
2643
2644     if (do_show_streams) {
2645         ret = show_streams(wctx, fmt_ctx);
2646         CHECK_END;
2647     }
2648     if (do_show_chapters) {
2649         ret = show_chapters(wctx, fmt_ctx);
2650         CHECK_END;
2651     }
2652     if (do_show_format) {
2653         ret = show_format(wctx, fmt_ctx);
2654         CHECK_END;
2655     }
2656
2657 end:
2658     if (fmt_ctx)
2659         close_input_file(&fmt_ctx);
2660     av_freep(&nb_streams_frames);
2661     av_freep(&nb_streams_packets);
2662     av_freep(&selected_streams);
2663
2664     return ret;
2665 }
2666
2667 static void show_usage(void)
2668 {
2669     av_log(NULL, AV_LOG_INFO, "Simple multimedia streams analyzer\n");
2670     av_log(NULL, AV_LOG_INFO, "usage: %s [OPTIONS] [INPUT_FILE]\n", program_name);
2671     av_log(NULL, AV_LOG_INFO, "\n");
2672 }
2673
2674 static void ffprobe_show_program_version(WriterContext *w)
2675 {
2676     AVBPrint pbuf;
2677     av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
2678
2679     writer_print_section_header(w, SECTION_ID_PROGRAM_VERSION);
2680     print_str("version", FFMPEG_VERSION);
2681     print_fmt("copyright", "Copyright (c) %d-%d the FFmpeg developers",
2682               program_birth_year, CONFIG_THIS_YEAR);
2683     print_str("compiler_ident", CC_IDENT);
2684     print_str("configuration", FFMPEG_CONFIGURATION);
2685     writer_print_section_footer(w);
2686
2687     av_bprint_finalize(&pbuf, NULL);
2688 }
2689
2690 #define SHOW_LIB_VERSION(libname, LIBNAME)                              \
2691     do {                                                                \
2692         if (CONFIG_##LIBNAME) {                                         \
2693             unsigned int version = libname##_version();                 \
2694             writer_print_section_header(w, SECTION_ID_LIBRARY_VERSION); \
2695             print_str("name",    "lib" #libname);                       \
2696             print_int("major",   LIB##LIBNAME##_VERSION_MAJOR);         \
2697             print_int("minor",   LIB##LIBNAME##_VERSION_MINOR);         \
2698             print_int("micro",   LIB##LIBNAME##_VERSION_MICRO);         \
2699             print_int("version", version);                              \
2700             print_str("ident",   LIB##LIBNAME##_IDENT);                 \
2701             writer_print_section_footer(w);                             \
2702         }                                                               \
2703     } while (0)
2704
2705 static void ffprobe_show_library_versions(WriterContext *w)
2706 {
2707     writer_print_section_header(w, SECTION_ID_LIBRARY_VERSIONS);
2708     SHOW_LIB_VERSION(avutil,     AVUTIL);
2709     SHOW_LIB_VERSION(avcodec,    AVCODEC);
2710     SHOW_LIB_VERSION(avformat,   AVFORMAT);
2711     SHOW_LIB_VERSION(avdevice,   AVDEVICE);
2712     SHOW_LIB_VERSION(avfilter,   AVFILTER);
2713     SHOW_LIB_VERSION(swscale,    SWSCALE);
2714     SHOW_LIB_VERSION(swresample, SWRESAMPLE);
2715     SHOW_LIB_VERSION(postproc,   POSTPROC);
2716     writer_print_section_footer(w);
2717 }
2718
2719 #define PRINT_PIX_FMT_FLAG(flagname, name)                                \
2720     do {                                                                  \
2721         print_int(name, !!(pixdesc->flags & AV_PIX_FMT_FLAG_##flagname)); \
2722     } while (0)
2723
2724 static void ffprobe_show_pixel_formats(WriterContext *w)
2725 {
2726     const AVPixFmtDescriptor *pixdesc = NULL;
2727     int i, n;
2728
2729     writer_print_section_header(w, SECTION_ID_PIXEL_FORMATS);
2730     while (pixdesc = av_pix_fmt_desc_next(pixdesc)) {
2731         writer_print_section_header(w, SECTION_ID_PIXEL_FORMAT);
2732         print_str("name", pixdesc->name);
2733         print_int("nb_components", pixdesc->nb_components);
2734         if ((pixdesc->nb_components >= 3) && !(pixdesc->flags & AV_PIX_FMT_FLAG_RGB)) {
2735             print_int    ("log2_chroma_w", pixdesc->log2_chroma_w);
2736             print_int    ("log2_chroma_h", pixdesc->log2_chroma_h);
2737         } else {
2738             print_str_opt("log2_chroma_w", "N/A");
2739             print_str_opt("log2_chroma_h", "N/A");
2740         }
2741         n = av_get_bits_per_pixel(pixdesc);
2742         if (n) print_int    ("bits_per_pixel", n);
2743         else   print_str_opt("bits_per_pixel", "N/A");
2744         if (do_show_pixel_format_flags) {
2745             writer_print_section_header(w, SECTION_ID_PIXEL_FORMAT_FLAGS);
2746             PRINT_PIX_FMT_FLAG(BE,        "big_endian");
2747             PRINT_PIX_FMT_FLAG(PAL,       "palette");
2748             PRINT_PIX_FMT_FLAG(BITSTREAM, "bitstream");
2749             PRINT_PIX_FMT_FLAG(HWACCEL,   "hwaccel");
2750             PRINT_PIX_FMT_FLAG(PLANAR,    "planar");
2751             PRINT_PIX_FMT_FLAG(RGB,       "rgb");
2752             PRINT_PIX_FMT_FLAG(PSEUDOPAL, "pseudopal");
2753             PRINT_PIX_FMT_FLAG(ALPHA,     "alpha");
2754             writer_print_section_footer(w);
2755         }
2756         if (do_show_pixel_format_components && (pixdesc->nb_components > 0)) {
2757             writer_print_section_header(w, SECTION_ID_PIXEL_FORMAT_COMPONENTS);
2758             for (i = 0; i < pixdesc->nb_components; i++) {
2759                 writer_print_section_header(w, SECTION_ID_PIXEL_FORMAT_COMPONENT);
2760                 print_int("index", i + 1);
2761                 print_int("bit_depth", pixdesc->comp[i].depth);
2762                 writer_print_section_footer(w);
2763             }
2764             writer_print_section_footer(w);
2765         }
2766         writer_print_section_footer(w);
2767     }
2768     writer_print_section_footer(w);
2769 }
2770
2771 static int opt_format(void *optctx, const char *opt, const char *arg)
2772 {
2773     iformat = av_find_input_format(arg);
2774     if (!iformat) {
2775         av_log(NULL, AV_LOG_ERROR, "Unknown input format: %s\n", arg);
2776         return AVERROR(EINVAL);
2777     }
2778     return 0;
2779 }
2780
2781 static inline void mark_section_show_entries(SectionID section_id,
2782                                              int show_all_entries, AVDictionary *entries)
2783 {
2784     struct section *section = &sections[section_id];
2785
2786     section->show_all_entries = show_all_entries;
2787     if (show_all_entries) {
2788         SectionID *id;
2789         for (id = section->children_ids; *id != -1; id++)
2790             mark_section_show_entries(*id, show_all_entries, entries);
2791     } else {
2792         av_dict_copy(&section->entries_to_show, entries, 0);
2793     }
2794 }
2795
2796 static int match_section(const char *section_name,
2797                          int show_all_entries, AVDictionary *entries)
2798 {
2799     int i, ret = 0;
2800
2801     for (i = 0; i < FF_ARRAY_ELEMS(sections); i++) {
2802         const struct section *section = &sections[i];
2803         if (!strcmp(section_name, section->name) ||
2804             (section->unique_name && !strcmp(section_name, section->unique_name))) {
2805             av_log(NULL, AV_LOG_DEBUG,
2806                    "'%s' matches section with unique name '%s'\n", section_name,
2807                    (char *)av_x_if_null(section->unique_name, section->name));
2808             ret++;
2809             mark_section_show_entries(section->id, show_all_entries, entries);
2810         }
2811     }
2812     return ret;
2813 }
2814
2815 static int opt_show_entries(void *optctx, const char *opt, const char *arg)
2816 {
2817     const char *p = arg;
2818     int ret = 0;
2819
2820     while (*p) {
2821         AVDictionary *entries = NULL;
2822         char *section_name = av_get_token(&p, "=:");
2823         int show_all_entries = 0;
2824
2825         if (!section_name) {
2826             av_log(NULL, AV_LOG_ERROR,
2827                    "Missing section name for option '%s'\n", opt);
2828             return AVERROR(EINVAL);
2829         }
2830
2831         if (*p == '=') {
2832             p++;
2833             while (*p && *p != ':') {
2834                 char *entry = av_get_token(&p, ",:");
2835                 if (!entry)
2836                     break;
2837                 av_log(NULL, AV_LOG_VERBOSE,
2838                        "Adding '%s' to the entries to show in section '%s'\n",
2839                        entry, section_name);
2840                 av_dict_set(&entries, entry, "", AV_DICT_DONT_STRDUP_KEY);
2841                 if (*p == ',')
2842                     p++;
2843             }
2844         } else {
2845             show_all_entries = 1;
2846         }
2847
2848         ret = match_section(section_name, show_all_entries, entries);
2849         if (ret == 0) {
2850             av_log(NULL, AV_LOG_ERROR, "No match for section '%s'\n", section_name);
2851             ret = AVERROR(EINVAL);
2852         }
2853         av_dict_free(&entries);
2854         av_free(section_name);
2855
2856         if (ret <= 0)
2857             break;
2858         if (*p)
2859             p++;
2860     }
2861
2862     return ret;
2863 }
2864
2865 static int opt_show_format_entry(void *optctx, const char *opt, const char *arg)
2866 {
2867     char *buf = av_asprintf("format=%s", arg);
2868     int ret;
2869
2870     if (!buf)
2871         return AVERROR(ENOMEM);
2872
2873     av_log(NULL, AV_LOG_WARNING,
2874            "Option '%s' is deprecated, use '-show_entries format=%s' instead\n",
2875            opt, arg);
2876     ret = opt_show_entries(optctx, opt, buf);
2877     av_free(buf);
2878     return ret;
2879 }
2880
2881 static void opt_input_file(void *optctx, const char *arg)
2882 {
2883     if (input_filename) {
2884         av_log(NULL, AV_LOG_ERROR,
2885                 "Argument '%s' provided as input filename, but '%s' was already specified.\n",
2886                 arg, input_filename);
2887         exit_program(1);
2888     }
2889     if (!strcmp(arg, "-"))
2890         arg = "pipe:";
2891     input_filename = arg;
2892 }
2893
2894 static int opt_input_file_i(void *optctx, const char *opt, const char *arg)
2895 {
2896     opt_input_file(optctx, arg);
2897     return 0;
2898 }
2899
2900 void show_help_default(const char *opt, const char *arg)
2901 {
2902     av_log_set_callback(log_callback_help);
2903     show_usage();
2904     show_help_options(options, "Main options:", 0, 0, 0);
2905     printf("\n");
2906
2907     show_help_children(avformat_get_class(), AV_OPT_FLAG_DECODING_PARAM);
2908 }
2909
2910 /**
2911  * Parse interval specification, according to the format:
2912  * INTERVAL ::= [START|+START_OFFSET][%[END|+END_OFFSET]]
2913  * INTERVALS ::= INTERVAL[,INTERVALS]
2914 */
2915 static int parse_read_interval(const char *interval_spec,
2916                                ReadInterval *interval)
2917 {
2918     int ret = 0;
2919     char *next, *p, *spec = av_strdup(interval_spec);
2920     if (!spec)
2921         return AVERROR(ENOMEM);
2922
2923     if (!*spec) {
2924         av_log(NULL, AV_LOG_ERROR, "Invalid empty interval specification\n");
2925         ret = AVERROR(EINVAL);
2926         goto end;
2927     }
2928
2929     p = spec;
2930     next = strchr(spec, '%');
2931     if (next)
2932         *next++ = 0;
2933
2934     /* parse first part */
2935     if (*p) {
2936         interval->has_start = 1;
2937
2938         if (*p == '+') {
2939             interval->start_is_offset = 1;
2940             p++;
2941         } else {
2942             interval->start_is_offset = 0;
2943         }
2944
2945         ret = av_parse_time(&interval->start, p, 1);
2946         if (ret < 0) {
2947             av_log(NULL, AV_LOG_ERROR, "Invalid interval start specification '%s'\n", p);
2948             goto end;
2949         }
2950     } else {
2951         interval->has_start = 0;
2952     }
2953
2954     /* parse second part */
2955     p = next;
2956     if (p && *p) {
2957         int64_t us;
2958         interval->has_end = 1;
2959
2960         if (*p == '+') {
2961             interval->end_is_offset = 1;
2962             p++;
2963         } else {
2964             interval->end_is_offset = 0;
2965         }
2966
2967         if (interval->end_is_offset && *p == '#') {
2968             long long int lli;
2969             char *tail;
2970             interval->duration_frames = 1;
2971             p++;
2972             lli = strtoll(p, &tail, 10);
2973             if (*tail || lli < 0) {
2974                 av_log(NULL, AV_LOG_ERROR,
2975                        "Invalid or negative value '%s' for duration number of frames\n", p);
2976                 goto end;
2977             }
2978             interval->end = lli;
2979         } else {
2980             ret = av_parse_time(&us, p, 1);
2981             if (ret < 0) {
2982                 av_log(NULL, AV_LOG_ERROR, "Invalid interval end/duration specification '%s'\n", p);
2983                 goto end;
2984             }
2985             interval->end = us;
2986         }
2987     } else {
2988         interval->has_end = 0;
2989     }
2990
2991 end:
2992     av_free(spec);
2993     return ret;
2994 }
2995
2996 static int parse_read_intervals(const char *intervals_spec)
2997 {
2998     int ret, n, i;
2999     char *p, *spec = av_strdup(intervals_spec);
3000     if (!spec)
3001         return AVERROR(ENOMEM);
3002
3003     /* preparse specification, get number of intervals */
3004     for (n = 0, p = spec; *p; p++)
3005         if (*p == ',')
3006             n++;
3007     n++;
3008
3009     read_intervals = av_malloc_array(n, sizeof(*read_intervals));
3010     if (!read_intervals) {
3011         ret = AVERROR(ENOMEM);
3012         goto end;
3013     }
3014     read_intervals_nb = n;
3015
3016     /* parse intervals */
3017     p = spec;
3018     for (i = 0; p; i++) {
3019         char *next;
3020
3021         av_assert0(i < read_intervals_nb);
3022         next = strchr(p, ',');
3023         if (next)
3024             *next++ = 0;
3025
3026         read_intervals[i].id = i;
3027         ret = parse_read_interval(p, &read_intervals[i]);
3028         if (ret < 0) {
3029             av_log(NULL, AV_LOG_ERROR, "Error parsing read interval #%d '%s'\n",
3030                    i, p);
3031             goto end;
3032         }
3033         av_log(NULL, AV_LOG_VERBOSE, "Parsed log interval ");
3034         log_read_interval(&read_intervals[i], NULL, AV_LOG_VERBOSE);
3035         p = next;
3036     }
3037     av_assert0(i == read_intervals_nb);
3038
3039 end:
3040     av_free(spec);
3041     return ret;
3042 }
3043
3044 static int opt_read_intervals(void *optctx, const char *opt, const char *arg)
3045 {
3046     return parse_read_intervals(arg);
3047 }
3048
3049 static int opt_pretty(void *optctx, const char *opt, const char *arg)
3050 {
3051     show_value_unit              = 1;
3052     use_value_prefix             = 1;
3053     use_byte_value_binary_prefix = 1;
3054     use_value_sexagesimal_format = 1;
3055     return 0;
3056 }
3057
3058 static void print_section(SectionID id, int level)
3059 {
3060     const SectionID *pid;
3061     const struct section *section = &sections[id];
3062     printf("%c%c%c",
3063            section->flags & SECTION_FLAG_IS_WRAPPER           ? 'W' : '.',
3064            section->flags & SECTION_FLAG_IS_ARRAY             ? 'A' : '.',
3065            section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS  ? 'V' : '.');
3066     printf("%*c  %s", level * 4, ' ', section->name);
3067     if (section->unique_name)
3068         printf("/%s", section->unique_name);
3069     printf("\n");
3070
3071     for (pid = section->children_ids; *pid != -1; pid++)
3072         print_section(*pid, level+1);
3073 }
3074
3075 static int opt_sections(void *optctx, const char *opt, const char *arg)
3076 {
3077     printf("Sections:\n"
3078            "W.. = Section is a wrapper (contains other sections, no local entries)\n"
3079            ".A. = Section contains an array of elements of the same type\n"
3080            "..V = Section may contain a variable number of fields with variable keys\n"
3081            "FLAGS NAME/UNIQUE_NAME\n"
3082            "---\n");
3083     print_section(SECTION_ID_ROOT, 0);
3084     return 0;
3085 }
3086
3087 static int opt_show_versions(const char *opt, const char *arg)
3088 {
3089     mark_section_show_entries(SECTION_ID_PROGRAM_VERSION, 1, NULL);
3090     mark_section_show_entries(SECTION_ID_LIBRARY_VERSION, 1, NULL);
3091     return 0;
3092 }
3093
3094 #define DEFINE_OPT_SHOW_SECTION(section, target_section_id)             \
3095     static int opt_show_##section(const char *opt, const char *arg)     \
3096     {                                                                   \
3097         mark_section_show_entries(SECTION_ID_##target_section_id, 1, NULL); \
3098         return 0;                                                       \
3099     }
3100
3101 DEFINE_OPT_SHOW_SECTION(chapters,         CHAPTERS)
3102 DEFINE_OPT_SHOW_SECTION(error,            ERROR)
3103 DEFINE_OPT_SHOW_SECTION(format,           FORMAT)
3104 DEFINE_OPT_SHOW_SECTION(frames,           FRAMES)
3105 DEFINE_OPT_SHOW_SECTION(library_versions, LIBRARY_VERSIONS)
3106 DEFINE_OPT_SHOW_SECTION(packets,          PACKETS)
3107 DEFINE_OPT_SHOW_SECTION(pixel_formats,    PIXEL_FORMATS)
3108 DEFINE_OPT_SHOW_SECTION(program_version,  PROGRAM_VERSION)
3109 DEFINE_OPT_SHOW_SECTION(streams,          STREAMS)
3110 DEFINE_OPT_SHOW_SECTION(programs,         PROGRAMS)
3111
3112 static const OptionDef real_options[] = {
3113 #include "cmdutils_common_opts.h"
3114     { "f", HAS_ARG, {.func_arg = opt_format}, "force format", "format" },
3115     { "unit", OPT_BOOL, {&show_value_unit}, "show unit of the displayed values" },
3116     { "prefix", OPT_BOOL, {&use_value_prefix}, "use SI prefixes for the displayed values" },
3117     { "byte_binary_prefix", OPT_BOOL, {&use_byte_value_binary_prefix},
3118       "use binary prefixes for byte units" },
3119     { "sexagesimal", OPT_BOOL,  {&use_value_sexagesimal_format},
3120       "use sexagesimal format HOURS:MM:SS.MICROSECONDS for time units" },
3121     { "pretty", 0, {.func_arg = opt_pretty},
3122       "prettify the format of displayed values, make it more human readable" },
3123     { "print_format", OPT_STRING | HAS_ARG, {(void*)&print_format},
3124       "set the output printing format (available formats are: default, compact, csv, flat, ini, json, xml)", "format" },
3125     { "of", OPT_STRING | HAS_ARG, {(void*)&print_format}, "alias for -print_format", "format" },
3126     { "select_streams", OPT_STRING | HAS_ARG, {(void*)&stream_specifier}, "select the specified streams", "stream_specifier" },
3127     { "sections", OPT_EXIT, {.func_arg = opt_sections}, "print sections structure and section information, and exit" },
3128     { "show_data",    OPT_BOOL, {(void*)&do_show_data}, "show packets data" },
3129     { "show_data_hash", OPT_STRING | HAS_ARG, {(void*)&show_data_hash}, "show packets data hash" },
3130     { "show_error",   0, {(void*)&opt_show_error},  "show probing error" },
3131     { "show_format",  0, {(void*)&opt_show_format}, "show format/container info" },
3132     { "show_frames",  0, {(void*)&opt_show_frames}, "show frames info" },
3133     { "show_format_entry", HAS_ARG, {.func_arg = opt_show_format_entry},
3134       "show a particular entry from the format/container info", "entry" },
3135     { "show_entries", HAS_ARG, {.func_arg = opt_show_entries},
3136       "show a set of specified entries", "entry_list" },
3137     { "show_packets", 0, {(void*)&opt_show_packets}, "show packets info" },
3138     { "show_programs", 0, {(void*)&opt_show_programs}, "show programs info" },
3139     { "show_streams", 0, {(void*)&opt_show_streams}, "show streams info" },
3140     { "show_chapters", 0, {(void*)&opt_show_chapters}, "show chapters info" },
3141     { "count_frames", OPT_BOOL, {(void*)&do_count_frames}, "count the number of frames per stream" },
3142     { "count_packets", OPT_BOOL, {(void*)&do_count_packets}, "count the number of packets per stream" },
3143     { "show_program_version",  0, {(void*)&opt_show_program_version},  "show ffprobe version" },
3144     { "show_library_versions", 0, {(void*)&opt_show_library_versions}, "show library versions" },
3145     { "show_versions",         0, {(void*)&opt_show_versions}, "show program and library versions" },
3146     { "show_pixel_formats", 0, {(void*)&opt_show_pixel_formats}, "show pixel format descriptions" },
3147     { "show_private_data", OPT_BOOL, {(void*)&show_private_data}, "show private data" },
3148     { "private",           OPT_BOOL, {(void*)&show_private_data}, "same as show_private_data" },
3149     { "bitexact", OPT_BOOL, {&do_bitexact}, "force bitexact output" },
3150     { "read_intervals", HAS_ARG, {.func_arg = opt_read_intervals}, "set read intervals", "read_intervals" },
3151     { "default", HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, {.func_arg = opt_default}, "generic catch all option", "" },
3152     { "i", HAS_ARG, {.func_arg = opt_input_file_i}, "read specified file", "input_file"},
3153     { NULL, },
3154 };
3155
3156 static inline int check_section_show_entries(int section_id)
3157 {
3158     int *id;
3159     struct section *section = &sections[section_id];
3160     if (sections[section_id].show_all_entries || sections[section_id].entries_to_show)
3161         return 1;
3162     for (id = section->children_ids; *id != -1; id++)
3163         if (check_section_show_entries(*id))
3164             return 1;
3165     return 0;
3166 }
3167
3168 #define SET_DO_SHOW(id, varname) do {                                   \
3169         if (check_section_show_entries(SECTION_ID_##id))                \
3170             do_show_##varname = 1;                                      \
3171     } while (0)
3172
3173 int main(int argc, char **argv)
3174 {
3175     const Writer *w;
3176     WriterContext *wctx;
3177     char *buf;
3178     char *w_name = NULL, *w_args = NULL;
3179     int ret, i;
3180
3181     av_log_set_flags(AV_LOG_SKIP_REPEATED);
3182     register_exit(ffprobe_cleanup);
3183
3184     options = real_options;
3185     parse_loglevel(argc, argv, options);
3186     av_register_all();
3187     avformat_network_init();
3188     init_opts();
3189 #if CONFIG_AVDEVICE
3190     avdevice_register_all();
3191 #endif
3192
3193     show_banner(argc, argv, options);
3194     parse_options(NULL, argc, argv, options, opt_input_file);
3195
3196     /* mark things to show, based on -show_entries */
3197     SET_DO_SHOW(CHAPTERS, chapters);
3198     SET_DO_SHOW(ERROR, error);
3199     SET_DO_SHOW(FORMAT, format);
3200     SET_DO_SHOW(FRAMES, frames);
3201     SET_DO_SHOW(LIBRARY_VERSIONS, library_versions);
3202     SET_DO_SHOW(PACKETS, packets);
3203     SET_DO_SHOW(PIXEL_FORMATS, pixel_formats);
3204     SET_DO_SHOW(PIXEL_FORMAT_FLAGS, pixel_format_flags);
3205     SET_DO_SHOW(PIXEL_FORMAT_COMPONENTS, pixel_format_components);
3206     SET_DO_SHOW(PROGRAM_VERSION, program_version);
3207     SET_DO_SHOW(PROGRAMS, programs);
3208     SET_DO_SHOW(STREAMS, streams);
3209     SET_DO_SHOW(STREAM_DISPOSITION, stream_disposition);
3210     SET_DO_SHOW(PROGRAM_STREAM_DISPOSITION, stream_disposition);
3211
3212     SET_DO_SHOW(CHAPTER_TAGS, chapter_tags);
3213     SET_DO_SHOW(FORMAT_TAGS, format_tags);
3214     SET_DO_SHOW(FRAME_TAGS, frame_tags);
3215     SET_DO_SHOW(PROGRAM_TAGS, program_tags);
3216     SET_DO_SHOW(STREAM_TAGS, stream_tags);
3217     SET_DO_SHOW(PACKET_TAGS, packet_tags);
3218
3219     if (do_bitexact && (do_show_program_version || do_show_library_versions)) {
3220         av_log(NULL, AV_LOG_ERROR,
3221                "-bitexact and -show_program_version or -show_library_versions "
3222                "options are incompatible\n");
3223         ret = AVERROR(EINVAL);
3224         goto end;
3225     }
3226
3227     writer_register_all();
3228
3229     if (!print_format)
3230         print_format = av_strdup("default");
3231     if (!print_format) {
3232         ret = AVERROR(ENOMEM);
3233         goto end;
3234     }
3235     w_name = av_strtok(print_format, "=", &buf);
3236     w_args = buf;
3237
3238     if (show_data_hash) {
3239         if ((ret = av_hash_alloc(&hash, show_data_hash)) < 0) {
3240             if (ret == AVERROR(EINVAL)) {
3241                 const char *n;
3242                 av_log(NULL, AV_LOG_ERROR,
3243                        "Unknown hash algorithm '%s'\nKnown algorithms:",
3244                        show_data_hash);
3245                 for (i = 0; (n = av_hash_names(i)); i++)
3246                     av_log(NULL, AV_LOG_ERROR, " %s", n);
3247                 av_log(NULL, AV_LOG_ERROR, "\n");
3248             }
3249             goto end;
3250         }
3251     }
3252
3253     w = writer_get_by_name(w_name);
3254     if (!w) {
3255         av_log(NULL, AV_LOG_ERROR, "Unknown output format with name '%s'\n", w_name);
3256         ret = AVERROR(EINVAL);
3257         goto end;
3258     }
3259
3260     if ((ret = writer_open(&wctx, w, w_args,
3261                            sections, FF_ARRAY_ELEMS(sections))) >= 0) {
3262         if (w == &xml_writer)
3263             wctx->string_validation_utf8_flags |= AV_UTF8_FLAG_EXCLUDE_XML_INVALID_CONTROL_CODES;
3264
3265         writer_print_section_header(wctx, SECTION_ID_ROOT);
3266
3267         if (do_show_program_version)
3268             ffprobe_show_program_version(wctx);
3269         if (do_show_library_versions)
3270             ffprobe_show_library_versions(wctx);
3271         if (do_show_pixel_formats)
3272             ffprobe_show_pixel_formats(wctx);
3273
3274         if (!input_filename &&
3275             ((do_show_format || do_show_programs || do_show_streams || do_show_chapters || do_show_packets || do_show_error) ||
3276              (!do_show_program_version && !do_show_library_versions && !do_show_pixel_formats))) {
3277             show_usage();
3278             av_log(NULL, AV_LOG_ERROR, "You have to specify one input file.\n");
3279             av_log(NULL, AV_LOG_ERROR, "Use -h to get full help or, even better, run 'man %s'.\n", program_name);
3280             ret = AVERROR(EINVAL);
3281         } else if (input_filename) {
3282             ret = probe_file(wctx, input_filename);
3283             if (ret < 0 && do_show_error)
3284                 show_error(wctx, ret);
3285         }
3286
3287         writer_print_section_footer(wctx);
3288         writer_close(&wctx);
3289     }
3290
3291 end:
3292     av_freep(&print_format);
3293     av_freep(&read_intervals);
3294     av_hash_freep(&hash);
3295
3296     uninit_opts();
3297     for (i = 0; i < FF_ARRAY_ELEMS(sections); i++)
3298         av_dict_free(&(sections[i].entries_to_show));
3299
3300     avformat_network_deinit();
3301
3302     return ret < 0;
3303 }