GCC Code Coverage Report
Directory: ../../../ffmpeg/ Exec Total Coverage
File: src/fftools/ffprobe.c Lines: 1332 1905 69.9 %
Date: 2020-09-25 23:16:12 Branches: 739 1193 61.9 %

Line Branch Exec Source
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/mastering_display_metadata.h"
39
#include "libavutil/dovi_meta.h"
40
#include "libavutil/opt.h"
41
#include "libavutil/pixdesc.h"
42
#include "libavutil/spherical.h"
43
#include "libavutil/stereo3d.h"
44
#include "libavutil/dict.h"
45
#include "libavutil/intreadwrite.h"
46
#include "libavutil/libm.h"
47
#include "libavutil/parseutils.h"
48
#include "libavutil/timecode.h"
49
#include "libavutil/timestamp.h"
50
#include "libavdevice/avdevice.h"
51
#include "libswscale/swscale.h"
52
#include "libswresample/swresample.h"
53
#include "libpostproc/postprocess.h"
54
#include "cmdutils.h"
55
56
#include "libavutil/thread.h"
57
58
#if !HAVE_THREADS
59
#  ifdef pthread_mutex_lock
60
#    undef pthread_mutex_lock
61
#  endif
62
#  define pthread_mutex_lock(a) do{}while(0)
63
#  ifdef pthread_mutex_unlock
64
#    undef pthread_mutex_unlock
65
#  endif
66
#  define pthread_mutex_unlock(a) do{}while(0)
67
#endif
68
69
typedef struct InputStream {
70
    AVStream *st;
71
72
    AVCodecContext *dec_ctx;
73
} InputStream;
74
75
typedef struct InputFile {
76
    AVFormatContext *fmt_ctx;
77
78
    InputStream *streams;
79
    int       nb_streams;
80
} InputFile;
81
82
const char program_name[] = "ffprobe";
83
const int program_birth_year = 2007;
84
85
static int do_bitexact = 0;
86
static int do_count_frames = 0;
87
static int do_count_packets = 0;
88
static int do_read_frames  = 0;
89
static int do_read_packets = 0;
90
static int do_show_chapters = 0;
91
static int do_show_error   = 0;
92
static int do_show_format  = 0;
93
static int do_show_frames  = 0;
94
static int do_show_packets = 0;
95
static int do_show_programs = 0;
96
static int do_show_streams = 0;
97
static int do_show_stream_disposition = 0;
98
static int do_show_data    = 0;
99
static int do_show_program_version  = 0;
100
static int do_show_library_versions = 0;
101
static int do_show_pixel_formats = 0;
102
static int do_show_pixel_format_flags = 0;
103
static int do_show_pixel_format_components = 0;
104
static int do_show_log = 0;
105
106
static int do_show_chapter_tags = 0;
107
static int do_show_format_tags = 0;
108
static int do_show_frame_tags = 0;
109
static int do_show_program_tags = 0;
110
static int do_show_stream_tags = 0;
111
static int do_show_packet_tags = 0;
112
113
static int show_value_unit              = 0;
114
static int use_value_prefix             = 0;
115
static int use_byte_value_binary_prefix = 0;
116
static int use_value_sexagesimal_format = 0;
117
static int show_private_data            = 1;
118
119
static char *print_format;
120
static char *stream_specifier;
121
static char *show_data_hash;
122
123
typedef struct ReadInterval {
124
    int id;             ///< identifier
125
    int64_t start, end; ///< start, end in second/AV_TIME_BASE units
126
    int has_start, has_end;
127
    int start_is_offset, end_is_offset;
128
    int duration_frames;
129
} ReadInterval;
130
131
static ReadInterval *read_intervals;
132
static int read_intervals_nb = 0;
133
134
static int find_stream_info  = 1;
135
136
/* section structure definition */
137
138
#define SECTION_MAX_NB_CHILDREN 10
139
140
struct section {
141
    int id;             ///< unique id identifying a section
142
    const char *name;
143
144
#define SECTION_FLAG_IS_WRAPPER      1 ///< the section only contains other sections, but has no data at its own level
145
#define SECTION_FLAG_IS_ARRAY        2 ///< the section contains an array of elements of the same type
146
#define SECTION_FLAG_HAS_VARIABLE_FIELDS 4 ///< the section may contain a variable number of fields with variable keys.
147
                                           ///  For these sections the element_name field is mandatory.
148
    int flags;
149
    int children_ids[SECTION_MAX_NB_CHILDREN+1]; ///< list of children section IDS, terminated by -1
150
    const char *element_name; ///< name of the contained element, if provided
151
    const char *unique_name;  ///< unique section name, in case the name is ambiguous
152
    AVDictionary *entries_to_show;
153
    int show_all_entries;
154
};
155
156
typedef enum {
157
    SECTION_ID_NONE = -1,
158
    SECTION_ID_CHAPTER,
159
    SECTION_ID_CHAPTER_TAGS,
160
    SECTION_ID_CHAPTERS,
161
    SECTION_ID_ERROR,
162
    SECTION_ID_FORMAT,
163
    SECTION_ID_FORMAT_TAGS,
164
    SECTION_ID_FRAME,
165
    SECTION_ID_FRAMES,
166
    SECTION_ID_FRAME_TAGS,
167
    SECTION_ID_FRAME_SIDE_DATA_LIST,
168
    SECTION_ID_FRAME_SIDE_DATA,
169
    SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST,
170
    SECTION_ID_FRAME_SIDE_DATA_TIMECODE,
171
    SECTION_ID_FRAME_LOG,
172
    SECTION_ID_FRAME_LOGS,
173
    SECTION_ID_LIBRARY_VERSION,
174
    SECTION_ID_LIBRARY_VERSIONS,
175
    SECTION_ID_PACKET,
176
    SECTION_ID_PACKET_TAGS,
177
    SECTION_ID_PACKETS,
178
    SECTION_ID_PACKETS_AND_FRAMES,
179
    SECTION_ID_PACKET_SIDE_DATA_LIST,
180
    SECTION_ID_PACKET_SIDE_DATA,
181
    SECTION_ID_PIXEL_FORMAT,
182
    SECTION_ID_PIXEL_FORMAT_FLAGS,
183
    SECTION_ID_PIXEL_FORMAT_COMPONENT,
184
    SECTION_ID_PIXEL_FORMAT_COMPONENTS,
185
    SECTION_ID_PIXEL_FORMATS,
186
    SECTION_ID_PROGRAM_STREAM_DISPOSITION,
187
    SECTION_ID_PROGRAM_STREAM_TAGS,
188
    SECTION_ID_PROGRAM,
189
    SECTION_ID_PROGRAM_STREAMS,
190
    SECTION_ID_PROGRAM_STREAM,
191
    SECTION_ID_PROGRAM_TAGS,
192
    SECTION_ID_PROGRAM_VERSION,
193
    SECTION_ID_PROGRAMS,
194
    SECTION_ID_ROOT,
195
    SECTION_ID_STREAM,
196
    SECTION_ID_STREAM_DISPOSITION,
197
    SECTION_ID_STREAMS,
198
    SECTION_ID_STREAM_TAGS,
199
    SECTION_ID_STREAM_SIDE_DATA_LIST,
200
    SECTION_ID_STREAM_SIDE_DATA,
201
    SECTION_ID_SUBTITLE,
202
} SectionID;
203
204
static struct section sections[] = {
205
    [SECTION_ID_CHAPTERS] =           { SECTION_ID_CHAPTERS, "chapters", SECTION_FLAG_IS_ARRAY, { SECTION_ID_CHAPTER, -1 } },
206
    [SECTION_ID_CHAPTER] =            { SECTION_ID_CHAPTER, "chapter", 0, { SECTION_ID_CHAPTER_TAGS, -1 } },
207
    [SECTION_ID_CHAPTER_TAGS] =       { SECTION_ID_CHAPTER_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "chapter_tags" },
208
    [SECTION_ID_ERROR] =              { SECTION_ID_ERROR, "error", 0, { -1 } },
209
    [SECTION_ID_FORMAT] =             { SECTION_ID_FORMAT, "format", 0, { SECTION_ID_FORMAT_TAGS, -1 } },
210
    [SECTION_ID_FORMAT_TAGS] =        { SECTION_ID_FORMAT_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "format_tags" },
211
    [SECTION_ID_FRAMES] =             { SECTION_ID_FRAMES, "frames", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME, SECTION_ID_SUBTITLE, -1 } },
212
    [SECTION_ID_FRAME] =              { SECTION_ID_FRAME, "frame", 0, { SECTION_ID_FRAME_TAGS, SECTION_ID_FRAME_SIDE_DATA_LIST, SECTION_ID_FRAME_LOGS, -1 } },
213
    [SECTION_ID_FRAME_TAGS] =         { SECTION_ID_FRAME_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "frame_tags" },
214
    [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 }, .element_name = "side_data", .unique_name = "frame_side_data_list" },
215
    [SECTION_ID_FRAME_SIDE_DATA] =     { SECTION_ID_FRAME_SIDE_DATA, "side_data", 0, { SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST, -1 } },
216
    [SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST] =     { SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST, "timecodes", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_SIDE_DATA_TIMECODE, -1 } },
217
    [SECTION_ID_FRAME_SIDE_DATA_TIMECODE] =     { SECTION_ID_FRAME_SIDE_DATA_TIMECODE, "timecode", 0, { -1 } },
218
    [SECTION_ID_FRAME_LOGS] =         { SECTION_ID_FRAME_LOGS, "logs", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_LOG, -1 } },
219
    [SECTION_ID_FRAME_LOG] =          { SECTION_ID_FRAME_LOG, "log", 0, { -1 },  },
220
    [SECTION_ID_LIBRARY_VERSIONS] =   { SECTION_ID_LIBRARY_VERSIONS, "library_versions", SECTION_FLAG_IS_ARRAY, { SECTION_ID_LIBRARY_VERSION, -1 } },
221
    [SECTION_ID_LIBRARY_VERSION] =    { SECTION_ID_LIBRARY_VERSION, "library_version", 0, { -1 } },
222
    [SECTION_ID_PACKETS] =            { SECTION_ID_PACKETS, "packets", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET, -1} },
223
    [SECTION_ID_PACKETS_AND_FRAMES] = { SECTION_ID_PACKETS_AND_FRAMES, "packets_and_frames", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET, -1} },
224
    [SECTION_ID_PACKET] =             { SECTION_ID_PACKET, "packet", 0, { SECTION_ID_PACKET_TAGS, SECTION_ID_PACKET_SIDE_DATA_LIST, -1 } },
225
    [SECTION_ID_PACKET_TAGS] =        { SECTION_ID_PACKET_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "packet_tags" },
226
    [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 }, .element_name = "side_data", .unique_name = "packet_side_data_list" },
227
    [SECTION_ID_PACKET_SIDE_DATA] =     { SECTION_ID_PACKET_SIDE_DATA, "side_data", 0, { -1 } },
228
    [SECTION_ID_PIXEL_FORMATS] =      { SECTION_ID_PIXEL_FORMATS, "pixel_formats", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PIXEL_FORMAT, -1 } },
229
    [SECTION_ID_PIXEL_FORMAT] =       { SECTION_ID_PIXEL_FORMAT, "pixel_format", 0, { SECTION_ID_PIXEL_FORMAT_FLAGS, SECTION_ID_PIXEL_FORMAT_COMPONENTS, -1 } },
230
    [SECTION_ID_PIXEL_FORMAT_FLAGS] = { SECTION_ID_PIXEL_FORMAT_FLAGS, "flags", 0, { -1 }, .unique_name = "pixel_format_flags" },
231
    [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" },
232
    [SECTION_ID_PIXEL_FORMAT_COMPONENT]  = { SECTION_ID_PIXEL_FORMAT_COMPONENT, "component", 0, { -1 } },
233
    [SECTION_ID_PROGRAM_STREAM_DISPOSITION] = { SECTION_ID_PROGRAM_STREAM_DISPOSITION, "disposition", 0, { -1 }, .unique_name = "program_stream_disposition" },
234
    [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" },
235
    [SECTION_ID_PROGRAM] =                    { SECTION_ID_PROGRAM, "program", 0, { SECTION_ID_PROGRAM_TAGS, SECTION_ID_PROGRAM_STREAMS, -1 } },
236
    [SECTION_ID_PROGRAM_STREAMS] =            { SECTION_ID_PROGRAM_STREAMS, "streams", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PROGRAM_STREAM, -1 }, .unique_name = "program_streams" },
237
    [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" },
238
    [SECTION_ID_PROGRAM_TAGS] =               { SECTION_ID_PROGRAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "program_tags" },
239
    [SECTION_ID_PROGRAM_VERSION] =    { SECTION_ID_PROGRAM_VERSION, "program_version", 0, { -1 } },
240
    [SECTION_ID_PROGRAMS] =                   { SECTION_ID_PROGRAMS, "programs", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PROGRAM, -1 } },
241
    [SECTION_ID_ROOT] =               { SECTION_ID_ROOT, "root", SECTION_FLAG_IS_WRAPPER,
242
                                        { SECTION_ID_CHAPTERS, SECTION_ID_FORMAT, SECTION_ID_FRAMES, SECTION_ID_PROGRAMS, SECTION_ID_STREAMS,
243
                                          SECTION_ID_PACKETS, SECTION_ID_ERROR, SECTION_ID_PROGRAM_VERSION, SECTION_ID_LIBRARY_VERSIONS,
244
                                          SECTION_ID_PIXEL_FORMATS, -1} },
245
    [SECTION_ID_STREAMS] =            { SECTION_ID_STREAMS, "streams", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM, -1 } },
246
    [SECTION_ID_STREAM] =             { SECTION_ID_STREAM, "stream", 0, { SECTION_ID_STREAM_DISPOSITION, SECTION_ID_STREAM_TAGS, SECTION_ID_STREAM_SIDE_DATA_LIST, -1 } },
247
    [SECTION_ID_STREAM_DISPOSITION] = { SECTION_ID_STREAM_DISPOSITION, "disposition", 0, { -1 }, .unique_name = "stream_disposition" },
248
    [SECTION_ID_STREAM_TAGS] =        { SECTION_ID_STREAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "stream_tags" },
249
    [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 }, .element_name = "side_data", .unique_name = "stream_side_data_list" },
250
    [SECTION_ID_STREAM_SIDE_DATA] =     { SECTION_ID_STREAM_SIDE_DATA, "side_data", 0, { -1 } },
251
    [SECTION_ID_SUBTITLE] =           { SECTION_ID_SUBTITLE, "subtitle", 0, { -1 } },
252
};
253
254
static const OptionDef *options;
255
256
/* FFprobe context */
257
static const char *input_filename;
258
static const char *print_input_filename;
259
static AVInputFormat *iformat = NULL;
260
261
static struct AVHashContext *hash;
262
263
static const struct {
264
    double bin_val;
265
    double dec_val;
266
    const char *bin_str;
267
    const char *dec_str;
268
} si_prefixes[] = {
269
    { 1.0, 1.0, "", "" },
270
    { 1.024e3, 1e3, "Ki", "K" },
271
    { 1.048576e6, 1e6, "Mi", "M" },
272
    { 1.073741824e9, 1e9, "Gi", "G" },
273
    { 1.099511627776e12, 1e12, "Ti", "T" },
274
    { 1.125899906842624e15, 1e15, "Pi", "P" },
275
};
276
277
static const char unit_second_str[]         = "s"    ;
278
static const char unit_hertz_str[]          = "Hz"   ;
279
static const char unit_byte_str[]           = "byte" ;
280
static const char unit_bit_per_second_str[] = "bit/s";
281
282
static int nb_streams;
283
static uint64_t *nb_streams_packets;
284
static uint64_t *nb_streams_frames;
285
static int *selected_streams;
286
287
#if HAVE_THREADS
288
pthread_mutex_t log_mutex;
289
#endif
290
typedef struct LogBuffer {
291
    char *context_name;
292
    int log_level;
293
    char *log_message;
294
    AVClassCategory category;
295
    char *parent_name;
296
    AVClassCategory parent_category;
297
}LogBuffer;
298
299
static LogBuffer *log_buffer;
300
static int log_buffer_size;
301
302
static void log_callback(void *ptr, int level, const char *fmt, va_list vl)
303
{
304
    AVClass* avc = ptr ? *(AVClass **) ptr : NULL;
305
    va_list vl2;
306
    char line[1024];
307
    static int print_prefix = 1;
308
    void *new_log_buffer;
309
310
    va_copy(vl2, vl);
311
    av_log_default_callback(ptr, level, fmt, vl);
312
    av_log_format_line(ptr, level, fmt, vl2, line, sizeof(line), &print_prefix);
313
    va_end(vl2);
314
315
#if HAVE_THREADS
316
    pthread_mutex_lock(&log_mutex);
317
318
    new_log_buffer = av_realloc_array(log_buffer, log_buffer_size + 1, sizeof(*log_buffer));
319
    if (new_log_buffer) {
320
        char *msg;
321
        int i;
322
323
        log_buffer = new_log_buffer;
324
        memset(&log_buffer[log_buffer_size], 0, sizeof(log_buffer[log_buffer_size]));
325
        log_buffer[log_buffer_size].context_name= avc ? av_strdup(avc->item_name(ptr)) : NULL;
326
        if (avc) {
327
            if (avc->get_category) log_buffer[log_buffer_size].category = avc->get_category(ptr);
328
            else                   log_buffer[log_buffer_size].category = avc->category;
329
        }
330
        log_buffer[log_buffer_size].log_level   = level;
331
        msg = log_buffer[log_buffer_size].log_message = av_strdup(line);
332
        for (i=strlen(msg) - 1; i>=0 && msg[i] == '\n'; i--) {
333
            msg[i] = 0;
334
        }
335
        if (avc && avc->parent_log_context_offset) {
336
            AVClass** parent = *(AVClass ***) (((uint8_t *) ptr) +
337
                                   avc->parent_log_context_offset);
338
            if (parent && *parent) {
339
                log_buffer[log_buffer_size].parent_name = av_strdup((*parent)->item_name(parent));
340
                log_buffer[log_buffer_size].parent_category =
341
                    (*parent)->get_category ? (*parent)->get_category(parent) :(*parent)->category;
342
            }
343
        }
344
        log_buffer_size ++;
345
    }
346
347
    pthread_mutex_unlock(&log_mutex);
348
#endif
349
}
350
351
static void ffprobe_cleanup(int ret)
352
{
353
    int i;
354
    for (i = 0; i < FF_ARRAY_ELEMS(sections); i++)
355
        av_dict_free(&(sections[i].entries_to_show));
356
357
#if HAVE_THREADS
358
    pthread_mutex_destroy(&log_mutex);
359
#endif
360
}
361
362
struct unit_value {
363
    union { double d; long long int i; } val;
364
    const char *unit;
365
};
366
367
29286
static char *value_string(char *buf, int buf_size, struct unit_value uv)
368
{
369
    double vald;
370
    long long int vali;
371
29286
    int show_float = 0;
372
373
29286
    if (uv.unit == unit_second_str) {
374
22535
        vald = uv.val.d;
375
22535
        show_float = 1;
376
    } else {
377
6751
        vald = vali = uv.val.i;
378
    }
379
380

29286
    if (uv.unit == unit_second_str && use_value_sexagesimal_format) {
381
        double secs;
382
        int hours, mins;
383
        secs  = vald;
384
        mins  = (int)secs / 60;
385
        secs  = secs - mins * 60;
386
        hours = mins / 60;
387
        mins %= 60;
388
        snprintf(buf, buf_size, "%d:%02d:%09.6f", hours, mins, secs);
389
    } else {
390
29286
        const char *prefix_string = "";
391
392

29286
        if (use_value_prefix && vald > 1) {
393
            long long int index;
394
395
            if (uv.unit == unit_byte_str && use_byte_value_binary_prefix) {
396
                index = (long long int) (log2(vald)) / 10;
397
                index = av_clip(index, 0, FF_ARRAY_ELEMS(si_prefixes) - 1);
398
                vald /= si_prefixes[index].bin_val;
399
                prefix_string = si_prefixes[index].bin_str;
400
            } else {
401
                index = (long long int) (log10(vald)) / 3;
402
                index = av_clip(index, 0, FF_ARRAY_ELEMS(si_prefixes) - 1);
403
                vald /= si_prefixes[index].dec_val;
404
                prefix_string = si_prefixes[index].dec_str;
405
            }
406
            vali = vald;
407
        }
408
409

29286
        if (show_float || (use_value_prefix && vald != (long long int)vald))
410
22535
            snprintf(buf, buf_size, "%f", vald);
411
        else
412
6751
            snprintf(buf, buf_size, "%lld", vali);
413

29286
        av_strlcatf(buf, buf_size, "%s%s%s", *prefix_string || show_value_unit ? " " : "",
414
29286
                 prefix_string, show_value_unit ? uv.unit : "");
415
    }
416
417
29286
    return buf;
418
}
419
420
/* WRITERS API */
421
422
typedef struct WriterContext WriterContext;
423
424
#define WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS 1
425
#define WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER 2
426
427
typedef enum {
428
    WRITER_STRING_VALIDATION_FAIL,
429
    WRITER_STRING_VALIDATION_REPLACE,
430
    WRITER_STRING_VALIDATION_IGNORE,
431
    WRITER_STRING_VALIDATION_NB
432
} StringValidation;
433
434
typedef struct Writer {
435
    const AVClass *priv_class;      ///< private class of the writer, if any
436
    int priv_size;                  ///< private size for the writer context
437
    const char *name;
438
439
    int  (*init)  (WriterContext *wctx);
440
    void (*uninit)(WriterContext *wctx);
441
442
    void (*print_section_header)(WriterContext *wctx);
443
    void (*print_section_footer)(WriterContext *wctx);
444
    void (*print_integer)       (WriterContext *wctx, const char *, long long int);
445
    void (*print_rational)      (WriterContext *wctx, AVRational *q, char *sep);
446
    void (*print_string)        (WriterContext *wctx, const char *, const char *);
447
    int flags;                  ///< a combination or WRITER_FLAG_*
448
} Writer;
449
450
#define SECTION_MAX_NB_LEVELS 10
451
452
struct WriterContext {
453
    const AVClass *class;           ///< class of the writer
454
    const Writer *writer;           ///< the Writer of which this is an instance
455
    char *name;                     ///< name of this writer instance
456
    void *priv;                     ///< private data for use by the filter
457
458
    const struct section *sections; ///< array containing all sections
459
    int nb_sections;                ///< number of sections
460
461
    int level;                      ///< current level, starting from 0
462
463
    /** number of the item printed in the given section, starting from 0 */
464
    unsigned int nb_item[SECTION_MAX_NB_LEVELS];
465
466
    /** section per each level */
467
    const struct section *section[SECTION_MAX_NB_LEVELS];
468
    AVBPrint section_pbuf[SECTION_MAX_NB_LEVELS]; ///< generic print buffer dedicated to each section,
469
                                                  ///  used by various writers
470
471
    unsigned int nb_section_packet; ///< number of the packet section in case we are in "packets_and_frames" section
472
    unsigned int nb_section_frame;  ///< number of the frame  section in case we are in "packets_and_frames" section
473
    unsigned int nb_section_packet_frame; ///< nb_section_packet or nb_section_frame according if is_packets_and_frames
474
475
    int string_validation;
476
    char *string_validation_replacement;
477
    unsigned int string_validation_utf8_flags;
478
};
479
480
static const char *writer_get_name(void *p)
481
{
482
    WriterContext *wctx = p;
483
    return wctx->writer->name;
484
}
485
486
#define OFFSET(x) offsetof(WriterContext, x)
487
488
static const AVOption writer_options[] = {
489
    { "string_validation", "set string validation mode",
490
      OFFSET(string_validation), AV_OPT_TYPE_INT, {.i64=WRITER_STRING_VALIDATION_REPLACE}, 0, WRITER_STRING_VALIDATION_NB-1, .unit = "sv" },
491
    { "sv", "set string validation mode",
492
      OFFSET(string_validation), AV_OPT_TYPE_INT, {.i64=WRITER_STRING_VALIDATION_REPLACE}, 0, WRITER_STRING_VALIDATION_NB-1, .unit = "sv" },
493
    { "ignore",  NULL, 0, AV_OPT_TYPE_CONST, {.i64 = WRITER_STRING_VALIDATION_IGNORE},  .unit = "sv" },
494
    { "replace", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = WRITER_STRING_VALIDATION_REPLACE}, .unit = "sv" },
495
    { "fail",    NULL, 0, AV_OPT_TYPE_CONST, {.i64 = WRITER_STRING_VALIDATION_FAIL},    .unit = "sv" },
496
    { "string_validation_replacement", "set string validation replacement string", OFFSET(string_validation_replacement), AV_OPT_TYPE_STRING, {.str=""}},
497
    { "svr", "set string validation replacement string", OFFSET(string_validation_replacement), AV_OPT_TYPE_STRING, {.str="\xEF\xBF\xBD"}},
498
    { NULL }
499
};
500
501
26
static void *writer_child_next(void *obj, void *prev)
502
{
503
26
    WriterContext *ctx = obj;
504


26
    if (!prev && ctx->writer && ctx->writer->priv_class && ctx->priv)
505
26
        return ctx->priv;
506
    return NULL;
507
}
508
509
static const AVClass writer_class = {
510
    .class_name = "Writer",
511
    .item_name  = writer_get_name,
512
    .option     = writer_options,
513
    .version    = LIBAVUTIL_VERSION_INT,
514
    .child_next = writer_child_next,
515
};
516
517
74
static void writer_close(WriterContext **wctx)
518
{
519
    int i;
520
521
74
    if (!*wctx)
522
        return;
523
524
74
    if ((*wctx)->writer->uninit)
525
        (*wctx)->writer->uninit(*wctx);
526
814
    for (i = 0; i < SECTION_MAX_NB_LEVELS; i++)
527
740
        av_bprint_finalize(&(*wctx)->section_pbuf[i], NULL);
528
74
    if ((*wctx)->writer->priv_class)
529
74
        av_opt_free((*wctx)->priv);
530
74
    av_freep(&((*wctx)->priv));
531
74
    av_opt_free(*wctx);
532
74
    av_freep(wctx);
533
}
534
535
static void bprint_bytes(AVBPrint *bp, const uint8_t *ubuf, size_t ubuf_size)
536
{
537
    int i;
538
    av_bprintf(bp, "0X");
539
    for (i = 0; i < ubuf_size; i++)
540
        av_bprintf(bp, "%02X", ubuf[i]);
541
}
542
543
544
74
static int writer_open(WriterContext **wctx, const Writer *writer, const char *args,
545
                       const struct section *sections, int nb_sections)
546
{
547
74
    int i, ret = 0;
548
549
74
    if (!(*wctx = av_mallocz(sizeof(WriterContext)))) {
550
        ret = AVERROR(ENOMEM);
551
        goto fail;
552
    }
553
554
74
    if (!((*wctx)->priv = av_mallocz(writer->priv_size))) {
555
        ret = AVERROR(ENOMEM);
556
        goto fail;
557
    }
558
559
74
    (*wctx)->class = &writer_class;
560
74
    (*wctx)->writer = writer;
561
74
    (*wctx)->level = -1;
562
74
    (*wctx)->sections = sections;
563
74
    (*wctx)->nb_sections = nb_sections;
564
565
74
    av_opt_set_defaults(*wctx);
566
567
74
    if (writer->priv_class) {
568
74
        void *priv_ctx = (*wctx)->priv;
569
74
        *((const AVClass **)priv_ctx) = writer->priv_class;
570
74
        av_opt_set_defaults(priv_ctx);
571
    }
572
573
    /* convert options to dictionary */
574
74
    if (args) {
575
19
        AVDictionary *opts = NULL;
576
19
        AVDictionaryEntry *opt = NULL;
577
578
19
        if ((ret = av_dict_parse_string(&opts, args, "=", ":", 0)) < 0) {
579
            av_log(*wctx, AV_LOG_ERROR, "Failed to parse option string '%s' provided to writer context\n", args);
580
            av_dict_free(&opts);
581
            goto fail;
582
        }
583
584
45
        while ((opt = av_dict_get(opts, "", opt, AV_DICT_IGNORE_SUFFIX))) {
585
26
            if ((ret = av_opt_set(*wctx, opt->key, opt->value, AV_OPT_SEARCH_CHILDREN)) < 0) {
586
                av_log(*wctx, AV_LOG_ERROR, "Failed to set option '%s' with value '%s' provided to writer context\n",
587
                       opt->key, opt->value);
588
                av_dict_free(&opts);
589
                goto fail;
590
            }
591
        }
592
593
19
        av_dict_free(&opts);
594
    }
595
596
    /* validate replace string */
597
    {
598
74
        const uint8_t *p = (*wctx)->string_validation_replacement;
599
74
        const uint8_t *endp = p + strlen(p);
600
148
        while (*p) {
601
74
            const uint8_t *p0 = p;
602
            int32_t code;
603
74
            ret = av_utf8_decode(&code, &p, endp, (*wctx)->string_validation_utf8_flags);
604
74
            if (ret < 0) {
605
                AVBPrint bp;
606
                av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC);
607
                bprint_bytes(&bp, p0, p-p0),
608
                    av_log(wctx, AV_LOG_ERROR,
609
                           "Invalid UTF8 sequence %s found in string validation replace '%s'\n",
610
                           bp.str, (*wctx)->string_validation_replacement);
611
                return ret;
612
            }
613
        }
614
    }
615
616
814
    for (i = 0; i < SECTION_MAX_NB_LEVELS; i++)
617
740
        av_bprint_init(&(*wctx)->section_pbuf[i], 1, AV_BPRINT_SIZE_UNLIMITED);
618
619
74
    if ((*wctx)->writer->init)
620
32
        ret = (*wctx)->writer->init(*wctx);
621
74
    if (ret < 0)
622
        goto fail;
623
624
74
    return 0;
625
626
fail:
627
    writer_close(wctx);
628
    return ret;
629
}
630
631
8140
static inline void writer_print_section_header(WriterContext *wctx,
632
                                               int section_id)
633
{
634
    int parent_section_id;
635
8140
    wctx->level++;
636
8140
    av_assert0(wctx->level < SECTION_MAX_NB_LEVELS);
637
16280
    parent_section_id = wctx->level ?
638
8140
        (wctx->section[wctx->level-1])->id : SECTION_ID_NONE;
639
640
8140
    wctx->nb_item[wctx->level] = 0;
641
8140
    wctx->section[wctx->level] = &wctx->sections[section_id];
642
643
8140
    if (section_id == SECTION_ID_PACKETS_AND_FRAMES) {
644
4
        wctx->nb_section_packet = wctx->nb_section_frame =
645
4
        wctx->nb_section_packet_frame = 0;
646
8136
    } else if (parent_section_id == SECTION_ID_PACKETS_AND_FRAMES) {
647
112
        wctx->nb_section_packet_frame = section_id == SECTION_ID_PACKET ?
648
112
            wctx->nb_section_packet : wctx->nb_section_frame;
649
    }
650
651
8140
    if (wctx->writer->print_section_header)
652
8140
        wctx->writer->print_section_header(wctx);
653
8140
}
654
655
8140
static inline void writer_print_section_footer(WriterContext *wctx)
656
{
657
8140
    int section_id = wctx->section[wctx->level]->id;
658
16280
    int parent_section_id = wctx->level ?
659
8140
        wctx->section[wctx->level-1]->id : SECTION_ID_NONE;
660
661
8140
    if (parent_section_id != SECTION_ID_NONE)
662
8066
        wctx->nb_item[wctx->level-1]++;
663
8140
    if (parent_section_id == SECTION_ID_PACKETS_AND_FRAMES) {
664
112
        if (section_id == SECTION_ID_PACKET) wctx->nb_section_packet++;
665
56
        else                                     wctx->nb_section_frame++;
666
    }
667
8140
    if (wctx->writer->print_section_footer)
668
8056
        wctx->writer->print_section_footer(wctx);
669
8140
    wctx->level--;
670
8140
}
671
672
41597
static inline void writer_print_integer(WriterContext *wctx,
673
                                        const char *key, long long int val)
674
{
675
41597
    const struct section *section = wctx->section[wctx->level];
676
677

41597
    if (section->show_all_entries || av_dict_get(section->entries_to_show, key, NULL, 0)) {
678
27064
        wctx->writer->print_integer(wctx, key, val);
679
27064
        wctx->nb_item[wctx->level]++;
680
    }
681
41597
}
682
683
4984
static inline int validate_string(WriterContext *wctx, char **dstp, const char *src)
684
{
685
    const uint8_t *p, *endp;
686
    AVBPrint dstbuf;
687
4984
    int invalid_chars_nb = 0, ret = 0;
688
689
4984
    av_bprint_init(&dstbuf, 0, AV_BPRINT_SIZE_UNLIMITED);
690
691
4984
    endp = src + strlen(src);
692
84202
    for (p = (uint8_t *)src; *p;) {
693
        uint32_t code;
694
79218
        int invalid = 0;
695
79218
        const uint8_t *p0 = p;
696
697
79218
        if (av_utf8_decode(&code, &p, endp, wctx->string_validation_utf8_flags) < 0) {
698
            AVBPrint bp;
699
            av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC);
700
            bprint_bytes(&bp, p0, p-p0);
701
            av_log(wctx, AV_LOG_DEBUG,
702
                   "Invalid UTF-8 sequence %s found in string '%s'\n", bp.str, src);
703
            invalid = 1;
704
        }
705
706
79218
        if (invalid) {
707
            invalid_chars_nb++;
708
709
            switch (wctx->string_validation) {
710
            case WRITER_STRING_VALIDATION_FAIL:
711
                av_log(wctx, AV_LOG_ERROR,
712
                       "Invalid UTF-8 sequence found in string '%s'\n", src);
713
                ret = AVERROR_INVALIDDATA;
714
                goto end;
715
                break;
716
717
            case WRITER_STRING_VALIDATION_REPLACE:
718
                av_bprintf(&dstbuf, "%s", wctx->string_validation_replacement);
719
                break;
720
            }
721
79218
        }
722
723

79218
        if (!invalid || wctx->string_validation == WRITER_STRING_VALIDATION_IGNORE)
724
79218
            av_bprint_append_data(&dstbuf, p0, p-p0);
725
    }
726
727

4984
    if (invalid_chars_nb && wctx->string_validation == WRITER_STRING_VALIDATION_REPLACE) {
728
        av_log(wctx, AV_LOG_WARNING,
729
               "%d invalid UTF-8 sequence(s) found in string '%s', replaced with '%s'\n",
730
               invalid_chars_nb, src, wctx->string_validation_replacement);
731
    }
732
733
4984
end:
734
4984
    av_bprint_finalize(&dstbuf, dstp);
735
4984
    return ret;
736
}
737
738
#define PRINT_STRING_OPT      1
739
#define PRINT_STRING_VALIDATE 2
740
741
67840
static inline int writer_print_string(WriterContext *wctx,
742
                                      const char *key, const char *val, int flags)
743
{
744
67840
    const struct section *section = wctx->section[wctx->level];
745
67840
    int ret = 0;
746
747
67840
    if ((flags & PRINT_STRING_OPT)
748
11530
        && !(wctx->writer->flags & WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS))
749
224
        return 0;
750
751

67616
    if (section->show_all_entries || av_dict_get(section->entries_to_show, key, NULL, 0)) {
752
24849
        if (flags & PRINT_STRING_VALIDATE) {
753
2492
            char *key1 = NULL, *val1 = NULL;
754
2492
            ret = validate_string(wctx, &key1, key);
755
2492
            if (ret < 0) goto end;
756
2492
            ret = validate_string(wctx, &val1, val);
757
2492
            if (ret < 0) goto end;
758
2492
            wctx->writer->print_string(wctx, key1, val1);
759
2492
        end:
760
2492
            if (ret < 0) {
761
                av_log(wctx, AV_LOG_ERROR,
762
                       "Invalid key=value string combination %s=%s in section %s\n",
763
                       key, val, section->unique_name);
764
            }
765
2492
            av_free(key1);
766
2492
            av_free(val1);
767
        } else {
768
22357
            wctx->writer->print_string(wctx, key, val);
769
        }
770
771
24849
        wctx->nb_item[wctx->level]++;
772
    }
773
774
67616
    return ret;
775
}
776
777
881
static inline void writer_print_rational(WriterContext *wctx,
778
                                         const char *key, AVRational q, char sep)
779
{
780
    AVBPrint buf;
781
881
    av_bprint_init(&buf, 0, AV_BPRINT_SIZE_AUTOMATIC);
782
881
    av_bprintf(&buf, "%d%c%d", q.num, sep, q.den);
783
881
    writer_print_string(wctx, key, buf.str, 0);
784
881
}
785
786
26684
static void writer_print_time(WriterContext *wctx, const char *key,
787
                              int64_t ts, const AVRational *time_base, int is_duration)
788
{
789
    char buf[128];
790
791


26684
    if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0)) {
792
4149
        writer_print_string(wctx, key, "N/A", PRINT_STRING_OPT);
793
    } else {
794
22535
        double d = ts * av_q2d(*time_base);
795
        struct unit_value uv;
796
22535
        uv.val.d = d;
797
22535
        uv.unit = unit_second_str;
798
22535
        value_string(buf, sizeof(buf), uv);
799
22535
        writer_print_string(wctx, key, buf, 0);
800
    }
801
26684
}
802
803
26618
static void writer_print_ts(WriterContext *wctx, const char *key, int64_t ts, int is_duration)
804
{
805


26618
    if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0)) {
806
4149
        writer_print_string(wctx, key, "N/A", PRINT_STRING_OPT);
807
    } else {
808
22469
        writer_print_integer(wctx, key, ts);
809
    }
810
26618
}
811
812
static void writer_print_data(WriterContext *wctx, const char *name,
813
                              uint8_t *data, int size)
814
{
815
    AVBPrint bp;
816
    int offset = 0, l, i;
817
818
    av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED);
819
    av_bprintf(&bp, "\n");
820
    while (size) {
821
        av_bprintf(&bp, "%08x: ", offset);
822
        l = FFMIN(size, 16);
823
        for (i = 0; i < l; i++) {
824
            av_bprintf(&bp, "%02x", data[i]);
825
            if (i & 1)
826
                av_bprintf(&bp, " ");
827
        }
828
        av_bprint_chars(&bp, ' ', 41 - 2 * i - i / 2);
829
        for (i = 0; i < l; i++)
830
            av_bprint_chars(&bp, data[i] - 32U < 95 ? data[i] : '.', 1);
831
        av_bprintf(&bp, "\n");
832
        offset += l;
833
        data   += l;
834
        size   -= l;
835
    }
836
    writer_print_string(wctx, name, bp.str, 0);
837
    av_bprint_finalize(&bp, NULL);
838
}
839
840
3674
static void writer_print_data_hash(WriterContext *wctx, const char *name,
841
                                   uint8_t *data, int size)
842
{
843
3674
    char *p, buf[AV_HASH_MAX_SIZE * 2 + 64] = { 0 };
844
845
3674
    if (!hash)
846
3670
        return;
847
4
    av_hash_init(hash);
848
4
    av_hash_update(hash, data, size);
849
4
    snprintf(buf, sizeof(buf), "%s:", av_hash_get_name(hash));
850
4
    p = buf + strlen(buf);
851
4
    av_hash_final_hex(hash, p, buf + sizeof(buf) - p);
852
4
    writer_print_string(wctx, name, buf, 0);
853
}
854
855
2
static void writer_print_integers(WriterContext *wctx, const char *name,
856
                                  uint8_t *data, int size, const char *format,
857
                                  int columns, int bytes, int offset_add)
858
{
859
    AVBPrint bp;
860
2
    int offset = 0, l, i;
861
862
2
    av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED);
863
2
    av_bprintf(&bp, "\n");
864
8
    while (size) {
865
6
        av_bprintf(&bp, "%08x: ", offset);
866
6
        l = FFMIN(size, columns);
867
24
        for (i = 0; i < l; i++) {
868
18
            if      (bytes == 1) av_bprintf(&bp, format, *data);
869
18
            else if (bytes == 2) av_bprintf(&bp, format, AV_RN16(data));
870
18
            else if (bytes == 4) av_bprintf(&bp, format, AV_RN32(data));
871
18
            data += bytes;
872
18
            size --;
873
        }
874
6
        av_bprintf(&bp, "\n");
875
6
        offset += offset_add;
876
    }
877
2
    writer_print_string(wctx, name, bp.str, 0);
878
2
    av_bprint_finalize(&bp, NULL);
879
2
}
880
881
#define MAX_REGISTERED_WRITERS_NB 64
882
883
static const Writer *registered_writers[MAX_REGISTERED_WRITERS_NB + 1];
884
885
518
static int writer_register(const Writer *writer)
886
{
887
    static int next_registered_writer_idx = 0;
888
889
518
    if (next_registered_writer_idx == MAX_REGISTERED_WRITERS_NB)
890
        return AVERROR(ENOMEM);
891
892
518
    registered_writers[next_registered_writer_idx++] = writer;
893
518
    return 0;
894
}
895
896
74
static const Writer *writer_get_by_name(const char *name)
897
{
898
    int i;
899
900
122
    for (i = 0; registered_writers[i]; i++)
901
122
        if (!strcmp(registered_writers[i]->name, name))
902
74
            return registered_writers[i];
903
904
    return NULL;
905
}
906
907
908
/* WRITERS */
909
910
#define DEFINE_WRITER_CLASS(name)                   \
911
static const char *name##_get_name(void *ctx)       \
912
{                                                   \
913
    return #name ;                                  \
914
}                                                   \
915
static const AVClass name##_class = {               \
916
    .class_name = #name,                            \
917
    .item_name  = name##_get_name,                  \
918
    .option     = name##_options                    \
919
}
920
921
/* Default output */
922
923
typedef struct DefaultContext {
924
    const AVClass *class;
925
    int nokey;
926
    int noprint_wrappers;
927
    int nested_section[SECTION_MAX_NB_LEVELS];
928
} DefaultContext;
929
930
#undef OFFSET
931
#define OFFSET(x) offsetof(DefaultContext, x)
932
933
static const AVOption default_options[] = {
934
    { "noprint_wrappers", "do not print headers and footers", OFFSET(noprint_wrappers), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
935
    { "nw",               "do not print headers and footers", OFFSET(noprint_wrappers), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
936
    { "nokey",          "force no key printing",     OFFSET(nokey),          AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
937
    { "nk",             "force no key printing",     OFFSET(nokey),          AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
938
    {NULL},
939
};
940
941
DEFINE_WRITER_CLASS(default);
942
943
/* lame uppercasing routine, assumes the string is lower case ASCII */
944
2315
static inline char *upcase_string(char *dst, size_t dst_size, const char *src)
945
{
946
    int i;
947

16826
    for (i = 0; src[i] && i < dst_size-1; i++)
948
14511
        dst[i] = av_toupper(src[i]);
949
2315
    dst[i] = 0;
950
2315
    return dst;
951
}
952
953
1403
static void default_print_section_header(WriterContext *wctx)
954
{
955
1403
    DefaultContext *def = wctx->priv;
956
    char buf[32];
957
1403
    const struct section *section = wctx->section[wctx->level];
958
2806
    const struct section *parent_section = wctx->level ?
959
1403
        wctx->section[wctx->level-1] : NULL;
960
961
1403
    av_bprint_clear(&wctx->section_pbuf[wctx->level]);
962
1403
    if (parent_section &&
963
1362
        !(parent_section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))) {
964
277
        def->nested_section[wctx->level] = 1;
965
277
        av_bprintf(&wctx->section_pbuf[wctx->level], "%s%s:",
966
277
                   wctx->section_pbuf[wctx->level-1].str,
967
                   upcase_string(buf, sizeof(buf),
968
277
                                 av_x_if_null(section->element_name, section->name)));
969
    }
970
971

1403
    if (def->noprint_wrappers || def->nested_section[wctx->level])
972
285
        return;
973
974
1118
    if (!(section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY)))
975
1019
        printf("[%s]\n", upcase_string(buf, sizeof(buf), section->name));
976
}
977
978
1403
static void default_print_section_footer(WriterContext *wctx)
979
{
980
1403
    DefaultContext *def = wctx->priv;
981
1403
    const struct section *section = wctx->section[wctx->level];
982
    char buf[32];
983
984

1403
    if (def->noprint_wrappers || def->nested_section[wctx->level])
985
285
        return;
986
987
1118
    if (!(section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY)))
988
1019
        printf("[/%s]\n", upcase_string(buf, sizeof(buf), section->name));
989
}
990
991
8518
static void default_print_str(WriterContext *wctx, const char *key, const char *value)
992
{
993
8518
    DefaultContext *def = wctx->priv;
994
995
8518
    if (!def->nokey)
996
8514
        printf("%s%s=", wctx->section_pbuf[wctx->level].str, key);
997
8518
    printf("%s\n", value);
998
8518
}
999
1000
4033
static void default_print_int(WriterContext *wctx, const char *key, long long int value)
1001
{
1002
4033
    DefaultContext *def = wctx->priv;
1003
1004
4033
    if (!def->nokey)
1005
4033
        printf("%s%s=", wctx->section_pbuf[wctx->level].str, key);
1006
4033
    printf("%lld\n", value);
1007
4033
}
1008
1009
static const Writer default_writer = {
1010
    .name                  = "default",
1011
    .priv_size             = sizeof(DefaultContext),
1012
    .print_section_header  = default_print_section_header,
1013
    .print_section_footer  = default_print_section_footer,
1014
    .print_integer         = default_print_int,
1015
    .print_string          = default_print_str,
1016
    .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS,
1017
    .priv_class            = &default_class,
1018
};
1019
1020
/* Compact output */
1021
1022
/**
1023
 * Apply C-language-like string escaping.
1024
 */
1025
14580
static const char *c_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
1026
{
1027
    const char *p;
1028
1029
88225
    for (p = src; *p; p++) {
1030

73645
        switch (*p) {
1031
        case '\b': av_bprintf(dst, "%s", "\\b");  break;
1032
        case '\f': av_bprintf(dst, "%s", "\\f");  break;
1033
4
        case '\n': av_bprintf(dst, "%s", "\\n");  break;
1034
        case '\r': av_bprintf(dst, "%s", "\\r");  break;
1035
        case '\\': av_bprintf(dst, "%s", "\\\\"); break;
1036
73641
        default:
1037
73641
            if (*p == sep)
1038
                av_bprint_chars(dst, '\\', 1);
1039
73641
            av_bprint_chars(dst, *p, 1);
1040
        }
1041
    }
1042
14580
    return dst->str;
1043
}
1044
1045
/**
1046
 * Quote fields containing special characters, check RFC4180.
1047
 */
1048
395
static const char *csv_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
1049
{
1050
395
    char meta_chars[] = { sep, '"', '\n', '\r', '\0' };
1051
395
    int needs_quoting = !!src[strcspn(src, meta_chars)];
1052
1053
395
    if (needs_quoting)
1054
1
        av_bprint_chars(dst, '"', 1);
1055
1056
2812
    for (; *src; src++) {
1057
2417
        if (*src == '"')
1058
2
            av_bprint_chars(dst, '"', 1);
1059
2417
        av_bprint_chars(dst, *src, 1);
1060
    }
1061
395
    if (needs_quoting)
1062
1
        av_bprint_chars(dst, '"', 1);
1063
395
    return dst->str;
1064
}
1065
1066
static const char *none_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
1067
{
1068
    return src;
1069
}
1070
1071
typedef struct CompactContext {
1072
    const AVClass *class;
1073
    char *item_sep_str;
1074
    char item_sep;
1075
    int nokey;
1076
    int print_section;
1077
    char *escape_mode_str;
1078
    const char * (*escape_str)(AVBPrint *dst, const char *src, const char sep, void *log_ctx);
1079
    int nested_section[SECTION_MAX_NB_LEVELS];
1080
    int has_nested_elems[SECTION_MAX_NB_LEVELS];
1081
    int terminate_line[SECTION_MAX_NB_LEVELS];
1082
} CompactContext;
1083
1084
#undef OFFSET
1085
#define OFFSET(x) offsetof(CompactContext, x)
1086
1087
static const AVOption compact_options[]= {
1088
    {"item_sep", "set item separator",    OFFSET(item_sep_str),    AV_OPT_TYPE_STRING, {.str="|"},  0, 0 },
1089
    {"s",        "set item separator",    OFFSET(item_sep_str),    AV_OPT_TYPE_STRING, {.str="|"},  0, 0 },
1090
    {"nokey",    "force no key printing", OFFSET(nokey),           AV_OPT_TYPE_BOOL,   {.i64=0},    0,        1        },
1091
    {"nk",       "force no key printing", OFFSET(nokey),           AV_OPT_TYPE_BOOL,   {.i64=0},    0,        1        },
1092
    {"escape",   "set escape mode",       OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="c"},  0, 0 },
1093
    {"e",        "set escape mode",       OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="c"},  0, 0 },
1094
    {"print_section", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL,   {.i64=1},    0,        1        },
1095
    {"p",             "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL,   {.i64=1},    0,        1        },
1096
    {NULL},
1097
};
1098
1099
DEFINE_WRITER_CLASS(compact);
1100
1101
29
static av_cold int compact_init(WriterContext *wctx)
1102
{
1103
29
    CompactContext *compact = wctx->priv;
1104
1105
29
    if (strlen(compact->item_sep_str) != 1) {
1106
        av_log(wctx, AV_LOG_ERROR, "Item separator '%s' specified, but must contain a single character\n",
1107
               compact->item_sep_str);
1108
        return AVERROR(EINVAL);
1109
    }
1110
29
    compact->item_sep = compact->item_sep_str[0];
1111
1112
29
    if      (!strcmp(compact->escape_mode_str, "none")) compact->escape_str = none_escape_str;
1113
29
    else if (!strcmp(compact->escape_mode_str, "c"   )) compact->escape_str = c_escape_str;
1114
1
    else if (!strcmp(compact->escape_mode_str, "csv" )) compact->escape_str = csv_escape_str;
1115
    else {
1116
        av_log(wctx, AV_LOG_ERROR, "Unknown escape mode '%s'\n", compact->escape_mode_str);
1117
        return AVERROR(EINVAL);
1118
    }
1119
1120
29
    return 0;
1121
}
1122
1123
6569
static void compact_print_section_header(WriterContext *wctx)
1124
{
1125
6569
    CompactContext *compact = wctx->priv;
1126
6569
    const struct section *section = wctx->section[wctx->level];
1127
13138
    const struct section *parent_section = wctx->level ?
1128
6569
        wctx->section[wctx->level-1] : NULL;
1129
6569
    compact->terminate_line[wctx->level] = 1;
1130
6569
    compact->has_nested_elems[wctx->level] = 0;
1131
1132
6569
    av_bprint_clear(&wctx->section_pbuf[wctx->level]);
1133

6569
    if (!(section->flags & SECTION_FLAG_IS_ARRAY) && parent_section &&
1134
6323
        !(parent_section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))) {
1135
462
        compact->nested_section[wctx->level] = 1;
1136
462
        compact->has_nested_elems[wctx->level-1] = 1;
1137
462
        av_bprintf(&wctx->section_pbuf[wctx->level], "%s%s:",
1138
462
                   wctx->section_pbuf[wctx->level-1].str,
1139
462
                   (char *)av_x_if_null(section->element_name, section->name));
1140
462
        wctx->nb_item[wctx->level] = wctx->nb_item[wctx->level-1];
1141
    } else {
1142

6107
        if (parent_section && compact->has_nested_elems[wctx->level-1] &&
1143
32
            (section->flags & SECTION_FLAG_IS_ARRAY)) {
1144
32
            compact->terminate_line[wctx->level-1] = 0;
1145
32
            printf("\n");
1146
        }
1147
6107
        if (compact->print_section &&
1148
4891
            !(section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY)))
1149
4773
            printf("%s%c", section->name, compact->item_sep);
1150
    }
1151
6569
}
1152
1153
6569
static void compact_print_section_footer(WriterContext *wctx)
1154
{
1155
6569
    CompactContext *compact = wctx->priv;
1156
1157
6569
    if (!compact->nested_section[wctx->level] &&
1158
6075
        compact->terminate_line[wctx->level] &&
1159
6043
        !(wctx->section[wctx->level]->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY)))
1160
5829
        printf("\n");
1161
6569
}
1162
1163
14975
static void compact_print_str(WriterContext *wctx, const char *key, const char *value)
1164
{
1165
14975
    CompactContext *compact = wctx->priv;
1166
    AVBPrint buf;
1167
1168
14975
    if (wctx->nb_item[wctx->level]) printf("%c", compact->item_sep);
1169
14975
    if (!compact->nokey)
1170
11415
        printf("%s%s=", wctx->section_pbuf[wctx->level].str, key);
1171
14975
    av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
1172
14975
    printf("%s", compact->escape_str(&buf, value, compact->item_sep, wctx));
1173
14975
    av_bprint_finalize(&buf, NULL);
1174
14975
}
1175
1176
21947
static void compact_print_int(WriterContext *wctx, const char *key, long long int value)
1177
{
1178
21947
    CompactContext *compact = wctx->priv;
1179
1180
21947
    if (wctx->nb_item[wctx->level]) printf("%c", compact->item_sep);
1181
21947
    if (!compact->nokey)
1182
20284
        printf("%s%s=", wctx->section_pbuf[wctx->level].str, key);
1183
21947
    printf("%lld", value);
1184
21947
}
1185
1186
static const Writer compact_writer = {
1187
    .name                 = "compact",
1188
    .priv_size            = sizeof(CompactContext),
1189
    .init                 = compact_init,
1190
    .print_section_header = compact_print_section_header,
1191
    .print_section_footer = compact_print_section_footer,
1192
    .print_integer        = compact_print_int,
1193
    .print_string         = compact_print_str,
1194
    .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS,
1195
    .priv_class           = &compact_class,
1196
};
1197
1198
/* CSV output */
1199
1200
#undef OFFSET
1201
#define OFFSET(x) offsetof(CompactContext, x)
1202
1203
static const AVOption csv_options[] = {
1204
    {"item_sep", "set item separator",    OFFSET(item_sep_str),    AV_OPT_TYPE_STRING, {.str=","},  0, 0 },
1205
    {"s",        "set item separator",    OFFSET(item_sep_str),    AV_OPT_TYPE_STRING, {.str=","},  0, 0 },
1206
    {"nokey",    "force no key printing", OFFSET(nokey),           AV_OPT_TYPE_BOOL,   {.i64=1},    0,        1        },
1207
    {"nk",       "force no key printing", OFFSET(nokey),           AV_OPT_TYPE_BOOL,   {.i64=1},    0,        1        },
1208
    {"escape",   "set escape mode",       OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="csv"}, 0, 0 },
1209
    {"e",        "set escape mode",       OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="csv"}, 0, 0 },
1210
    {"print_section", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL,   {.i64=1},    0,        1        },
1211
    {"p",             "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL,   {.i64=1},    0,        1        },
1212
    {NULL},
1213
};
1214
1215
DEFINE_WRITER_CLASS(csv);
1216
1217
static const Writer csv_writer = {
1218
    .name                 = "csv",
1219
    .priv_size            = sizeof(CompactContext),
1220
    .init                 = compact_init,
1221
    .print_section_header = compact_print_section_header,
1222
    .print_section_footer = compact_print_section_footer,
1223
    .print_integer        = compact_print_int,
1224
    .print_string         = compact_print_str,
1225
    .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS,
1226
    .priv_class           = &csv_class,
1227
};
1228
1229
/* Flat output */
1230
1231
typedef struct FlatContext {
1232
    const AVClass *class;
1233
    const char *sep_str;
1234
    char sep;
1235
    int hierarchical;
1236
} FlatContext;
1237
1238
#undef OFFSET
1239
#define OFFSET(x) offsetof(FlatContext, x)
1240
1241
static const AVOption flat_options[]= {
1242
    {"sep_char", "set separator",    OFFSET(sep_str),    AV_OPT_TYPE_STRING, {.str="."},  0, 0 },
1243
    {"s",        "set separator",    OFFSET(sep_str),    AV_OPT_TYPE_STRING, {.str="."},  0, 0 },
1244
    {"hierarchical", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
1245
    {"h",            "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
1246
    {NULL},
1247
};
1248
1249
DEFINE_WRITER_CLASS(flat);
1250
1251
1
static av_cold int flat_init(WriterContext *wctx)
1252
{
1253
1
    FlatContext *flat = wctx->priv;
1254
1255
1
    if (strlen(flat->sep_str) != 1) {
1256
        av_log(wctx, AV_LOG_ERROR, "Item separator '%s' specified, but must contain a single character\n",
1257
               flat->sep_str);
1258
        return AVERROR(EINVAL);
1259
    }
1260
1
    flat->sep = flat->sep_str[0];
1261
1262
1
    return 0;
1263
}
1264
1265
395
static const char *flat_escape_key_str(AVBPrint *dst, const char *src, const char sep)
1266
{
1267
    const char *p;
1268
1269
5013
    for (p = src; *p; p++) {
1270

4618
        if (!((*p >= '0' && *p <= '9') ||
1271

4617
              (*p >= 'a' && *p <= 'z') ||
1272

455
              (*p >= 'A' && *p <= 'Z')))
1273
454
            av_bprint_chars(dst, '_', 1);
1274
        else
1275
4164
            av_bprint_chars(dst, *p, 1);
1276
    }
1277
395
    return dst->str;
1278
}
1279
1280
395
static const char *flat_escape_value_str(AVBPrint *dst, const char *src)
1281
{
1282
    const char *p;
1283
1284
2812
    for (p = src; *p; p++) {
1285

2417
        switch (*p) {
1286
        case '\n': av_bprintf(dst, "%s", "\\n");  break;
1287
        case '\r': av_bprintf(dst, "%s", "\\r");  break;
1288
        case '\\': av_bprintf(dst, "%s", "\\\\"); break;
1289
2
        case '"':  av_bprintf(dst, "%s", "\\\""); break;
1290
        case '`':  av_bprintf(dst, "%s", "\\`");  break;
1291
        case '$':  av_bprintf(dst, "%s", "\\$");  break;
1292
2415
        default:   av_bprint_chars(dst, *p, 1);   break;
1293
        }
1294
    }
1295
395
    return dst->str;
1296
}
1297
1298
42
static void flat_print_section_header(WriterContext *wctx)
1299
{
1300
42
    FlatContext *flat = wctx->priv;
1301
42
    AVBPrint *buf = &wctx->section_pbuf[wctx->level];
1302
42
    const struct section *section = wctx->section[wctx->level];
1303
84
    const struct section *parent_section = wctx->level ?
1304
42
        wctx->section[wctx->level-1] : NULL;
1305
1306
    /* build section header */
1307
42
    av_bprint_clear(buf);
1308
42
    if (!parent_section)
1309
1
        return;
1310
41
    av_bprintf(buf, "%s", wctx->section_pbuf[wctx->level-1].str);
1311
1312
41
    if (flat->hierarchical ||
1313
        !(section->flags & (SECTION_FLAG_IS_ARRAY|SECTION_FLAG_IS_WRAPPER))) {
1314
41
        av_bprintf(buf, "%s%s", wctx->section[wctx->level]->name, flat->sep_str);
1315
1316
41
        if (parent_section->flags & SECTION_FLAG_IS_ARRAY) {
1317
62
            int n = parent_section->id == SECTION_ID_PACKETS_AND_FRAMES ?
1318
31
                wctx->nb_section_packet_frame : wctx->nb_item[wctx->level-1];
1319
31
            av_bprintf(buf, "%d%s", n, flat->sep_str);
1320
        }
1321
    }
1322
}
1323
1324
271
static void flat_print_int(WriterContext *wctx, const char *key, long long int value)
1325
{
1326
271
    printf("%s%s=%lld\n", wctx->section_pbuf[wctx->level].str, key, value);
1327
271
}
1328
1329
395
static void flat_print_str(WriterContext *wctx, const char *key, const char *value)
1330
{
1331
395
    FlatContext *flat = wctx->priv;
1332
    AVBPrint buf;
1333
1334
395
    printf("%s", wctx->section_pbuf[wctx->level].str);
1335
395
    av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
1336
395
    printf("%s=", flat_escape_key_str(&buf, key, flat->sep));
1337
395
    av_bprint_clear(&buf);
1338
395
    printf("\"%s\"\n", flat_escape_value_str(&buf, value));
1339
395
    av_bprint_finalize(&buf, NULL);
1340
395
}
1341
1342
static const Writer flat_writer = {
1343
    .name                  = "flat",
1344
    .priv_size             = sizeof(FlatContext),
1345
    .init                  = flat_init,
1346
    .print_section_header  = flat_print_section_header,
1347
    .print_integer         = flat_print_int,
1348
    .print_string          = flat_print_str,
1349
    .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS|WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER,
1350
    .priv_class            = &flat_class,
1351
};
1352
1353
/* INI format output */
1354
1355
typedef struct INIContext {
1356
    const AVClass *class;
1357
    int hierarchical;
1358
} INIContext;
1359
1360
#undef OFFSET
1361
#define OFFSET(x) offsetof(INIContext, x)
1362
1363
static const AVOption ini_options[] = {
1364
    {"hierarchical", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
1365
    {"h",            "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
1366
    {NULL},
1367
};
1368
1369
DEFINE_WRITER_CLASS(ini);
1370
1371
790
static char *ini_escape_str(AVBPrint *dst, const char *src)
1372
{
1373
790
    int i = 0;
1374
790
    char c = 0;
1375
1376
7825
    while (c = src[i++]) {
1377

7035
        switch (c) {
1378
        case '\b': av_bprintf(dst, "%s", "\\b"); break;
1379
        case '\f': av_bprintf(dst, "%s", "\\f"); break;
1380
        case '\n': av_bprintf(dst, "%s", "\\n"); break;
1381
        case '\r': av_bprintf(dst, "%s", "\\r"); break;
1382
        case '\t': av_bprintf(dst, "%s", "\\t"); break;
1383
14
        case '\\':
1384
        case '#' :
1385
        case '=' :
1386
14
        case ':' : av_bprint_chars(dst, '\\', 1);
1387
7035
        default:
1388
7035
            if ((unsigned char)c < 32)
1389
                av_bprintf(dst, "\\x00%02x", c & 0xff);
1390
            else
1391
7035
                av_bprint_chars(dst, c, 1);
1392
7035
            break;
1393
        }
1394
    }
1395
790
    return dst->str;
1396
}
1397
1398
42
static void ini_print_section_header(WriterContext *wctx)
1399
{
1400
42
    INIContext *ini = wctx->priv;
1401
42
    AVBPrint *buf = &wctx->section_pbuf[wctx->level];
1402
42
    const struct section *section = wctx->section[wctx->level];
1403
84
    const struct section *parent_section = wctx->level ?
1404
42
        wctx->section[wctx->level-1] : NULL;
1405
1406
42
    av_bprint_clear(buf);
1407
42
    if (!parent_section) {
1408
1
        printf("# ffprobe output\n\n");
1409
1
        return;
1410
    }
1411
1412
41
    if (wctx->nb_item[wctx->level-1])
1413
38
        printf("\n");
1414
1415
41
    av_bprintf(buf, "%s", wctx->section_pbuf[wctx->level-1].str);
1416
41
    if (ini->hierarchical ||
1417
        !(section->flags & (SECTION_FLAG_IS_ARRAY|SECTION_FLAG_IS_WRAPPER))) {
1418
41
        av_bprintf(buf, "%s%s", buf->str[0] ? "." : "", wctx->section[wctx->level]->name);
1419
1420
41
        if (parent_section->flags & SECTION_FLAG_IS_ARRAY) {
1421
62
            int n = parent_section->id == SECTION_ID_PACKETS_AND_FRAMES ?
1422
31
                wctx->nb_section_packet_frame : wctx->nb_item[wctx->level-1];
1423
31
            av_bprintf(buf, ".%d", n);
1424
        }
1425
    }
1426
1427
41
    if (!(section->flags & (SECTION_FLAG_IS_ARRAY|SECTION_FLAG_IS_WRAPPER)))
1428
39
        printf("[%s]\n", buf->str);
1429
}
1430
1431
395
static void ini_print_str(WriterContext *wctx, const char *key, const char *value)
1432
{
1433
    AVBPrint buf;
1434
1435
395
    av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
1436
395
    printf("%s=", ini_escape_str(&buf, key));
1437
395
    av_bprint_clear(&buf);
1438
395
    printf("%s\n", ini_escape_str(&buf, value));
1439
395
    av_bprint_finalize(&buf, NULL);
1440
395
}
1441
1442
271
static void ini_print_int(WriterContext *wctx, const char *key, long long int value)
1443
{
1444
271
    printf("%s=%lld\n", key, value);
1445
271
}
1446
1447
static const Writer ini_writer = {
1448
    .name                  = "ini",
1449
    .priv_size             = sizeof(INIContext),
1450
    .print_section_header  = ini_print_section_header,
1451
    .print_integer         = ini_print_int,
1452
    .print_string          = ini_print_str,
1453
    .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS|WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER,
1454
    .priv_class            = &ini_class,
1455
};
1456
1457
/* JSON output */
1458
1459
typedef struct JSONContext {
1460
    const AVClass *class;
1461
    int indent_level;
1462
    int compact;
1463
    const char *item_sep, *item_start_end;
1464
} JSONContext;
1465
1466
#undef OFFSET
1467
#define OFFSET(x) offsetof(JSONContext, x)
1468
1469
static const AVOption json_options[]= {
1470
    { "compact", "enable compact output", OFFSET(compact), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
1471
    { "c",       "enable compact output", OFFSET(compact), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
1472
    { NULL }
1473
};
1474
1475
DEFINE_WRITER_CLASS(json);
1476
1477
1
static av_cold int json_init(WriterContext *wctx)
1478
{
1479
1
    JSONContext *json = wctx->priv;
1480
1481
1
    json->item_sep       = json->compact ? ", " : ",\n";
1482
1
    json->item_start_end = json->compact ? " "  : "\n";
1483
1484
1
    return 0;
1485
}
1486
1487
878
static const char *json_escape_str(AVBPrint *dst, const char *src, void *log_ctx)
1488
{
1489
    static const char json_escape[] = {'"', '\\', '\b', '\f', '\n', '\r', '\t', 0};
1490
    static const char json_subst[]  = {'"', '\\',  'b',  'f',  'n',  'r',  't', 0};
1491
    const char *p;
1492
1493
8664
    for (p = src; *p; p++) {
1494
7786
        char *s = strchr(json_escape, *p);
1495
7786
        if (s) {
1496
2
            av_bprint_chars(dst, '\\', 1);
1497
2
            av_bprint_chars(dst, json_subst[s - json_escape], 1);
1498
7784
        } else if ((unsigned char)*p < 32) {
1499
            av_bprintf(dst, "\\u00%02x", *p & 0xff);
1500
        } else {
1501
7784
            av_bprint_chars(dst, *p, 1);
1502
        }
1503
    }
1504
878
    return dst->str;
1505
}
1506
1507
#define JSON_INDENT() printf("%*c", json->indent_level * 4, ' ')
1508
1509
42
static void json_print_section_header(WriterContext *wctx)
1510
{
1511
42
    JSONContext *json = wctx->priv;
1512
    AVBPrint buf;
1513
42
    const struct section *section = wctx->section[wctx->level];
1514
84
    const struct section *parent_section = wctx->level ?
1515
42
        wctx->section[wctx->level-1] : NULL;
1516
1517

42
    if (wctx->level && wctx->nb_item[wctx->level-1])
1518
38
        printf(",\n");
1519
1520
42
    if (section->flags & SECTION_FLAG_IS_WRAPPER) {
1521
1
        printf("{\n");
1522
1
        json->indent_level++;
1523
    } else {
1524
41
        av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
1525
41
        json_escape_str(&buf, section->name, wctx);
1526
41
        JSON_INDENT();
1527
1528
41
        json->indent_level++;
1529
41
        if (section->flags & SECTION_FLAG_IS_ARRAY) {
1530
2
            printf("\"%s\": [\n", buf.str);
1531

39
        } else if (parent_section && !(parent_section->flags & SECTION_FLAG_IS_ARRAY)) {
1532
8
            printf("\"%s\": {%s", buf.str, json->item_start_end);
1533
        } else {
1534
31
            printf("{%s", json->item_start_end);
1535
1536
            /* this is required so the parser can distinguish between packets and frames */
1537

31
            if (parent_section && parent_section->id == SECTION_ID_PACKETS_AND_FRAMES) {
1538
28
                if (!json->compact)
1539
28
                    JSON_INDENT();
1540
28
                printf("\"type\": \"%s\"", section->name);
1541
            }
1542
        }
1543
41
        av_bprint_finalize(&buf, NULL);
1544
    }
1545
42
}
1546
1547
42
static void json_print_section_footer(WriterContext *wctx)
1548
{
1549
42
    JSONContext *json = wctx->priv;
1550
42
    const struct section *section = wctx->section[wctx->level];
1551
1552
42
    if (wctx->level == 0) {
1553
1
        json->indent_level--;
1554
1
        printf("\n}\n");
1555
41
    } else if (section->flags & SECTION_FLAG_IS_ARRAY) {
1556
2
        printf("\n");
1557
2
        json->indent_level--;
1558
2
        JSON_INDENT();
1559
2
        printf("]");
1560
    } else {
1561
39
        printf("%s", json->item_start_end);
1562
39
        json->indent_level--;
1563
39
        if (!json->compact)
1564
39
            JSON_INDENT();
1565
39
        printf("}");
1566
    }
1567
42
}
1568
1569
283
static inline void json_print_item_str(WriterContext *wctx,
1570
                                       const char *key, const char *value)
1571
{
1572
    AVBPrint buf;
1573
1574
283
    av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
1575
283
    printf("\"%s\":", json_escape_str(&buf, key,   wctx));
1576
283
    av_bprint_clear(&buf);
1577
283
    printf(" \"%s\"", json_escape_str(&buf, value, wctx));
1578
283
    av_bprint_finalize(&buf, NULL);
1579
283
}
1580
1581
283
static void json_print_str(WriterContext *wctx, const char *key, const char *value)
1582
{
1583
283
    JSONContext *json = wctx->priv;
1584
566
    const struct section *parent_section = wctx->level ?
1585
283
        wctx->section[wctx->level-1] : NULL;
1586
1587

283
    if (wctx->nb_item[wctx->level] || (parent_section && parent_section->id == SECTION_ID_PACKETS_AND_FRAMES))
1588
278
        printf("%s", json->item_sep);
1589
283
    if (!json->compact)
1590
283
        JSON_INDENT();
1591
283
    json_print_item_str(wctx, key, value);
1592
283
}
1593
1594
271
static void json_print_int(WriterContext *wctx, const char *key, long long int value)
1595
{
1596
271
    JSONContext *json = wctx->priv;
1597
542
    const struct section *parent_section = wctx->level ?
1598
271
        wctx->section[wctx->level-1] : NULL;
1599
    AVBPrint buf;
1600
1601

271
    if (wctx->nb_item[wctx->level] || (parent_section && parent_section->id == SECTION_ID_PACKETS_AND_FRAMES))
1602
265
        printf("%s", json->item_sep);
1603
271
    if (!json->compact)
1604
271
        JSON_INDENT();
1605
1606
271
    av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
1607
271
    printf("\"%s\": %lld", json_escape_str(&buf, key, wctx), value);
1608
271
    av_bprint_finalize(&buf, NULL);
1609
271
}
1610
1611
static const Writer json_writer = {
1612
    .name                 = "json",
1613
    .priv_size            = sizeof(JSONContext),
1614
    .init                 = json_init,
1615
    .print_section_header = json_print_section_header,
1616
    .print_section_footer = json_print_section_footer,
1617
    .print_integer        = json_print_int,
1618
    .print_string         = json_print_str,
1619
    .flags = WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER,
1620
    .priv_class           = &json_class,
1621
};
1622
1623
/* XML output */
1624
1625
typedef struct XMLContext {
1626
    const AVClass *class;
1627
    int within_tag;
1628
    int indent_level;
1629
    int fully_qualified;
1630
    int xsd_strict;
1631
} XMLContext;
1632
1633
#undef OFFSET
1634
#define OFFSET(x) offsetof(XMLContext, x)
1635
1636
static const AVOption xml_options[] = {
1637
    {"fully_qualified", "specify if the output should be fully qualified", OFFSET(fully_qualified), AV_OPT_TYPE_BOOL, {.i64=0},  0, 1 },
1638
    {"q",               "specify if the output should be fully qualified", OFFSET(fully_qualified), AV_OPT_TYPE_BOOL, {.i64=0},  0, 1 },
1639
    {"xsd_strict",      "ensure that the output is XSD compliant",         OFFSET(xsd_strict),      AV_OPT_TYPE_BOOL, {.i64=0},  0, 1 },
1640
    {"x",               "ensure that the output is XSD compliant",         OFFSET(xsd_strict),      AV_OPT_TYPE_BOOL, {.i64=0},  0, 1 },
1641
    {NULL},
1642
};
1643
1644
DEFINE_WRITER_CLASS(xml);
1645
1646
1
static av_cold int xml_init(WriterContext *wctx)
1647
{
1648
1
    XMLContext *xml = wctx->priv;
1649
1650
1
    if (xml->xsd_strict) {
1651
        xml->fully_qualified = 1;
1652
#define CHECK_COMPLIANCE(opt, opt_name)                                 \
1653
        if (opt) {                                                      \
1654
            av_log(wctx, AV_LOG_ERROR,                                  \
1655
                   "XSD-compliant output selected but option '%s' was selected, XML output may be non-compliant.\n" \
1656
                   "You need to disable such option with '-no%s'\n", opt_name, opt_name); \
1657
            return AVERROR(EINVAL);                                     \
1658
        }
1659
        CHECK_COMPLIANCE(show_private_data, "private");
1660
        CHECK_COMPLIANCE(show_value_unit,   "unit");
1661
        CHECK_COMPLIANCE(use_value_prefix,  "prefix");
1662
1663
        if (do_show_frames && do_show_packets) {
1664
            av_log(wctx, AV_LOG_ERROR,
1665
                   "Interleaved frames and packets are not allowed in XSD. "
1666
                   "Select only one between the -show_frames and the -show_packets options.\n");
1667
            return AVERROR(EINVAL);
1668
        }
1669
    }
1670
1671
1
    return 0;
1672
}
1673
1674
292
static const char *xml_escape_str(AVBPrint *dst, const char *src, void *log_ctx)
1675
{
1676
    const char *p;
1677
1678
2143
    for (p = src; *p; p++) {
1679

1851
        switch (*p) {
1680
1
        case '&' : av_bprintf(dst, "%s", "&amp;");  break;
1681
1
        case '<' : av_bprintf(dst, "%s", "&lt;");   break;
1682
1
        case '>' : av_bprintf(dst, "%s", "&gt;");   break;
1683
2
        case '"' : av_bprintf(dst, "%s", "&quot;"); break;
1684
2
        case '\'': av_bprintf(dst, "%s", "&apos;"); break;
1685
1844
        default: av_bprint_chars(dst, *p, 1);
1686
        }
1687
    }
1688
1689
292
    return dst->str;
1690
}
1691
1692
#define XML_INDENT() printf("%*c", xml->indent_level * 4, ' ')
1693
1694
42
static void xml_print_section_header(WriterContext *wctx)
1695
{
1696
42
    XMLContext *xml = wctx->priv;
1697
42
    const struct section *section = wctx->section[wctx->level];
1698
84
    const struct section *parent_section = wctx->level ?
1699
42
        wctx->section[wctx->level-1] : NULL;
1700
1701
42
    if (wctx->level == 0) {
1702
1
        const char *qual = " xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' "
1703
            "xmlns:ffprobe='http://www.ffmpeg.org/schema/ffprobe' "
1704
            "xsi:schemaLocation='http://www.ffmpeg.org/schema/ffprobe ffprobe.xsd'";
1705
1706
1
        printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1707
2
        printf("<%sffprobe%s>\n",
1708
1
               xml->fully_qualified ? "ffprobe:" : "",
1709
1
               xml->fully_qualified ? qual : "");
1710
1
        return;
1711
    }
1712
1713
41
    if (xml->within_tag) {
1714
4
        xml->within_tag = 0;
1715
4
        printf(">\n");
1716
    }
1717
41
    if (section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS) {
1718
4
        xml->indent_level++;
1719
    } else {
1720

37
        if (parent_section && (parent_section->flags & SECTION_FLAG_IS_WRAPPER) &&
1721

3
            wctx->level && wctx->nb_item[wctx->level-1])
1722
2
            printf("\n");
1723
37
        xml->indent_level++;
1724
1725
37
        if (section->flags & SECTION_FLAG_IS_ARRAY) {
1726
2
            XML_INDENT(); printf("<%s>\n", section->name);
1727
        } else {
1728
35
            XML_INDENT(); printf("<%s ", section->name);
1729
35
            xml->within_tag = 1;
1730
        }
1731
    }
1732
}
1733
1734
42
static void xml_print_section_footer(WriterContext *wctx)
1735
{
1736
42
    XMLContext *xml = wctx->priv;
1737
42
    const struct section *section = wctx->section[wctx->level];
1738
1739
42
    if (wctx->level == 0) {
1740
1
        printf("</%sffprobe>\n", xml->fully_qualified ? "ffprobe:" : "");
1741
41
    } else if (xml->within_tag) {
1742
31
        xml->within_tag = 0;
1743
31
        printf("/>\n");
1744
31
        xml->indent_level--;
1745
10
    } else if (section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS) {
1746
4
        xml->indent_level--;
1747
    } else {
1748
6
        XML_INDENT(); printf("</%s>\n", section->name);
1749
6
        xml->indent_level--;
1750
    }
1751
42
}
1752
1753
283
static void xml_print_str(WriterContext *wctx, const char *key, const char *value)
1754
{
1755
    AVBPrint buf;
1756
283
    XMLContext *xml = wctx->priv;
1757
283
    const struct section *section = wctx->section[wctx->level];
1758
1759
283
    av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
1760
1761
283
    if (section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS) {
1762
9
        XML_INDENT();
1763
9
        printf("<%s key=\"%s\"",
1764
               section->element_name, xml_escape_str(&buf, key, wctx));
1765
9
        av_bprint_clear(&buf);
1766
9
        printf(" value=\"%s\"/>\n", xml_escape_str(&buf, value, wctx));
1767
    } else {
1768
274
        if (wctx->nb_item[wctx->level])
1769
245
            printf(" ");
1770
274
        printf("%s=\"%s\"", key, xml_escape_str(&buf, value, wctx));
1771
    }
1772
1773
283
    av_bprint_finalize(&buf, NULL);
1774
283
}
1775
1776
271
static void xml_print_int(WriterContext *wctx, const char *key, long long int value)
1777
{
1778
271
    if (wctx->nb_item[wctx->level])
1779
265
        printf(" ");
1780
271
    printf("%s=\"%lld\"", key, value);
1781
271
}
1782
1783
static Writer xml_writer = {
1784
    .name                 = "xml",
1785
    .priv_size            = sizeof(XMLContext),
1786
    .init                 = xml_init,
1787
    .print_section_header = xml_print_section_header,
1788
    .print_section_footer = xml_print_section_footer,
1789
    .print_integer        = xml_print_int,
1790
    .print_string         = xml_print_str,
1791
    .flags = WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER,
1792
    .priv_class           = &xml_class,
1793
};
1794
1795
74
static void writer_register_all(void)
1796
{
1797
    static int initialized;
1798
1799
74
    if (initialized)
1800
        return;
1801
74
    initialized = 1;
1802
1803
74
    writer_register(&default_writer);
1804
74
    writer_register(&compact_writer);
1805
74
    writer_register(&csv_writer);
1806
74
    writer_register(&flat_writer);
1807
74
    writer_register(&ini_writer);
1808
74
    writer_register(&json_writer);
1809
74
    writer_register(&xml_writer);
1810
}
1811
1812
#define print_fmt(k, f, ...) do {              \
1813
    av_bprint_clear(&pbuf);                    \
1814
    av_bprintf(&pbuf, f, __VA_ARGS__);         \
1815
    writer_print_string(w, k, pbuf.str, 0);    \
1816
} while (0)
1817
1818
#define print_int(k, v)         writer_print_integer(w, k, v)
1819
#define print_q(k, v, s)        writer_print_rational(w, k, v, s)
1820
#define print_str(k, v)         writer_print_string(w, k, v, 0)
1821
#define print_str_opt(k, v)     writer_print_string(w, k, v, PRINT_STRING_OPT)
1822
#define print_str_validate(k, v) writer_print_string(w, k, v, PRINT_STRING_VALIDATE)
1823
#define print_time(k, v, tb)    writer_print_time(w, k, v, tb, 0)
1824
#define print_ts(k, v)          writer_print_ts(w, k, v, 0)
1825
#define print_duration_time(k, v, tb) writer_print_time(w, k, v, tb, 1)
1826
#define print_duration_ts(k, v)       writer_print_ts(w, k, v, 1)
1827
#define print_val(k, v, u) do {                                     \
1828
    struct unit_value uv;                                           \
1829
    uv.val.i = v;                                                   \
1830
    uv.unit = u;                                                    \
1831
    writer_print_string(w, k, value_string(val_str, sizeof(val_str), uv), 0); \
1832
} while (0)
1833
1834
#define print_section_header(s) writer_print_section_header(w, s)
1835
#define print_section_footer(s) writer_print_section_footer(w, s)
1836
1837
#define REALLOCZ_ARRAY_STREAM(ptr, cur_n, new_n)                        \
1838
{                                                                       \
1839
    ret = av_reallocp_array(&(ptr), (new_n), sizeof(*(ptr)));           \
1840
    if (ret < 0)                                                        \
1841
        goto end;                                                       \
1842
    memset( (ptr) + (cur_n), 0, ((new_n) - (cur_n)) * sizeof(*(ptr)) ); \
1843
}
1844
1845
1243
static inline int show_tags(WriterContext *w, AVDictionary *tags, int section_id)
1846
{
1847
1243
    AVDictionaryEntry *tag = NULL;
1848
1243
    int ret = 0;
1849
1850
1243
    if (!tags)
1851
634
        return 0;
1852
609
    writer_print_section_header(w, section_id);
1853
1854
3094
    while ((tag = av_dict_get(tags, "", tag, AV_DICT_IGNORE_SUFFIX))) {
1855
2485
        if ((ret = print_str_validate(tag->key, tag->value)) < 0)
1856
            break;
1857
    }
1858
609
    writer_print_section_footer(w);
1859
1860
609
    return ret;
1861
}
1862
1863
207
static void print_pkt_side_data(WriterContext *w,
1864
                                AVCodecParameters *par,
1865
                                const AVPacketSideData *side_data,
1866
                                int nb_side_data,
1867
                                SectionID id_data_list,
1868
                                SectionID id_data)
1869
{
1870
    int i;
1871
1872
207
    writer_print_section_header(w, id_data_list);
1873
417
    for (i = 0; i < nb_side_data; i++) {
1874
210
        const AVPacketSideData *sd = &side_data[i];
1875
210
        const char *name = av_packet_side_data_name(sd->type);
1876
1877
210
        writer_print_section_header(w, id_data);
1878
210
        print_str("side_data_type", name ? name : "unknown");
1879

210
        if (sd->type == AV_PKT_DATA_DISPLAYMATRIX && sd->size >= 9*4) {
1880
2
            writer_print_integers(w, "displaymatrix", sd->data, 9, " %11d", 3, 4, 1);
1881
2
            print_int("rotation", av_display_rotation_get((int32_t *)sd->data));
1882
208
        } else if (sd->type == AV_PKT_DATA_STEREO3D) {
1883
2
            const AVStereo3D *stereo = (AVStereo3D *)sd->data;
1884
2
            print_str("type", av_stereo3d_type_name(stereo->type));
1885
2
            print_int("inverted", !!(stereo->flags & AV_STEREO3D_FLAG_INVERT));
1886
206
        } else if (sd->type == AV_PKT_DATA_SPHERICAL) {
1887
2
            const AVSphericalMapping *spherical = (AVSphericalMapping *)sd->data;
1888
2
            print_str("projection", av_spherical_projection_name(spherical->projection));
1889
2
            if (spherical->projection == AV_SPHERICAL_CUBEMAP) {
1890
                print_int("padding", spherical->padding);
1891
2
            } else if (spherical->projection == AV_SPHERICAL_EQUIRECTANGULAR_TILE) {
1892
                size_t l, t, r, b;
1893
2
                av_spherical_tile_bounds(spherical, par->width, par->height,
1894
                                         &l, &t, &r, &b);
1895
2
                print_int("bound_left", l);
1896
2
                print_int("bound_top", t);
1897
2
                print_int("bound_right", r);
1898
2
                print_int("bound_bottom", b);
1899
            }
1900
1901
2
            print_int("yaw", (double) spherical->yaw / (1 << 16));
1902
2
            print_int("pitch", (double) spherical->pitch / (1 << 16));
1903
2
            print_int("roll", (double) spherical->roll / (1 << 16));
1904

204
        } else if (sd->type == AV_PKT_DATA_SKIP_SAMPLES && sd->size == 10) {
1905
5
            print_int("skip_samples",    AV_RL32(sd->data));
1906
5
            print_int("discard_padding", AV_RL32(sd->data + 4));
1907
5
            print_int("skip_reason",     AV_RL8(sd->data + 8));
1908
5
            print_int("discard_reason",  AV_RL8(sd->data + 9));
1909
199
        } else if (sd->type == AV_PKT_DATA_MASTERING_DISPLAY_METADATA) {
1910
1
            AVMasteringDisplayMetadata *metadata = (AVMasteringDisplayMetadata *)sd->data;
1911
1912
1
            if (metadata->has_primaries) {
1913
1
                print_q("red_x", metadata->display_primaries[0][0], '/');
1914
1
                print_q("red_y", metadata->display_primaries[0][1], '/');
1915
1
                print_q("green_x", metadata->display_primaries[1][0], '/');
1916
1
                print_q("green_y", metadata->display_primaries[1][1], '/');
1917
1
                print_q("blue_x", metadata->display_primaries[2][0], '/');
1918
1
                print_q("blue_y", metadata->display_primaries[2][1], '/');
1919
1920
1
                print_q("white_point_x", metadata->white_point[0], '/');
1921
1
                print_q("white_point_y", metadata->white_point[1], '/');
1922
            }
1923
1924
1
            if (metadata->has_luminance) {
1925
1
                print_q("min_luminance", metadata->min_luminance, '/');
1926
1
                print_q("max_luminance", metadata->max_luminance, '/');
1927
            }
1928
198
        } else if (sd->type == AV_PKT_DATA_CONTENT_LIGHT_LEVEL) {
1929
1
            AVContentLightMetadata *metadata = (AVContentLightMetadata *)sd->data;
1930
1
            print_int("max_content", metadata->MaxCLL);
1931
1
            print_int("max_average", metadata->MaxFALL);
1932
197
        } else if (sd->type == AV_PKT_DATA_DOVI_CONF) {
1933
            AVDOVIDecoderConfigurationRecord *dovi = (AVDOVIDecoderConfigurationRecord *)sd->data;
1934
            print_int("dv_version_major", dovi->dv_version_major);
1935
            print_int("dv_version_minor", dovi->dv_version_minor);
1936
            print_int("dv_profile", dovi->dv_profile);
1937
            print_int("dv_level", dovi->dv_level);
1938
            print_int("rpu_present_flag", dovi->rpu_present_flag);
1939
            print_int("el_present_flag", dovi->el_present_flag);
1940
            print_int("bl_present_flag", dovi->bl_present_flag);
1941
            print_int("dv_bl_signal_compatibility_id", dovi->dv_bl_signal_compatibility_id);
1942
        }
1943
210
        writer_print_section_footer(w);
1944
    }
1945
207
    writer_print_section_footer(w);
1946
207
}
1947
1948
492
static void print_color_range(WriterContext *w, enum AVColorRange color_range)
1949
{
1950
492
    const char *val = av_color_range_name(color_range);
1951

492
    if (!val || color_range == AVCOL_RANGE_UNSPECIFIED) {
1952
401
        print_str_opt("color_range", "unknown");
1953
    } else {
1954
91
        print_str("color_range", val);
1955
    }
1956
492
}
1957
1958
492
static void print_color_space(WriterContext *w, enum AVColorSpace color_space)
1959
{
1960
492
    const char *val = av_color_space_name(color_space);
1961

492
    if (!val || color_space == AVCOL_SPC_UNSPECIFIED) {
1962
416
        print_str_opt("color_space", "unknown");
1963
    } else {
1964
76
        print_str("color_space", val);
1965
    }
1966
492
}
1967
1968
492
static void print_primaries(WriterContext *w, enum AVColorPrimaries color_primaries)
1969
{
1970
492
    const char *val = av_color_primaries_name(color_primaries);
1971

492
    if (!val || color_primaries == AVCOL_PRI_UNSPECIFIED) {
1972
419
        print_str_opt("color_primaries", "unknown");
1973
    } else {
1974
73
        print_str("color_primaries", val);
1975
    }
1976
492
}
1977
1978
492
static void print_color_trc(WriterContext *w, enum AVColorTransferCharacteristic color_trc)
1979
{
1980
492
    const char *val = av_color_transfer_name(color_trc);
1981

492
    if (!val || color_trc == AVCOL_TRC_UNSPECIFIED) {
1982
417
        print_str_opt("color_transfer", "unknown");
1983
    } else {
1984
75
        print_str("color_transfer", val);
1985
    }
1986
492
}
1987
1988
492
static void print_chroma_location(WriterContext *w, enum AVChromaLocation chroma_location)
1989
{
1990
492
    const char *val = av_chroma_location_name(chroma_location);
1991

492
    if (!val || chroma_location == AVCHROMA_LOC_UNSPECIFIED) {
1992
401
        print_str_opt("chroma_location", "unspecified");
1993
    } else {
1994
91
        print_str("chroma_location", val);
1995
    }
1996
492
}
1997
1998
1999
5946
static void clear_log(int need_lock)
2000
{
2001
    int i;
2002
2003
5946
    if (need_lock)
2004
5946
        pthread_mutex_lock(&log_mutex);
2005
5946
    for (i=0; i<log_buffer_size; i++) {
2006
        av_freep(&log_buffer[i].context_name);
2007
        av_freep(&log_buffer[i].parent_name);
2008
        av_freep(&log_buffer[i].log_message);
2009
    }
2010
5946
    log_buffer_size = 0;
2011
5946
    if(need_lock)
2012
5946
        pthread_mutex_unlock(&log_mutex);
2013
5946
}
2014
2015
static int show_log(WriterContext *w, int section_ids, int section_id, int log_level)
2016
{
2017
    int i;
2018
    pthread_mutex_lock(&log_mutex);
2019
    if (!log_buffer_size) {
2020
        pthread_mutex_unlock(&log_mutex);
2021
        return 0;
2022
    }
2023
    writer_print_section_header(w, section_ids);
2024
2025
    for (i=0; i<log_buffer_size; i++) {
2026
        if (log_buffer[i].log_level <= log_level) {
2027
            writer_print_section_header(w, section_id);
2028
            print_str("context", log_buffer[i].context_name);
2029
            print_int("level", log_buffer[i].log_level);
2030
            print_int("category", log_buffer[i].category);
2031
            if (log_buffer[i].parent_name) {
2032
                print_str("parent_context", log_buffer[i].parent_name);
2033
                print_int("parent_category", log_buffer[i].parent_category);
2034
            } else {
2035
                print_str_opt("parent_context", "N/A");
2036
                print_str_opt("parent_category", "N/A");
2037
            }
2038
            print_str("message", log_buffer[i].log_message);
2039
            writer_print_section_footer(w);
2040
        }
2041
    }
2042
    clear_log(0);
2043
    pthread_mutex_unlock(&log_mutex);
2044
2045
    writer_print_section_footer(w);
2046
2047
    return 0;
2048
}
2049
2050
3588
static void show_packet(WriterContext *w, InputFile *ifile, AVPacket *pkt, int packet_idx)
2051
{
2052
    char val_str[128];
2053
3588
    AVStream *st = ifile->streams[pkt->stream_index].st;
2054
    AVBPrint pbuf;
2055
    const char *s;
2056
2057
3588
    av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
2058
2059
3588
    writer_print_section_header(w, SECTION_ID_PACKET);
2060
2061
3588
    s = av_get_media_type_string(st->codecpar->codec_type);
2062
3588
    if (s) print_str    ("codec_type", s);
2063
    else   print_str_opt("codec_type", "unknown");
2064
3588
    print_int("stream_index",     pkt->stream_index);
2065
3588
    print_ts  ("pts",             pkt->pts);
2066
3588
    print_time("pts_time",        pkt->pts, &st->time_base);
2067
3588
    print_ts  ("dts",             pkt->dts);
2068
3588
    print_time("dts_time",        pkt->dts, &st->time_base);
2069
3588
    print_duration_ts("duration",        pkt->duration);
2070
3588
    print_duration_time("duration_time", pkt->duration, &st->time_base);
2071
3588
    print_duration_ts("convergence_duration", pkt->convergence_duration);
2072
3588
    print_duration_time("convergence_duration_time", pkt->convergence_duration, &st->time_base);
2073
3588
    print_val("size",             pkt->size, unit_byte_str);
2074
3588
    if (pkt->pos != -1) print_fmt    ("pos", "%"PRId64, pkt->pos);
2075
82
    else                print_str_opt("pos", "N/A");
2076

3588
    print_fmt("flags", "%c%c",      pkt->flags & AV_PKT_FLAG_KEY ? 'K' : '_',
2077
              pkt->flags & AV_PKT_FLAG_DISCARD ? 'D' : '_');
2078
2079
3588
    if (pkt->side_data_elems) {
2080
        int size;
2081
        const uint8_t *side_metadata;
2082
2083
200
        side_metadata = av_packet_get_side_data(pkt, AV_PKT_DATA_STRINGS_METADATA, &size);
2084

200
        if (side_metadata && size && do_show_packet_tags) {
2085
131
            AVDictionary *dict = NULL;
2086
131
            if (av_packet_unpack_dictionary(side_metadata, size, &dict) >= 0)
2087
131
                show_tags(w, dict, SECTION_ID_PACKET_TAGS);
2088
131
            av_dict_free(&dict);
2089
        }
2090
2091
200
        print_pkt_side_data(w, st->codecpar, pkt->side_data, pkt->side_data_elems,
2092
                            SECTION_ID_PACKET_SIDE_DATA_LIST,
2093
                            SECTION_ID_PACKET_SIDE_DATA);
2094
    }
2095
2096
3588
    if (do_show_data)
2097
        writer_print_data(w, "data", pkt->data, pkt->size);
2098
3588
    writer_print_data_hash(w, "data_hash", pkt->data, pkt->size);
2099
3588
    writer_print_section_footer(w);
2100
2101
3588
    av_bprint_finalize(&pbuf, NULL);
2102
3588
    fflush(stdout);
2103
3588
}
2104
2105
static void show_subtitle(WriterContext *w, AVSubtitle *sub, AVStream *stream,
2106
                          AVFormatContext *fmt_ctx)
2107
{
2108
    AVBPrint pbuf;
2109
2110
    av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
2111
2112
    writer_print_section_header(w, SECTION_ID_SUBTITLE);
2113
2114
    print_str ("media_type",         "subtitle");
2115
    print_ts  ("pts",                 sub->pts);
2116
    print_time("pts_time",            sub->pts, &AV_TIME_BASE_Q);
2117
    print_int ("format",              sub->format);
2118
    print_int ("start_display_time",  sub->start_display_time);
2119
    print_int ("end_display_time",    sub->end_display_time);
2120
    print_int ("num_rects",           sub->num_rects);
2121
2122
    writer_print_section_footer(w);
2123
2124
    av_bprint_finalize(&pbuf, NULL);
2125
    fflush(stdout);
2126
}
2127
2128
3022
static void show_frame(WriterContext *w, AVFrame *frame, AVStream *stream,
2129
                       AVFormatContext *fmt_ctx)
2130
{
2131
    AVBPrint pbuf;
2132
    char val_str[128];
2133
    const char *s;
2134
    int i;
2135
2136
3022
    av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
2137
2138
3022
    writer_print_section_header(w, SECTION_ID_FRAME);
2139
2140
3022
    s = av_get_media_type_string(stream->codecpar->codec_type);
2141
3022
    if (s) print_str    ("media_type", s);
2142
    else   print_str_opt("media_type", "unknown");
2143
3022
    print_int("stream_index",           stream->index);
2144
3022
    print_int("key_frame",              frame->key_frame);
2145
3022
    print_ts  ("pkt_pts",               frame->pts);
2146
3022
    print_time("pkt_pts_time",          frame->pts, &stream->time_base);
2147
3022
    print_ts  ("pkt_dts",               frame->pkt_dts);
2148
3022
    print_time("pkt_dts_time",          frame->pkt_dts, &stream->time_base);
2149
3022
    print_ts  ("best_effort_timestamp", frame->best_effort_timestamp);
2150
3022
    print_time("best_effort_timestamp_time", frame->best_effort_timestamp, &stream->time_base);
2151
3022
    print_duration_ts  ("pkt_duration",      frame->pkt_duration);
2152
3022
    print_duration_time("pkt_duration_time", frame->pkt_duration, &stream->time_base);
2153
3022
    if (frame->pkt_pos != -1) print_fmt    ("pkt_pos", "%"PRId64, frame->pkt_pos);
2154
302
    else                      print_str_opt("pkt_pos", "N/A");
2155
3022
    if (frame->pkt_size != -1) print_val    ("pkt_size", frame->pkt_size, unit_byte_str);
2156
    else                       print_str_opt("pkt_size", "N/A");
2157
2158
3022
    switch (stream->codecpar->codec_type) {
2159
        AVRational sar;
2160
2161
452
    case AVMEDIA_TYPE_VIDEO:
2162
452
        print_int("width",                  frame->width);
2163
452
        print_int("height",                 frame->height);
2164
452
        s = av_get_pix_fmt_name(frame->format);
2165
452
        if (s) print_str    ("pix_fmt", s);
2166
        else   print_str_opt("pix_fmt", "unknown");
2167
452
        sar = av_guess_sample_aspect_ratio(fmt_ctx, stream, frame);
2168
452
        if (sar.num) {
2169
450
            print_q("sample_aspect_ratio", sar, ':');
2170
        } else {
2171
2
            print_str_opt("sample_aspect_ratio", "N/A");
2172
        }
2173
452
        print_fmt("pict_type",              "%c", av_get_picture_type_char(frame->pict_type));
2174
452
        print_int("coded_picture_number",   frame->coded_picture_number);
2175
452
        print_int("display_picture_number", frame->display_picture_number);
2176
452
        print_int("interlaced_frame",       frame->interlaced_frame);
2177
452
        print_int("top_field_first",        frame->top_field_first);
2178
452
        print_int("repeat_pict",            frame->repeat_pict);
2179
2180
452
        print_color_range(w, frame->color_range);
2181
452
        print_color_space(w, frame->colorspace);
2182
452
        print_primaries(w, frame->color_primaries);
2183
452
        print_color_trc(w, frame->color_trc);
2184
452
        print_chroma_location(w, frame->chroma_location);
2185
452
        break;
2186
2187
2570
    case AVMEDIA_TYPE_AUDIO:
2188
2570
        s = av_get_sample_fmt_name(frame->format);
2189
2570
        if (s) print_str    ("sample_fmt", s);
2190
        else   print_str_opt("sample_fmt", "unknown");
2191
2570
        print_int("nb_samples",         frame->nb_samples);
2192
2570
        print_int("channels", frame->channels);
2193
2570
        if (frame->channel_layout) {
2194
2352
            av_bprint_clear(&pbuf);
2195
2352
            av_bprint_channel_layout(&pbuf, frame->channels,
2196
                                     frame->channel_layout);
2197
2352
            print_str    ("channel_layout", pbuf.str);
2198
        } else
2199
218
            print_str_opt("channel_layout", "unknown");
2200
2570
        break;
2201
    }
2202
3022
    if (do_show_frame_tags)
2203
1041
        show_tags(w, frame->metadata, SECTION_ID_FRAME_TAGS);
2204
3022
    if (do_show_log)
2205
        show_log(w, SECTION_ID_FRAME_LOGS, SECTION_ID_FRAME_LOG, do_show_log);
2206
3022
    if (frame->nb_side_data) {
2207
68
        writer_print_section_header(w, SECTION_ID_FRAME_SIDE_DATA_LIST);
2208
138
        for (i = 0; i < frame->nb_side_data; i++) {
2209
70
            AVFrameSideData *sd = frame->side_data[i];
2210
            const char *name;
2211
2212
70
            writer_print_section_header(w, SECTION_ID_FRAME_SIDE_DATA);
2213
70
            name = av_frame_side_data_name(sd->type);
2214
70
            print_str("side_data_type", name ? name : "unknown");
2215

70
            if (sd->type == AV_FRAME_DATA_DISPLAYMATRIX && sd->size >= 9*4) {
2216
                writer_print_integers(w, "displaymatrix", sd->data, 9, " %11d", 3, 4, 1);
2217
                print_int("rotation", av_display_rotation_get((int32_t *)sd->data));
2218

70
            } else if (sd->type == AV_FRAME_DATA_GOP_TIMECODE && sd->size >= 8) {
2219
                char tcbuf[AV_TIMECODE_STR_SIZE];
2220
                av_timecode_make_mpeg_tc_string(tcbuf, *(int64_t *)(sd->data));
2221
                print_str("timecode", tcbuf);
2222

70
            } else if (sd->type == AV_FRAME_DATA_S12M_TIMECODE && sd->size == 16) {
2223
                uint32_t *tc = (uint32_t*)sd->data;
2224
                int m = FFMIN(tc[0],3);
2225
                writer_print_section_header(w, SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST);
2226
                for (int j = 1; j <= m ; j++) {
2227
                    char tcbuf[AV_TIMECODE_STR_SIZE];
2228
                    av_timecode_make_smpte_tc_string2(tcbuf, stream->avg_frame_rate, tc[j], 0, 0);
2229
                    writer_print_section_header(w, SECTION_ID_FRAME_SIDE_DATA_TIMECODE);
2230
                    print_str("value", tcbuf);
2231
                    writer_print_section_footer(w);
2232
                }
2233
                writer_print_section_footer(w);
2234
70
            } else if (sd->type == AV_FRAME_DATA_MASTERING_DISPLAY_METADATA) {
2235
                AVMasteringDisplayMetadata *metadata = (AVMasteringDisplayMetadata *)sd->data;
2236
2237
                if (metadata->has_primaries) {
2238
                    print_q("red_x", metadata->display_primaries[0][0], '/');
2239
                    print_q("red_y", metadata->display_primaries[0][1], '/');
2240
                    print_q("green_x", metadata->display_primaries[1][0], '/');
2241
                    print_q("green_y", metadata->display_primaries[1][1], '/');
2242
                    print_q("blue_x", metadata->display_primaries[2][0], '/');
2243
                    print_q("blue_y", metadata->display_primaries[2][1], '/');
2244
2245
                    print_q("white_point_x", metadata->white_point[0], '/');
2246
                    print_q("white_point_y", metadata->white_point[1], '/');
2247
                }
2248
2249
                if (metadata->has_luminance) {
2250
                    print_q("min_luminance", metadata->min_luminance, '/');
2251
                    print_q("max_luminance", metadata->max_luminance, '/');
2252
                }
2253
70
            } else if (sd->type == AV_FRAME_DATA_CONTENT_LIGHT_LEVEL) {
2254
                AVContentLightMetadata *metadata = (AVContentLightMetadata *)sd->data;
2255
                print_int("max_content", metadata->MaxCLL);
2256
                print_int("max_average", metadata->MaxFALL);
2257
70
            } else if (sd->type == AV_FRAME_DATA_ICC_PROFILE) {
2258
                AVDictionaryEntry *tag = av_dict_get(sd->metadata, "name", NULL, AV_DICT_MATCH_CASE);
2259
                if (tag)
2260
                    print_str(tag->key, tag->value);
2261
                print_int("size", sd->size);
2262
            }
2263
70
            writer_print_section_footer(w);
2264
        }
2265
68
        writer_print_section_footer(w);
2266
    }
2267
2268
3022
    writer_print_section_footer(w);
2269
2270
3022
    av_bprint_finalize(&pbuf, NULL);
2271
3022
    fflush(stdout);
2272
3022
}
2273
2274
5946
static av_always_inline int process_frame(WriterContext *w,
2275
                                          InputFile *ifile,
2276
                                          AVFrame *frame, AVPacket *pkt,
2277
                                          int *packet_new)
2278
{
2279
5946
    AVFormatContext *fmt_ctx = ifile->fmt_ctx;
2280
5946
    AVCodecContext *dec_ctx = ifile->streams[pkt->stream_index].dec_ctx;
2281
5946
    AVCodecParameters *par = ifile->streams[pkt->stream_index].st->codecpar;
2282
    AVSubtitle sub;
2283
5946
    int ret = 0, got_frame = 0;
2284
2285
5946
    clear_log(1);
2286

5946
    if (dec_ctx && dec_ctx->codec) {
2287
5946
        switch (par->codec_type) {
2288
5946
        case AVMEDIA_TYPE_VIDEO:
2289
        case AVMEDIA_TYPE_AUDIO:
2290
5946
            if (*packet_new) {
2291
2930
                ret = avcodec_send_packet(dec_ctx, pkt);
2292
2930
                if (ret == AVERROR(EAGAIN)) {
2293
                    ret = 0;
2294

2930
                } else if (ret >= 0 || ret == AVERROR_EOF) {
2295
2928
                    ret = 0;
2296
2928
                    *packet_new = 0;
2297
                }
2298
            }
2299
5946
            if (ret >= 0) {
2300
5944
                ret = avcodec_receive_frame(dec_ctx, frame);
2301
5944
                if (ret >= 0) {
2302
3022
                    got_frame = 1;
2303

2922
                } else if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
2304
2922
                    ret = 0;
2305
                }
2306
            }
2307
5946
            break;
2308
2309
        case AVMEDIA_TYPE_SUBTITLE:
2310
            if (*packet_new)
2311
                ret = avcodec_decode_subtitle2(dec_ctx, &sub, &got_frame, pkt);
2312
            *packet_new = 0;
2313
            break;
2314
        default:
2315
            *packet_new = 0;
2316
        }
2317
    } else {
2318
        *packet_new = 0;
2319
    }
2320
2321
5946
    if (ret < 0)
2322
2
        return ret;
2323
5944
    if (got_frame) {
2324
3022
        int is_sub = (par->codec_type == AVMEDIA_TYPE_SUBTITLE);
2325
3022
        nb_streams_frames[pkt->stream_index]++;
2326
3022
        if (do_show_frames)
2327
3022
            if (is_sub)
2328
                show_subtitle(w, &sub, ifile->streams[pkt->stream_index].st, fmt_ctx);
2329
            else
2330
3022
                show_frame(w, frame, ifile->streams[pkt->stream_index].st, fmt_ctx);
2331
3022
        if (is_sub)
2332
            avsubtitle_free(&sub);
2333
    }
2334

5944
    return got_frame || *packet_new;
2335
}
2336
2337
45
static void log_read_interval(const ReadInterval *interval, void *log_ctx, int log_level)
2338
{
2339
45
    av_log(log_ctx, log_level, "id:%d", interval->id);
2340
2341
45
    if (interval->has_start) {
2342
        av_log(log_ctx, log_level, " start:%s%s", interval->start_is_offset ? "+" : "",
2343
               av_ts2timestr(interval->start, &AV_TIME_BASE_Q));
2344
    } else {
2345
45
        av_log(log_ctx, log_level, " start:N/A");
2346
    }
2347
2348
45
    if (interval->has_end) {
2349
        av_log(log_ctx, log_level, " end:%s", interval->end_is_offset ? "+" : "");
2350
        if (interval->duration_frames)
2351
            av_log(log_ctx, log_level, "#%"PRId64, interval->end);
2352
        else
2353
            av_log(log_ctx, log_level, "%s", av_ts2timestr(interval->end, &AV_TIME_BASE_Q));
2354
    } else {
2355
45
        av_log(log_ctx, log_level, " end:N/A");
2356
    }
2357
2358
45
    av_log(log_ctx, log_level, "\n");
2359
45
}
2360
2361
45
static int read_interval_packets(WriterContext *w, InputFile *ifile,
2362
                                 const ReadInterval *interval, int64_t *cur_ts)
2363
{
2364
45
    AVFormatContext *fmt_ctx = ifile->fmt_ctx;
2365
    AVPacket pkt;
2366
45
    AVFrame *frame = NULL;
2367
45
    int ret = 0, i = 0, frame_count = 0;
2368
45
    int64_t start = -INT64_MAX, end = interval->end;
2369

45
    int has_start = 0, has_end = interval->has_end && !interval->end_is_offset;
2370
2371
45
    av_init_packet(&pkt);
2372
2373
45
    av_log(NULL, AV_LOG_VERBOSE, "Processing read interval ");
2374
45
    log_read_interval(interval, NULL, AV_LOG_VERBOSE);
2375
2376
45
    if (interval->has_start) {
2377
        int64_t target;
2378
        if (interval->start_is_offset) {
2379
            if (*cur_ts == AV_NOPTS_VALUE) {
2380
                av_log(NULL, AV_LOG_ERROR,
2381
                       "Could not seek to relative position since current "
2382
                       "timestamp is not defined\n");
2383
                ret = AVERROR(EINVAL);
2384
                goto end;
2385
            }
2386
            target = *cur_ts + interval->start;
2387
        } else {
2388
            target = interval->start;
2389
        }
2390
2391
        av_log(NULL, AV_LOG_VERBOSE, "Seeking to read interval start point %s\n",
2392
               av_ts2timestr(target, &AV_TIME_BASE_Q));
2393
        if ((ret = avformat_seek_file(fmt_ctx, -1, -INT64_MAX, target, INT64_MAX, 0)) < 0) {
2394
            av_log(NULL, AV_LOG_ERROR, "Could not seek to position %"PRId64": %s\n",
2395
                   interval->start, av_err2str(ret));
2396
            goto end;
2397
        }
2398
    }
2399
2400
45
    frame = av_frame_alloc();
2401
45
    if (!frame) {
2402
        ret = AVERROR(ENOMEM);
2403
        goto end;
2404
    }
2405
6331
    while (!av_read_frame(fmt_ctx, &pkt)) {
2406
6286
        if (fmt_ctx->nb_streams > nb_streams) {
2407
            REALLOCZ_ARRAY_STREAM(nb_streams_frames,  nb_streams, fmt_ctx->nb_streams);
2408
            REALLOCZ_ARRAY_STREAM(nb_streams_packets, nb_streams, fmt_ctx->nb_streams);
2409
            REALLOCZ_ARRAY_STREAM(selected_streams,   nb_streams, fmt_ctx->nb_streams);
2410
            nb_streams = fmt_ctx->nb_streams;
2411
        }
2412
6286
        if (selected_streams[pkt.stream_index]) {
2413
6283
            AVRational tb = ifile->streams[pkt.stream_index].st->time_base;
2414
2415
6283
            if (pkt.pts != AV_NOPTS_VALUE)
2416
6271
                *cur_ts = av_rescale_q(pkt.pts, tb, AV_TIME_BASE_Q);
2417
2418

6283
            if (!has_start && *cur_ts != AV_NOPTS_VALUE) {
2419
43
                start = *cur_ts;
2420
43
                has_start = 1;
2421
            }
2422
2423

6283
            if (has_start && !has_end && interval->end_is_offset) {
2424
                end = start + interval->end;
2425
                has_end = 1;
2426
            }
2427
2428

6283
            if (interval->end_is_offset && interval->duration_frames) {
2429
                if (frame_count >= interval->end)
2430
                    break;
2431

6283
            } else if (has_end && *cur_ts != AV_NOPTS_VALUE && *cur_ts >= end) {
2432
                break;
2433
            }
2434
2435
6283
            frame_count++;
2436
6283
            if (do_read_packets) {
2437
3588
                if (do_show_packets)
2438
3588
                    show_packet(w, ifile, &pkt, i++);
2439
3588
                nb_streams_packets[pkt.stream_index]++;
2440
            }
2441
6283
            if (do_read_frames) {
2442
2876
                int packet_new = 1;
2443
5892
                while (process_frame(w, ifile, frame, &pkt, &packet_new) > 0);
2444
            }
2445
        }
2446
6286
        av_packet_unref(&pkt);
2447
    }
2448
45
    av_packet_unref(&pkt);
2449
    //Flush remaining frames that are cached in the decoder
2450
113
    for (i = 0; i < fmt_ctx->nb_streams; i++) {
2451
68
        pkt.stream_index = i;
2452
68
        if (do_read_frames)
2453
54
            while (process_frame(w, ifile, frame, &pkt, &(int){1}) > 0);
2454
    }
2455
2456
45
end:
2457
45
    av_frame_free(&frame);
2458
45
    if (ret < 0) {
2459
        av_log(NULL, AV_LOG_ERROR, "Could not read packets in interval ");
2460
        log_read_interval(interval, NULL, AV_LOG_ERROR);
2461
    }
2462
45
    return ret;
2463
}
2464
2465
45
static int read_packets(WriterContext *w, InputFile *ifile)
2466
{
2467
45
    AVFormatContext *fmt_ctx = ifile->fmt_ctx;
2468
45
    int i, ret = 0;
2469
45
    int64_t cur_ts = fmt_ctx->start_time;
2470
2471
45
    if (read_intervals_nb == 0) {
2472
45
        ReadInterval interval = (ReadInterval) { .has_start = 0, .has_end = 0 };
2473
45
        ret = read_interval_packets(w, ifile, &interval, &cur_ts);
2474
    } else {
2475
        for (i = 0; i < read_intervals_nb; i++) {
2476
            ret = read_interval_packets(w, ifile, &read_intervals[i], &cur_ts);
2477
            if (ret < 0)
2478
                break;
2479
        }
2480
    }
2481
2482
45
    return ret;
2483
}
2484
2485
86
static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_idx, InputStream *ist, int in_program)
2486
{
2487
86
    AVStream *stream = ist->st;
2488
    AVCodecParameters *par;
2489
    AVCodecContext *dec_ctx;
2490
    char val_str[128];
2491
    const char *s;
2492
    AVRational sar, dar;
2493
    AVBPrint pbuf;
2494
    const AVCodecDescriptor *cd;
2495
86
    int ret = 0;
2496
86
    const char *profile = NULL;
2497
2498
86
    av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
2499
2500
86
    writer_print_section_header(w, in_program ? SECTION_ID_PROGRAM_STREAM : SECTION_ID_STREAM);
2501
2502
86
    print_int("index", stream->index);
2503
2504
86
    par     = stream->codecpar;
2505
86
    dec_ctx = ist->dec_ctx;
2506
86
    if (cd = avcodec_descriptor_get(par->codec_id)) {
2507
83
        print_str("codec_name", cd->name);
2508
83
        if (!do_bitexact) {
2509
9
            print_str("codec_long_name",
2510
                      cd->long_name ? cd->long_name : "unknown");
2511
        }
2512
    } else {
2513
3
        print_str_opt("codec_name", "unknown");
2514
3
        if (!do_bitexact) {
2515
            print_str_opt("codec_long_name", "unknown");
2516
        }
2517
    }
2518
2519

86
    if (!do_bitexact && (profile = avcodec_profile_name(par->codec_id, par->profile)))
2520
7
        print_str("profile", profile);
2521
    else {
2522
79
        if (par->profile != FF_PROFILE_UNKNOWN) {
2523
            char profile_num[12];
2524
28
            snprintf(profile_num, sizeof(profile_num), "%d", par->profile);
2525
28
            print_str("profile", profile_num);
2526
        } else
2527
51
            print_str_opt("profile", "unknown");
2528
    }
2529
2530
86
    s = av_get_media_type_string(par->codec_type);
2531
86
    if (s) print_str    ("codec_type", s);
2532
    else   print_str_opt("codec_type", "unknown");
2533
#if FF_API_LAVF_AVCTX
2534
86
    if (dec_ctx)
2535
80
        print_q("codec_time_base", dec_ctx->time_base, '/');
2536
#endif
2537
2538
    /* print AVI/FourCC tag */
2539
86
    print_str("codec_tag_string",    av_fourcc2str(par->codec_tag));
2540
86
    print_fmt("codec_tag", "0x%04"PRIx32, par->codec_tag);
2541
2542

86
    switch (par->codec_type) {
2543
40
    case AVMEDIA_TYPE_VIDEO:
2544
40
        print_int("width",        par->width);
2545
40
        print_int("height",       par->height);
2546
#if FF_API_LAVF_AVCTX
2547
40
        if (dec_ctx) {
2548
40
            print_int("coded_width",  dec_ctx->coded_width);
2549
40
            print_int("coded_height", dec_ctx->coded_height);
2550
40
            print_int("closed_captions", !!(dec_ctx->properties & FF_CODEC_PROPERTY_CLOSED_CAPTIONS));
2551
        }
2552
#endif
2553
40
        print_int("has_b_frames", par->video_delay);
2554
40
        sar = av_guess_sample_aspect_ratio(fmt_ctx, stream, NULL);
2555
40
        if (sar.num) {
2556
35
            print_q("sample_aspect_ratio", sar, ':');
2557
35
            av_reduce(&dar.num, &dar.den,
2558
35
                      par->width  * sar.num,
2559
35
                      par->height * sar.den,
2560
                      1024*1024);
2561
35
            print_q("display_aspect_ratio", dar, ':');
2562
        } else {
2563
5
            print_str_opt("sample_aspect_ratio", "N/A");
2564
5
            print_str_opt("display_aspect_ratio", "N/A");
2565
        }
2566
40
        s = av_get_pix_fmt_name(par->format);
2567
40
        if (s) print_str    ("pix_fmt", s);
2568
2
        else   print_str_opt("pix_fmt", "unknown");
2569
40
        print_int("level",   par->level);
2570
2571
40
        print_color_range(w, par->color_range);
2572
40
        print_color_space(w, par->color_space);
2573
40
        print_color_trc(w, par->color_trc);
2574
40
        print_primaries(w, par->color_primaries);
2575
40
        print_chroma_location(w, par->chroma_location);
2576
2577
40
        if (par->field_order == AV_FIELD_PROGRESSIVE)
2578
6
            print_str("field_order", "progressive");
2579
34
        else if (par->field_order == AV_FIELD_TT)
2580
5
            print_str("field_order", "tt");
2581
29
        else if (par->field_order == AV_FIELD_BB)
2582
1
            print_str("field_order", "bb");
2583
28
        else if (par->field_order == AV_FIELD_TB)
2584
            print_str("field_order", "tb");
2585
28
        else if (par->field_order == AV_FIELD_BT)
2586
            print_str("field_order", "bt");
2587
        else
2588
28
            print_str_opt("field_order", "unknown");
2589
2590
#if FF_API_PRIVATE_OPT
2591

40
        if (dec_ctx && dec_ctx->timecode_frame_start >= 0) {
2592
            char tcbuf[AV_TIMECODE_STR_SIZE];
2593
            av_timecode_make_mpeg_tc_string(tcbuf, dec_ctx->timecode_frame_start);
2594
            print_str("timecode", tcbuf);
2595
        } else {
2596
40
            print_str_opt("timecode", "N/A");
2597
        }
2598
#endif
2599
40
        if (dec_ctx)
2600
40
            print_int("refs", dec_ctx->refs);
2601
40
        break;
2602
2603
40
    case AVMEDIA_TYPE_AUDIO:
2604
40
        s = av_get_sample_fmt_name(par->format);
2605
40
        if (s) print_str    ("sample_fmt", s);
2606
        else   print_str_opt("sample_fmt", "unknown");
2607
40
        print_val("sample_rate",     par->sample_rate, unit_hertz_str);
2608
40
        print_int("channels",        par->channels);
2609
2610
40
        if (par->channel_layout) {
2611
23
            av_bprint_clear(&pbuf);
2612
23
            av_bprint_channel_layout(&pbuf, par->channels, par->channel_layout);
2613
23
            print_str    ("channel_layout", pbuf.str);
2614
        } else {
2615
17
            print_str_opt("channel_layout", "unknown");
2616
        }
2617
2618
40
        print_int("bits_per_sample", av_get_bits_per_sample(par->codec_id));
2619
40
        break;
2620
2621
    case AVMEDIA_TYPE_SUBTITLE:
2622
        if (par->width)
2623
            print_int("width",       par->width);
2624
        else
2625
            print_str_opt("width",   "N/A");
2626
        if (par->height)
2627
            print_int("height",      par->height);
2628
        else
2629
            print_str_opt("height",  "N/A");
2630
        break;
2631
    }
2632
2633


86
    if (dec_ctx && dec_ctx->codec && dec_ctx->codec->priv_class && show_private_data) {
2634
46
        const AVOption *opt = NULL;
2635
225
        while (opt = av_opt_next(dec_ctx->priv_data,opt)) {
2636
            uint8_t *str;
2637
179
            if (opt->flags) continue;
2638
51
            if (av_opt_get(dec_ctx->priv_data, opt->name, 0, &str) >= 0) {
2639
51
                print_str(opt->name, str);
2640
51
                av_free(str);
2641
            }
2642
        }
2643
    }
2644
2645
86
    if (fmt_ctx->iformat->flags & AVFMT_SHOW_IDS) print_fmt    ("id", "0x%x", stream->id);
2646
69
    else                                          print_str_opt("id", "N/A");
2647
86
    print_q("r_frame_rate",   stream->r_frame_rate,   '/');
2648
86
    print_q("avg_frame_rate", stream->avg_frame_rate, '/');
2649
86
    print_q("time_base",      stream->time_base,      '/');
2650
86
    print_ts  ("start_pts",   stream->start_time);
2651
86
    print_time("start_time",  stream->start_time, &stream->time_base);
2652
86
    print_ts  ("duration_ts", stream->duration);
2653
86
    print_time("duration",    stream->duration, &stream->time_base);
2654
86
    if (par->bit_rate > 0)     print_val    ("bit_rate", par->bit_rate, unit_bit_per_second_str);
2655
37
    else                       print_str_opt("bit_rate", "N/A");
2656
#if FF_API_LAVF_AVCTX
2657
86
    if (stream->codec->rc_max_rate > 0) print_val ("max_bit_rate", stream->codec->rc_max_rate, unit_bit_per_second_str);
2658
74
    else                                print_str_opt("max_bit_rate", "N/A");
2659
#endif
2660

86
    if (dec_ctx && dec_ctx->bits_per_raw_sample > 0) print_fmt("bits_per_raw_sample", "%d", dec_ctx->bits_per_raw_sample);
2661
73
    else                                             print_str_opt("bits_per_raw_sample", "N/A");
2662
86
    if (stream->nb_frames) print_fmt    ("nb_frames", "%"PRId64, stream->nb_frames);
2663
63
    else                   print_str_opt("nb_frames", "N/A");
2664
86
    if (nb_streams_frames[stream_idx])  print_fmt    ("nb_read_frames", "%"PRIu64, nb_streams_frames[stream_idx]);
2665
59
    else                                print_str_opt("nb_read_frames", "N/A");
2666
86
    if (nb_streams_packets[stream_idx]) print_fmt    ("nb_read_packets", "%"PRIu64, nb_streams_packets[stream_idx]);
2667
48
    else                                print_str_opt("nb_read_packets", "N/A");
2668
86
    if (do_show_data)
2669
        writer_print_data(w, "extradata", par->extradata,
2670
                                          par->extradata_size);
2671
86
    writer_print_data_hash(w, "extradata_hash", par->extradata,
2672
                                                par->extradata_size);
2673
2674
    /* Print disposition information */
2675
#define PRINT_DISPOSITION(flagname, name) do {                                \
2676
        print_int(name, !!(stream->disposition & AV_DISPOSITION_##flagname)); \
2677
    } while (0)
2678
2679
86
    if (do_show_stream_disposition) {
2680
46
        writer_print_section_header(w, in_program ? SECTION_ID_PROGRAM_STREAM_DISPOSITION : SECTION_ID_STREAM_DISPOSITION);
2681
46
        PRINT_DISPOSITION(DEFAULT,          "default");
2682
46
        PRINT_DISPOSITION(DUB,              "dub");
2683
46
        PRINT_DISPOSITION(ORIGINAL,         "original");
2684
46
        PRINT_DISPOSITION(COMMENT,          "comment");
2685
46
        PRINT_DISPOSITION(LYRICS,           "lyrics");
2686
46
        PRINT_DISPOSITION(KARAOKE,          "karaoke");
2687
46
        PRINT_DISPOSITION(FORCED,           "forced");
2688
46
        PRINT_DISPOSITION(HEARING_IMPAIRED, "hearing_impaired");
2689
46
        PRINT_DISPOSITION(VISUAL_IMPAIRED,  "visual_impaired");
2690
46
        PRINT_DISPOSITION(CLEAN_EFFECTS,    "clean_effects");
2691
46
        PRINT_DISPOSITION(ATTACHED_PIC,     "attached_pic");
2692
46
        PRINT_DISPOSITION(TIMED_THUMBNAILS, "timed_thumbnails");
2693
46
        writer_print_section_footer(w);
2694
    }
2695
2696
86
    if (do_show_stream_tags)
2697
46
        ret = show_tags(w, stream->metadata, in_program ? SECTION_ID_PROGRAM_STREAM_TAGS : SECTION_ID_STREAM_TAGS);
2698
2699
86
    if (stream->nb_side_data) {
2700
7
        print_pkt_side_data(w, stream->codecpar, stream->side_data, stream->nb_side_data,
2701
                            SECTION_ID_STREAM_SIDE_DATA_LIST,
2702
                            SECTION_ID_STREAM_SIDE_DATA);
2703
    }
2704
2705
86
    writer_print_section_footer(w);
2706
86
    av_bprint_finalize(&pbuf, NULL);
2707
86
    fflush(stdout);
2708
2709
86
    return ret;
2710
}
2711
2712
45
static int show_streams(WriterContext *w, InputFile *ifile)
2713
{
2714
45
    AVFormatContext *fmt_ctx = ifile->fmt_ctx;
2715
45
    int i, ret = 0;
2716
2717
45
    writer_print_section_header(w, SECTION_ID_STREAMS);
2718
130
    for (i = 0; i < ifile->nb_streams; i++)
2719
85
        if (selected_streams[i]) {
2720
78
            ret = show_stream(w, fmt_ctx, i, &ifile->streams[i], 0);
2721
78
            if (ret < 0)
2722
                break;
2723
        }
2724
45
    writer_print_section_footer(w);
2725
2726
45
    return ret;
2727
}
2728
2729
3
static int show_program(WriterContext *w, InputFile *ifile, AVProgram *program)
2730
{
2731
3
    AVFormatContext *fmt_ctx = ifile->fmt_ctx;
2732
3
    int i, ret = 0;
2733
2734
3
    writer_print_section_header(w, SECTION_ID_PROGRAM);
2735
3
    print_int("program_id", program->id);
2736
3
    print_int("program_num", program->program_num);
2737
3
    print_int("nb_streams", program->nb_stream_indexes);
2738
3
    print_int("pmt_pid", program->pmt_pid);
2739
3
    print_int("pcr_pid", program->pcr_pid);
2740
3
    print_ts("start_pts", program->start_time);
2741
3
    print_time("start_time", program->start_time, &AV_TIME_BASE_Q);
2742
3
    print_ts("end_pts", program->end_time);
2743
3
    print_time("end_time", program->end_time, &AV_TIME_BASE_Q);
2744
3
    if (do_show_program_tags)
2745
        ret = show_tags(w, program->metadata, SECTION_ID_PROGRAM_TAGS);
2746
3
    if (ret < 0)
2747
        goto end;
2748
2749
3
    writer_print_section_header(w, SECTION_ID_PROGRAM_STREAMS);
2750
12
    for (i = 0; i < program->nb_stream_indexes; i++) {
2751
9
        if (selected_streams[program->stream_index[i]]) {
2752
8
            ret = show_stream(w, fmt_ctx, program->stream_index[i], &ifile->streams[program->stream_index[i]], 1);
2753
8
            if (ret < 0)
2754
                break;
2755
        }
2756
    }
2757
3
    writer_print_section_footer(w);
2758
2759
3
end:
2760
3
    writer_print_section_footer(w);
2761
3
    return ret;
2762
}
2763
2764
28
static int show_programs(WriterContext *w, InputFile *ifile)
2765
{
2766
28
    AVFormatContext *fmt_ctx = ifile->fmt_ctx;
2767
28
    int i, ret = 0;
2768
2769
28
    writer_print_section_header(w, SECTION_ID_PROGRAMS);
2770
31
    for (i = 0; i < fmt_ctx->nb_programs; i++) {
2771
3
        AVProgram *program = fmt_ctx->programs[i];
2772
3
        if (!program)
2773
            continue;
2774
3
        ret = show_program(w, ifile, program);
2775
3
        if (ret < 0)
2776
            break;
2777
    }
2778
28
    writer_print_section_footer(w);
2779
28
    return ret;
2780
}
2781
2782
3
static int show_chapters(WriterContext *w, InputFile *ifile)
2783
{
2784
3
    AVFormatContext *fmt_ctx = ifile->fmt_ctx;
2785
3
    int i, ret = 0;
2786
2787
3
    writer_print_section_header(w, SECTION_ID_CHAPTERS);
2788
16
    for (i = 0; i < fmt_ctx->nb_chapters; i++) {
2789
13
        AVChapter *chapter = fmt_ctx->chapters[i];
2790
2791
13
        writer_print_section_header(w, SECTION_ID_CHAPTER);
2792
13
        print_int("id", chapter->id);
2793
13
        print_q  ("time_base", chapter->time_base, '/');
2794
13
        print_int("start", chapter->start);
2795
13
        print_time("start_time", chapter->start, &chapter->time_base);
2796
13
        print_int("end", chapter->end);
2797
13
        print_time("end_time", chapter->end, &chapter->time_base);
2798
13
        if (do_show_chapter_tags)
2799
13
            ret = show_tags(w, chapter->metadata, SECTION_ID_CHAPTER_TAGS);
2800
13
        writer_print_section_footer(w);
2801
    }
2802
3
    writer_print_section_footer(w);
2803
2804
3
    return ret;
2805
}
2806
2807
20
static int show_format(WriterContext *w, InputFile *ifile)
2808
{
2809
20
    AVFormatContext *fmt_ctx = ifile->fmt_ctx;
2810
    char val_str[128];
2811
20
    int64_t size = fmt_ctx->pb ? avio_size(fmt_ctx->pb) : -1;
2812
20
    int ret = 0;
2813
2814
20
    writer_print_section_header(w, SECTION_ID_FORMAT);
2815
20
    print_str_validate("filename", fmt_ctx->url);
2816
20
    print_int("nb_streams",       fmt_ctx->nb_streams);
2817
20
    print_int("nb_programs",      fmt_ctx->nb_programs);
2818
20
    print_str("format_name",      fmt_ctx->iformat->name);
2819
20
    if (!do_bitexact) {
2820
5
        if (fmt_ctx->iformat->long_name) print_str    ("format_long_name", fmt_ctx->iformat->long_name);
2821
        else                             print_str_opt("format_long_name", "unknown");
2822
    }
2823
20
    print_time("start_time",      fmt_ctx->start_time, &AV_TIME_BASE_Q);
2824
20
    print_time("duration",        fmt_ctx->duration,   &AV_TIME_BASE_Q);
2825
20
    if (size >= 0) print_val    ("size", size, unit_byte_str);
2826
    else           print_str_opt("size", "N/A");
2827
20
    if (fmt_ctx->bit_rate > 0) print_val    ("bit_rate", fmt_ctx->bit_rate, unit_bit_per_second_str);
2828
    else                       print_str_opt("bit_rate", "N/A");
2829
20
    print_int("probe_score", fmt_ctx->probe_score);
2830
20
    if (do_show_format_tags)
2831
12
        ret = show_tags(w, fmt_ctx->metadata, SECTION_ID_FORMAT_TAGS);
2832
2833
20
    writer_print_section_footer(w);
2834
20
    fflush(stdout);
2835
20
    return ret;
2836
}
2837
2838
static void show_error(WriterContext *w, int err)
2839
{
2840
    char errbuf[128];
2841
    const char *errbuf_ptr = errbuf;
2842
2843
    if (av_strerror(err, errbuf, sizeof(errbuf)) < 0)
2844
        errbuf_ptr = strerror(AVUNERROR(err));
2845
2846
    writer_print_section_header(w, SECTION_ID_ERROR);
2847
    print_int("code", err);
2848
    print_str("string", errbuf_ptr);
2849
    writer_print_section_footer(w);
2850
}
2851
2852
74
static int open_input_file(InputFile *ifile, const char *filename,
2853
                           const char *print_filename)
2854
{
2855
    int err, i;
2856
74
    AVFormatContext *fmt_ctx = NULL;
2857
74
    AVDictionaryEntry *t = NULL;
2858
74
    int scan_all_pmts_set = 0;
2859
2860
74
    fmt_ctx = avformat_alloc_context();
2861
74
    if (!fmt_ctx) {
2862
        print_error(filename, AVERROR(ENOMEM));
2863
        exit_program(1);
2864
    }
2865
2866
74
    if (!av_dict_get(format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE)) {
2867
74
        av_dict_set(&format_opts, "scan_all_pmts", "1", AV_DICT_DONT_OVERWRITE);
2868
74
        scan_all_pmts_set = 1;
2869
    }
2870
74
    if ((err = avformat_open_input(&fmt_ctx, filename,
2871
                                   iformat, &format_opts)) < 0) {
2872
        print_error(filename, err);
2873
        return err;
2874
    }
2875
74
    if (print_filename) {
2876
7
        av_freep(&fmt_ctx->url);
2877
7
        fmt_ctx->url = av_strdup(print_filename);
2878
    }
2879
74
    ifile->fmt_ctx = fmt_ctx;
2880
74
    if (scan_all_pmts_set)
2881
74
        av_dict_set(&format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE);
2882
74
    while ((t = av_dict_get(format_opts, "", t, AV_DICT_IGNORE_SUFFIX)))
2883
        av_log(NULL, AV_LOG_WARNING, "Option %s skipped - not known to demuxer.\n", t->key);
2884
2885
74
    if (find_stream_info) {
2886
74
        AVDictionary **opts = setup_find_stream_info_opts(fmt_ctx, codec_opts);
2887
74
        int orig_nb_streams = fmt_ctx->nb_streams;
2888
2889
74
        err = avformat_find_stream_info(fmt_ctx, opts);
2890
2891
186
        for (i = 0; i < orig_nb_streams; i++)
2892
112
            av_dict_free(&opts[i]);
2893
74
        av_freep(&opts);
2894
2895
74
        if (err < 0) {
2896
            print_error(filename, err);
2897
            return err;
2898
        }
2899
    }
2900
2901
74
    av_dump_format(fmt_ctx, 0, filename, 0);
2902
2903
74
    ifile->streams = av_mallocz_array(fmt_ctx->nb_streams,
2904
                                      sizeof(*ifile->streams));
2905
74
    if (!ifile->streams)
2906
        exit(1);
2907
74
    ifile->nb_streams = fmt_ctx->nb_streams;
2908
2909
    /* bind a decoder to each input stream */
2910
193
    for (i = 0; i < fmt_ctx->nb_streams; i++) {
2911
119
        InputStream *ist = &ifile->streams[i];
2912
119
        AVStream *stream = fmt_ctx->streams[i];
2913
        AVCodec *codec;
2914
2915
119
        ist->st = stream;
2916
2917
119
        if (stream->codecpar->codec_id == AV_CODEC_ID_PROBE) {
2918
            av_log(NULL, AV_LOG_WARNING,
2919
                   "Failed to probe codec for input stream %d\n",
2920
                    stream->index);
2921
            continue;
2922
        }
2923
2924
119
        codec = avcodec_find_decoder(stream->codecpar->codec_id);
2925
119
        if (!codec) {
2926
7
            av_log(NULL, AV_LOG_WARNING,
2927
                    "Unsupported codec with id %d for input stream %d\n",
2928
7
                    stream->codecpar->codec_id, stream->index);
2929
7
            continue;
2930
        }
2931
        {
2932
112
            AVDictionary *opts = filter_codec_opts(codec_opts, stream->codecpar->codec_id,
2933
                                                   fmt_ctx, stream, codec);
2934
2935
112
            ist->dec_ctx = avcodec_alloc_context3(codec);
2936
112
            if (!ist->dec_ctx)
2937
                exit(1);
2938
2939
112
            err = avcodec_parameters_to_context(ist->dec_ctx, stream->codecpar);
2940
112
            if (err < 0)
2941
                exit(1);
2942
2943
112
            if (do_show_log) {
2944
                // For loging it is needed to disable at least frame threads as otherwise
2945
                // the log information would need to be reordered and matches up to contexts and frames
2946
                // That is in fact possible but not trivial
2947
                av_dict_set(&codec_opts, "threads", "1", 0);
2948
            }
2949
2950
112
            ist->dec_ctx->pkt_timebase = stream->time_base;
2951
112
            ist->dec_ctx->framerate = stream->avg_frame_rate;
2952
#if FF_API_LAVF_AVCTX
2953
112
            ist->dec_ctx->properties = stream->codec->properties;
2954
112
            ist->dec_ctx->coded_width = stream->codec->coded_width;
2955
112
            ist->dec_ctx->coded_height = stream->codec->coded_height;
2956
#endif
2957
2958
112
            if (avcodec_open2(ist->dec_ctx, codec, &opts) < 0) {
2959
                av_log(NULL, AV_LOG_WARNING, "Could not open codec for input stream %d\n",
2960
                       stream->index);
2961
                exit(1);
2962
            }
2963
2964
112
            if ((t = av_dict_get(opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
2965
                av_log(NULL, AV_LOG_ERROR, "Option %s for input stream %d not found\n",
2966
                       t->key, stream->index);
2967
                return AVERROR_OPTION_NOT_FOUND;
2968
            }
2969
        }
2970
    }
2971
2972
74
    ifile->fmt_ctx = fmt_ctx;
2973
74
    return 0;
2974
}
2975
2976
74
static void close_input_file(InputFile *ifile)
2977
{
2978
    int i;
2979
2980
    /* close decoder for each stream */
2981
193
    for (i = 0; i < ifile->nb_streams; i++)
2982
119
        if (ifile->streams[i].st->codecpar->codec_id != AV_CODEC_ID_NONE)
2983
115
            avcodec_free_context(&ifile->streams[i].dec_ctx);
2984
2985
74
    av_freep(&ifile->streams);
2986
74
    ifile->nb_streams = 0;
2987
2988
74
    avformat_close_input(&ifile->fmt_ctx);
2989
74
}
2990
2991
74
static int probe_file(WriterContext *wctx, const char *filename,
2992
                      const char *print_filename)
2993
{
2994
74
    InputFile ifile = { 0 };
2995
    int ret, i;
2996
    int section_id;
2997
2998

74
    do_read_frames = do_show_frames || do_count_frames;
2999

74
    do_read_packets = do_show_packets || do_count_packets;
3000
3001
74
    ret = open_input_file(&ifile, filename, print_filename);
3002
74
    if (ret < 0)
3003
        goto end;
3004
3005
#define CHECK_END if (ret < 0) goto end
3006
3007
74
    nb_streams = ifile.fmt_ctx->nb_streams;
3008
74
    REALLOCZ_ARRAY_STREAM(nb_streams_frames,0,ifile.fmt_ctx->nb_streams);
3009
74
    REALLOCZ_ARRAY_STREAM(nb_streams_packets,0,ifile.fmt_ctx->nb_streams);
3010
74
    REALLOCZ_ARRAY_STREAM(selected_streams,0,ifile.fmt_ctx->nb_streams);
3011
3012
193
    for (i = 0; i < ifile.fmt_ctx->nb_streams; i++) {
3013
119
        if (stream_specifier) {
3014
31
            ret = avformat_match_stream_specifier(ifile.fmt_ctx,
3015
31
                                                  ifile.fmt_ctx->streams[i],
3016
                                                  stream_specifier);
3017
31
            CHECK_END;
3018
            else
3019
31
                selected_streams[i] = ret;
3020
31
            ret = 0;
3021
        } else {
3022
88
            selected_streams[i] = 1;
3023
        }
3024
119
        if (!selected_streams[i])
3025
8
            ifile.fmt_ctx->streams[i]->discard = AVDISCARD_ALL;
3026
    }
3027
3028

74
    if (do_read_frames || do_read_packets) {
3029

45
        if (do_show_frames && do_show_packets &&
3030
9
            wctx->writer->flags & WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER)
3031
4
            section_id = SECTION_ID_PACKETS_AND_FRAMES;
3032

41
        else if (do_show_packets && !do_show_frames)
3033
13
            section_id = SECTION_ID_PACKETS;
3034
        else // (!do_show_packets && do_show_frames)
3035
28
            section_id = SECTION_ID_FRAMES;
3036

45
        if (do_show_frames || do_show_packets)
3037
45
            writer_print_section_header(wctx, section_id);
3038
45
        ret = read_packets(wctx, &ifile);
3039

45
        if (do_show_frames || do_show_packets)
3040
45
            writer_print_section_footer(wctx);
3041
45
        CHECK_END;
3042
    }
3043
3044
74
    if (do_show_programs) {
3045
28
        ret = show_programs(wctx, &ifile);
3046
28
        CHECK_END;
3047
    }
3048
3049
74
    if (do_show_streams) {
3050
45
        ret = show_streams(wctx, &ifile);
3051
45
        CHECK_END;
3052
    }
3053
74
    if (do_show_chapters) {
3054
3
        ret = show_chapters(wctx, &ifile);
3055
3
        CHECK_END;
3056
    }
3057
74
    if (do_show_format) {
3058
20
        ret = show_format(wctx, &ifile);
3059
20
        CHECK_END;
3060
    }
3061
3062
74
end:
3063
74
    if (ifile.fmt_ctx)
3064
74
        close_input_file(&ifile);
3065
74
    av_freep(&nb_streams_frames);
3066
74
    av_freep(&nb_streams_packets);
3067
74
    av_freep(&selected_streams);
3068
3069
74
    return ret;
3070
}
3071
3072
static void show_usage(void)
3073
{
3074
    av_log(NULL, AV_LOG_INFO, "Simple multimedia streams analyzer\n");
3075
    av_log(NULL, AV_LOG_INFO, "usage: %s [OPTIONS] [INPUT_FILE]\n", program_name);
3076
    av_log(NULL, AV_LOG_INFO, "\n");
3077
}
3078
3079
static void ffprobe_show_program_version(WriterContext *w)
3080
{
3081
    AVBPrint pbuf;
3082
    av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
3083
3084
    writer_print_section_header(w, SECTION_ID_PROGRAM_VERSION);
3085
    print_str("version", FFMPEG_VERSION);
3086
    print_fmt("copyright", "Copyright (c) %d-%d the FFmpeg developers",
3087
              program_birth_year, CONFIG_THIS_YEAR);
3088
    print_str("compiler_ident", CC_IDENT);
3089
    print_str("configuration", FFMPEG_CONFIGURATION);
3090
    writer_print_section_footer(w);
3091
3092
    av_bprint_finalize(&pbuf, NULL);
3093
}
3094
3095
#define SHOW_LIB_VERSION(libname, LIBNAME)                              \
3096
    do {                                                                \
3097
        if (CONFIG_##LIBNAME) {                                         \
3098
            unsigned int version = libname##_version();                 \
3099
            writer_print_section_header(w, SECTION_ID_LIBRARY_VERSION); \
3100
            print_str("name",    "lib" #libname);                       \
3101
            print_int("major",   LIB##LIBNAME##_VERSION_MAJOR);         \
3102
            print_int("minor",   LIB##LIBNAME##_VERSION_MINOR);         \
3103
            print_int("micro",   LIB##LIBNAME##_VERSION_MICRO);         \
3104
            print_int("version", version);                              \
3105
            print_str("ident",   LIB##LIBNAME##_IDENT);                 \
3106
            writer_print_section_footer(w);                             \
3107
        }                                                               \
3108
    } while (0)
3109
3110
static void ffprobe_show_library_versions(WriterContext *w)
3111
{
3112
    writer_print_section_header(w, SECTION_ID_LIBRARY_VERSIONS);
3113
    SHOW_LIB_VERSION(avutil,     AVUTIL);
3114
    SHOW_LIB_VERSION(avcodec,    AVCODEC);
3115
    SHOW_LIB_VERSION(avformat,   AVFORMAT);
3116
    SHOW_LIB_VERSION(avdevice,   AVDEVICE);
3117
    SHOW_LIB_VERSION(avfilter,   AVFILTER);
3118
    SHOW_LIB_VERSION(swscale,    SWSCALE);
3119
    SHOW_LIB_VERSION(swresample, SWRESAMPLE);
3120
    SHOW_LIB_VERSION(postproc,   POSTPROC);
3121
    writer_print_section_footer(w);
3122
}
3123
3124
#define PRINT_PIX_FMT_FLAG(flagname, name)                                \
3125
    do {                                                                  \
3126
        print_int(name, !!(pixdesc->flags & AV_PIX_FMT_FLAG_##flagname)); \
3127
    } while (0)
3128
3129
static void ffprobe_show_pixel_formats(WriterContext *w)
3130
{
3131
    const AVPixFmtDescriptor *pixdesc = NULL;
3132
    int i, n;
3133
3134
    writer_print_section_header(w, SECTION_ID_PIXEL_FORMATS);
3135
    while (pixdesc = av_pix_fmt_desc_next(pixdesc)) {
3136
        writer_print_section_header(w, SECTION_ID_PIXEL_FORMAT);
3137
        print_str("name", pixdesc->name);
3138
        print_int("nb_components", pixdesc->nb_components);
3139
        if ((pixdesc->nb_components >= 3) && !(pixdesc->flags & AV_PIX_FMT_FLAG_RGB)) {
3140
            print_int    ("log2_chroma_w", pixdesc->log2_chroma_w);
3141
            print_int    ("log2_chroma_h", pixdesc->log2_chroma_h);
3142
        } else {
3143
            print_str_opt("log2_chroma_w", "N/A");
3144
            print_str_opt("log2_chroma_h", "N/A");
3145
        }
3146
        n = av_get_bits_per_pixel(pixdesc);
3147
        if (n) print_int    ("bits_per_pixel", n);
3148
        else   print_str_opt("bits_per_pixel", "N/A");
3149
        if (do_show_pixel_format_flags) {
3150
            writer_print_section_header(w, SECTION_ID_PIXEL_FORMAT_FLAGS);
3151
            PRINT_PIX_FMT_FLAG(BE,        "big_endian");
3152
            PRINT_PIX_FMT_FLAG(PAL,       "palette");
3153
            PRINT_PIX_FMT_FLAG(BITSTREAM, "bitstream");
3154
            PRINT_PIX_FMT_FLAG(HWACCEL,   "hwaccel");
3155
            PRINT_PIX_FMT_FLAG(PLANAR,    "planar");
3156
            PRINT_PIX_FMT_FLAG(RGB,       "rgb");
3157
#if FF_API_PSEUDOPAL
3158
            PRINT_PIX_FMT_FLAG(PSEUDOPAL, "pseudopal");
3159
#endif
3160
            PRINT_PIX_FMT_FLAG(ALPHA,     "alpha");
3161
            writer_print_section_footer(w);
3162
        }
3163
        if (do_show_pixel_format_components && (pixdesc->nb_components > 0)) {
3164
            writer_print_section_header(w, SECTION_ID_PIXEL_FORMAT_COMPONENTS);
3165
            for (i = 0; i < pixdesc->nb_components; i++) {
3166
                writer_print_section_header(w, SECTION_ID_PIXEL_FORMAT_COMPONENT);
3167
                print_int("index", i + 1);
3168
                print_int("bit_depth", pixdesc->comp[i].depth);
3169
                writer_print_section_footer(w);
3170
            }
3171
            writer_print_section_footer(w);
3172
        }
3173
        writer_print_section_footer(w);
3174
    }
3175
    writer_print_section_footer(w);
3176
}
3177
3178
12
static int opt_format(void *optctx, const char *opt, const char *arg)
3179
{
3180
12
    iformat = av_find_input_format(arg);
3181
12
    if (!iformat) {
3182
        av_log(NULL, AV_LOG_ERROR, "Unknown input format: %s\n", arg);
3183
        return AVERROR(EINVAL);
3184
    }
3185
12
    return 0;
3186
}
3187
3188
512
static inline void mark_section_show_entries(SectionID section_id,
3189
                                             int show_all_entries, AVDictionary *entries)
3190
{
3191
512
    struct section *section = &sections[section_id];
3192
3193
512
    section->show_all_entries = show_all_entries;
3194
512
    if (show_all_entries) {
3195
        SectionID *id;
3196
769
        for (id = section->children_ids; *id != -1; id++)
3197
339
            mark_section_show_entries(*id, show_all_entries, entries);
3198
    } else {
3199
82
        av_dict_copy(&section->entries_to_show, entries, 0);
3200
    }
3201
512
}
3202
3203
86
static int match_section(const char *section_name,
3204
                         int show_all_entries, AVDictionary *entries)
3205
{
3206
86
    int i, ret = 0;
3207
3208
3870
    for (i = 0; i < FF_ARRAY_ELEMS(sections); i++) {
3209
3784
        const struct section *section = &sections[i];
3210
3784
        if (!strcmp(section_name, section->name) ||
3211

3694
            (section->unique_name && !strcmp(section_name, section->unique_name))) {
3212
114
            av_log(NULL, AV_LOG_DEBUG,
3213
                   "'%s' matches section with unique name '%s'\n", section_name,
3214
114
                   (char *)av_x_if_null(section->unique_name, section->name));
3215
114
            ret++;
3216
114
            mark_section_show_entries(section->id, show_all_entries, entries);
3217
        }
3218
    }
3219
86
    return ret;
3220
}
3221
3222
48
static int opt_show_entries(void *optctx, const char *opt, const char *arg)
3223
{
3224
48
    const char *p = arg;
3225
48
    int ret = 0;
3226
3227
134
    while (*p) {
3228
86
        AVDictionary *entries = NULL;
3229
86
        char *section_name = av_get_token(&p, "=:");
3230
86
        int show_all_entries = 0;
3231
3232
86
        if (!section_name) {
3233
            av_log(NULL, AV_LOG_ERROR,
3234
                   "Missing section name for option '%s'\n", opt);
3235
            return AVERROR(EINVAL);
3236
        }
3237
3238
86
        if (*p == '=') {
3239
58
            p++;
3240

172
            while (*p && *p != ':') {
3241
114
                char *entry = av_get_token(&p, ",:");
3242
114
                if (!entry)
3243
                    break;
3244
114
                av_log(NULL, AV_LOG_VERBOSE,
3245
                       "Adding '%s' to the entries to show in section '%s'\n",
3246
                       entry, section_name);
3247
114
                av_dict_set(&entries, entry, "", AV_DICT_DONT_STRDUP_KEY);
3248
114
                if (*p == ',')
3249
56
                    p++;
3250
            }
3251
        } else {
3252
28
            show_all_entries = 1;
3253
        }
3254
3255
86
        ret = match_section(section_name, show_all_entries, entries);
3256
86
        if (ret == 0) {
3257
            av_log(NULL, AV_LOG_ERROR, "No match for section '%s'\n", section_name);
3258
            ret = AVERROR(EINVAL);
3259
        }
3260
86
        av_dict_free(&entries);
3261
86
        av_free(section_name);
3262
3263
86
        if (ret <= 0)
3264
            break;
3265
86
        if (*p)
3266
38
            p++;
3267
    }
3268
3269
48
    return ret;
3270
}
3271
3272
static int opt_show_format_entry(void *optctx, const char *opt, const char *arg)
3273
{
3274
    char *buf = av_asprintf("format=%s", arg);
3275
    int ret;
3276
3277
    if (!buf)
3278
        return AVERROR(ENOMEM);
3279
3280
    av_log(NULL, AV_LOG_WARNING,
3281
           "Option '%s' is deprecated, use '-show_entries format=%s' instead\n",
3282
           opt, arg);
3283
    ret = opt_show_entries(optctx, opt, buf);
3284
    av_free(buf);
3285
    return ret;
3286
}
3287
3288
74
static void opt_input_file(void *optctx, const char *arg)
3289
{
3290
74
    if (input_filename) {
3291
        av_log(NULL, AV_LOG_ERROR,
3292
                "Argument '%s' provided as input filename, but '%s' was already specified.\n",
3293
                arg, input_filename);
3294
        exit_program(1);
3295
    }
3296
74
    if (!strcmp(arg, "-"))
3297
        arg = "pipe:";
3298
74
    input_filename = arg;
3299
74
}
3300
3301
7
static int opt_input_file_i(void *optctx, const char *opt, const char *arg)
3302
{
3303
7
    opt_input_file(optctx, arg);
3304
7
    return 0;
3305
}
3306
3307
7
static int opt_print_filename(void *optctx, const char *opt, const char *arg)
3308
{
3309
7
    print_input_filename = arg;
3310
7
    return 0;
3311
}
3312
3313
void show_help_default(const char *opt, const char *arg)
3314
{
3315
    av_log_set_callback(log_callback_help);
3316
    show_usage();
3317
    show_help_options(options, "Main options:", 0, 0, 0);
3318
    printf("\n");
3319
3320
    show_help_children(avformat_get_class(), AV_OPT_FLAG_DECODING_PARAM);
3321
    show_help_children(avcodec_get_class(), AV_OPT_FLAG_DECODING_PARAM);
3322
}
3323
3324
/**
3325
 * Parse interval specification, according to the format:
3326
 * INTERVAL ::= [START|+START_OFFSET][%[END|+END_OFFSET]]
3327
 * INTERVALS ::= INTERVAL[,INTERVALS]
3328
*/
3329
static int parse_read_interval(const char *interval_spec,
3330
                               ReadInterval *interval)
3331
{
3332
    int ret = 0;
3333
    char *next, *p, *spec = av_strdup(interval_spec);
3334
    if (!spec)
3335
        return AVERROR(ENOMEM);
3336
3337
    if (!*spec) {
3338
        av_log(NULL, AV_LOG_ERROR, "Invalid empty interval specification\n");
3339
        ret = AVERROR(EINVAL);
3340
        goto end;
3341
    }
3342
3343
    p = spec;
3344
    next = strchr(spec, '%');
3345
    if (next)
3346
        *next++ = 0;
3347
3348
    /* parse first part */
3349
    if (*p) {
3350
        interval->has_start = 1;
3351
3352
        if (*p == '+') {
3353
            interval->start_is_offset = 1;
3354
            p++;
3355
        } else {
3356
            interval->start_is_offset = 0;
3357
        }
3358
3359
        ret = av_parse_time(&interval->start, p, 1);
3360
        if (ret < 0) {
3361
            av_log(NULL, AV_LOG_ERROR, "Invalid interval start specification '%s'\n", p);
3362
            goto end;
3363
        }
3364
    } else {
3365
        interval->has_start = 0;
3366
    }
3367
3368
    /* parse second part */
3369
    p = next;
3370
    if (p && *p) {
3371
        int64_t us;
3372
        interval->has_end = 1;
3373
3374
        if (*p == '+') {
3375
            interval->end_is_offset = 1;
3376
            p++;
3377
        } else {
3378
            interval->end_is_offset = 0;
3379
        }
3380
3381
        if (interval->end_is_offset && *p == '#') {
3382
            long long int lli;
3383
            char *tail;
3384
            interval->duration_frames = 1;
3385
            p++;
3386
            lli = strtoll(p, &tail, 10);
3387
            if (*tail || lli < 0) {
3388
                av_log(NULL, AV_LOG_ERROR,
3389
                       "Invalid or negative value '%s' for duration number of frames\n", p);
3390
                goto end;
3391
            }
3392
            interval->end = lli;
3393
        } else {
3394
            interval->duration_frames = 0;
3395
            ret = av_parse_time(&us, p, 1);
3396
            if (ret < 0) {
3397
                av_log(NULL, AV_LOG_ERROR, "Invalid interval end/duration specification '%s'\n", p);
3398
                goto end;
3399
            }
3400
            interval->end = us;
3401
        }
3402
    } else {
3403
        interval->has_end = 0;
3404
    }
3405
3406
end:
3407
    av_free(spec);
3408
    return ret;
3409
}
3410
3411
static int parse_read_intervals(const char *intervals_spec)
3412
{
3413
    int ret, n, i;
3414
    char *p, *spec = av_strdup(intervals_spec);
3415
    if (!spec)
3416
        return AVERROR(ENOMEM);
3417
3418
    /* preparse specification, get number of intervals */
3419
    for (n = 0, p = spec; *p; p++)
3420
        if (*p == ',')
3421
            n++;
3422
    n++;
3423
3424
    read_intervals = av_malloc_array(n, sizeof(*read_intervals));
3425
    if (!read_intervals) {
3426
        ret = AVERROR(ENOMEM);
3427
        goto end;
3428
    }
3429
    read_intervals_nb = n;
3430
3431
    /* parse intervals */
3432
    p = spec;
3433
    for (i = 0; p; i++) {
3434
        char *next;
3435
3436
        av_assert0(i < read_intervals_nb);
3437
        next = strchr(p, ',');
3438
        if (next)
3439
            *next++ = 0;
3440
3441
        read_intervals[i].id = i;
3442
        ret = parse_read_interval(p, &read_intervals[i]);
3443
        if (ret < 0) {
3444
            av_log(NULL, AV_LOG_ERROR, "Error parsing read interval #%d '%s'\n",
3445
                   i, p);
3446
            goto end;
3447
        }
3448
        av_log(NULL, AV_LOG_VERBOSE, "Parsed log interval ");
3449
        log_read_interval(&read_intervals[i], NULL, AV_LOG_VERBOSE);
3450
        p = next;
3451
    }
3452
    av_assert0(i == read_intervals_nb);
3453
3454
end:
3455
    av_free(spec);
3456
    return ret;
3457