GCC Code Coverage Report
Directory: ../../../ffmpeg/ Exec Total Coverage
File: src/fftools/ffprobe.c Lines: 1388 1961 70.8 %
Date: 2021-01-21 21:11:50 Branches: 766 1225 62.5 %

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

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

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

29292
        if (show_float || (use_value_prefix && vald != (long long int)vald))
411
22539
            snprintf(buf, buf_size, "%f", vald);
412
        else
413
6753
            snprintf(buf, buf_size, "%lld", vali);
414

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


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

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

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

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

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


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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3
            wctx->level && wctx->nb_item[wctx->level-1])
1723
2
            printf("\n");
1724
37
        xml->indent_level++;
1725
1726
37
        if (section->flags & SECTION_FLAG_IS_ARRAY) {
1727
2
            XML_INDENT(); printf("<%s>\n", section->name);
1728
        } else {
1729
35
            XML_INDENT(); printf("<%s ", section->name);
1730
35
            xml->within_tag = 1;
1731
        }
1732
    }
1733
}
1734
1735
42
static void xml_print_section_footer(WriterContext *wctx)
1736
{
1737
42
    XMLContext *xml = wctx->priv;
1738
42
    const struct section *section = wctx->section[wctx->level];
1739
1740
42
    if (wctx->level == 0) {
1741
1
        printf("</%sffprobe>\n", xml->fully_qualified ? "ffprobe:" : "");
1742
41
    } else if (xml->within_tag) {
1743
31
        xml->within_tag = 0;
1744
31
        printf("/>\n");
1745
31
        xml->indent_level--;
1746
10
    } else if (section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS) {
1747
4
        xml->indent_level--;
1748
    } else {
1749
6
        XML_INDENT(); printf("</%s>\n", section->name);
1750
6
        xml->indent_level--;
1751
    }
1752
42
}
1753
1754
283
static void xml_print_str(WriterContext *wctx, const char *key, const char *value)
1755
{
1756
    AVBPrint buf;
1757
283
    XMLContext *xml = wctx->priv;
1758
283
    const struct section *section = wctx->section[wctx->level];
1759
1760
283
    av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
1761
1762
283
    if (section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS) {
1763
9
        XML_INDENT();
1764
9
        printf("<%s key=\"%s\"",
1765
               section->element_name, xml_escape_str(&buf, key, wctx));
1766
9
        av_bprint_clear(&buf);
1767
9
        printf(" value=\"%s\"/>\n", xml_escape_str(&buf, value, wctx));
1768
    } else {
1769
274
        if (wctx->nb_item[wctx->level])
1770
245
            printf(" ");
1771
274
        printf("%s=\"%s\"", key, xml_escape_str(&buf, value, wctx));
1772
    }
1773
1774
283
    av_bprint_finalize(&buf, NULL);
1775
283
}
1776
1777
271
static void xml_print_int(WriterContext *wctx, const char *key, long long int value)
1778
{
1779
271
    if (wctx->nb_item[wctx->level])
1780
265
        printf(" ");
1781
271
    printf("%s=\"%lld\"", key, value);
1782
271
}
1783
1784
static Writer xml_writer = {
1785
    .name                 = "xml",
1786
    .priv_size            = sizeof(XMLContext),
1787
    .init                 = xml_init,
1788
    .print_section_header = xml_print_section_header,
1789
    .print_section_footer = xml_print_section_footer,
1790
    .print_integer        = xml_print_int,
1791
    .print_string         = xml_print_str,
1792
    .flags = WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER,
1793
    .priv_class           = &xml_class,
1794
};
1795
1796
76
static void writer_register_all(void)
1797
{
1798
    static int initialized;
1799
1800
76
    if (initialized)
1801
        return;
1802
76
    initialized = 1;
1803
1804
76
    writer_register(&default_writer);
1805
76
    writer_register(&compact_writer);
1806
76
    writer_register(&csv_writer);
1807
76
    writer_register(&flat_writer);
1808
76
    writer_register(&ini_writer);
1809
76
    writer_register(&json_writer);
1810
76
    writer_register(&xml_writer);
1811
}
1812
1813
#define print_fmt(k, f, ...) do {              \
1814
    av_bprint_clear(&pbuf);                    \
1815
    av_bprintf(&pbuf, f, __VA_ARGS__);         \
1816
    writer_print_string(w, k, pbuf.str, 0);    \
1817
} while (0)
1818
1819
#define print_int(k, v)         writer_print_integer(w, k, v)
1820
#define print_q(k, v, s)        writer_print_rational(w, k, v, s)
1821
#define print_str(k, v)         writer_print_string(w, k, v, 0)
1822
#define print_str_opt(k, v)     writer_print_string(w, k, v, PRINT_STRING_OPT)
1823
#define print_str_validate(k, v) writer_print_string(w, k, v, PRINT_STRING_VALIDATE)
1824
#define print_time(k, v, tb)    writer_print_time(w, k, v, tb, 0)
1825
#define print_ts(k, v)          writer_print_ts(w, k, v, 0)
1826
#define print_duration_time(k, v, tb) writer_print_time(w, k, v, tb, 1)
1827
#define print_duration_ts(k, v)       writer_print_ts(w, k, v, 1)
1828
#define print_val(k, v, u) do {                                     \
1829
    struct unit_value uv;                                           \
1830
    uv.val.i = v;                                                   \
1831
    uv.unit = u;                                                    \
1832
    writer_print_string(w, k, value_string(val_str, sizeof(val_str), uv), 0); \
1833
} while (0)
1834
1835
#define print_section_header(s) writer_print_section_header(w, s)
1836
#define print_section_footer(s) writer_print_section_footer(w, s)
1837
1838
#define REALLOCZ_ARRAY_STREAM(ptr, cur_n, new_n)                        \
1839
{                                                                       \
1840
    ret = av_reallocp_array(&(ptr), (new_n), sizeof(*(ptr)));           \
1841
    if (ret < 0)                                                        \
1842
        goto end;                                                       \
1843
    memset( (ptr) + (cur_n), 0, ((new_n) - (cur_n)) * sizeof(*(ptr)) ); \
1844
}
1845
1846
1245
static inline int show_tags(WriterContext *w, AVDictionary *tags, int section_id)
1847
{
1848
1245
    AVDictionaryEntry *tag = NULL;
1849
1245
    int ret = 0;
1850
1851
1245
    if (!tags)
1852
635
        return 0;
1853
610
    writer_print_section_header(w, section_id);
1854
1855
3101
    while ((tag = av_dict_get(tags, "", tag, AV_DICT_IGNORE_SUFFIX))) {
1856
2491
        if ((ret = print_str_validate(tag->key, tag->value)) < 0)
1857
            break;
1858
    }
1859
610
    writer_print_section_footer(w);
1860
1861
610
    return ret;
1862
}
1863
1864
1
static void print_dynamic_hdr10_plus(WriterContext *w, const AVDynamicHDRPlus *metadata)
1865
{
1866
1
    if (!metadata)
1867
        return;
1868
1
    print_int("application version", metadata->application_version);
1869
1
    print_int("num_windows", metadata->num_windows);
1870
1
    for (int n = 1; n < metadata->num_windows; n++) {
1871
        const AVHDRPlusColorTransformParams *params = &metadata->params[n];
1872
        print_q("window_upper_left_corner_x",
1873
                params->window_upper_left_corner_x,'/');
1874
        print_q("window_upper_left_corner_y",
1875
                params->window_upper_left_corner_y,'/');
1876
        print_q("window_lower_right_corner_x",
1877
                params->window_lower_right_corner_x,'/');
1878
        print_q("window_lower_right_corner_y",
1879
                params->window_lower_right_corner_y,'/');
1880
        print_q("window_upper_left_corner_x",
1881
                params->window_upper_left_corner_x,'/');
1882
        print_q("window_upper_left_corner_y",
1883
                params->window_upper_left_corner_y,'/');
1884
        print_int("center_of_ellipse_x",
1885
                  params->center_of_ellipse_x ) ;
1886
        print_int("center_of_ellipse_y",
1887
                  params->center_of_ellipse_y );
1888
        print_int("rotation_angle",
1889
                  params->rotation_angle);
1890
        print_int("semimajor_axis_internal_ellipse",
1891
                  params->semimajor_axis_internal_ellipse);
1892
        print_int("semimajor_axis_external_ellipse",
1893
                  params->semimajor_axis_external_ellipse);
1894
        print_int("semiminor_axis_external_ellipse",
1895
                  params->semiminor_axis_external_ellipse);
1896
        print_int("overlap_process_option",
1897
                  params->overlap_process_option);
1898
    }
1899
1
    print_q("targeted_system_display_maximum_luminance",
1900
            metadata->targeted_system_display_maximum_luminance,'/');
1901
1
    if (metadata->targeted_system_display_actual_peak_luminance_flag) {
1902
        print_int("num_rows_targeted_system_display_actual_peak_luminance",
1903
                  metadata->num_rows_targeted_system_display_actual_peak_luminance);
1904
        print_int("num_cols_targeted_system_display_actual_peak_luminance",
1905
                  metadata->num_cols_targeted_system_display_actual_peak_luminance);
1906
        for (int i = 0; i < metadata->num_rows_targeted_system_display_actual_peak_luminance; i++) {
1907
            for (int j = 0; j < metadata->num_cols_targeted_system_display_actual_peak_luminance; j++) {
1908
                print_q("targeted_system_display_actual_peak_luminance",
1909
                        metadata->targeted_system_display_actual_peak_luminance[i][j],'/');
1910
            }
1911
        }
1912
    }
1913
2
    for (int n = 0; n < metadata->num_windows; n++) {
1914
1
        const AVHDRPlusColorTransformParams *params = &metadata->params[n];
1915
4
        for (int i = 0; i < 3; i++) {
1916
3
            print_q("maxscl",params->maxscl[i],'/');
1917
        }
1918
1
        print_q("average_maxrgb",
1919
                params->average_maxrgb,'/');
1920
1
        print_int("num_distribution_maxrgb_percentiles",
1921
                  params->num_distribution_maxrgb_percentiles);
1922
10
        for (int i = 0; i < params->num_distribution_maxrgb_percentiles; i++) {
1923
9
            print_int("distribution_maxrgb_percentage",
1924
                      params->distribution_maxrgb[i].percentage);
1925
9
            print_q("distribution_maxrgb_percentile",
1926
                    params->distribution_maxrgb[i].percentile,'/');
1927
        }
1928
1
        print_q("fraction_bright_pixels",
1929
                params->fraction_bright_pixels,'/');
1930
    }
1931
1
    if (metadata->mastering_display_actual_peak_luminance_flag) {
1932
        print_int("num_rows_mastering_display_actual_peak_luminance",
1933
                  metadata->num_rows_mastering_display_actual_peak_luminance);
1934
        print_int("num_cols_mastering_display_actual_peak_luminance",
1935
                  metadata->num_cols_mastering_display_actual_peak_luminance);
1936
        for (int i = 0; i < metadata->num_rows_mastering_display_actual_peak_luminance; i++) {
1937
            for (int j = 0; j <  metadata->num_cols_mastering_display_actual_peak_luminance; j++) {
1938
                print_q("mastering_display_actual_peak_luminance",
1939
                        metadata->mastering_display_actual_peak_luminance[i][j],'/');
1940
            }
1941
        }
1942
    }
1943
1944
2
    for (int n = 0; n < metadata->num_windows; n++) {
1945
1
        const AVHDRPlusColorTransformParams *params = &metadata->params[n];
1946
1
        if (params->tone_mapping_flag) {
1947
1
            print_q("knee_point_x", params->knee_point_x,'/');
1948
1
            print_q("knee_point_y", params->knee_point_y,'/');
1949
1
            print_int("num_bezier_curve_anchors",
1950
                      params->num_bezier_curve_anchors );
1951
10
            for (int i = 0; i < params->num_bezier_curve_anchors; i++) {
1952
9
                print_q("bezier_curve_anchors",
1953
                        params->bezier_curve_anchors[i],'/');
1954
            }
1955
        }
1956
1
        if (params->color_saturation_mapping_flag) {
1957
            print_q("color_saturation_weight",
1958
                    params->color_saturation_weight,'/');
1959
        }
1960
    }
1961
}
1962
1963
207
static void print_pkt_side_data(WriterContext *w,
1964
                                AVCodecParameters *par,
1965
                                const AVPacketSideData *side_data,
1966
                                int nb_side_data,
1967
                                SectionID id_data_list,
1968
                                SectionID id_data)
1969
{
1970
    int i;
1971
1972
207
    writer_print_section_header(w, id_data_list);
1973
417
    for (i = 0; i < nb_side_data; i++) {
1974
210
        const AVPacketSideData *sd = &side_data[i];
1975
210
        const char *name = av_packet_side_data_name(sd->type);
1976
1977
210
        writer_print_section_header(w, id_data);
1978
210
        print_str("side_data_type", name ? name : "unknown");
1979

210
        if (sd->type == AV_PKT_DATA_DISPLAYMATRIX && sd->size >= 9*4) {
1980
2
            writer_print_integers(w, "displaymatrix", sd->data, 9, " %11d", 3, 4, 1);
1981
2
            print_int("rotation", av_display_rotation_get((int32_t *)sd->data));
1982
208
        } else if (sd->type == AV_PKT_DATA_STEREO3D) {
1983
2
            const AVStereo3D *stereo = (AVStereo3D *)sd->data;
1984
2
            print_str("type", av_stereo3d_type_name(stereo->type));
1985
2
            print_int("inverted", !!(stereo->flags & AV_STEREO3D_FLAG_INVERT));
1986
206
        } else if (sd->type == AV_PKT_DATA_SPHERICAL) {
1987
2
            const AVSphericalMapping *spherical = (AVSphericalMapping *)sd->data;
1988
2
            print_str("projection", av_spherical_projection_name(spherical->projection));
1989
2
            if (spherical->projection == AV_SPHERICAL_CUBEMAP) {
1990
                print_int("padding", spherical->padding);
1991
2
            } else if (spherical->projection == AV_SPHERICAL_EQUIRECTANGULAR_TILE) {
1992
                size_t l, t, r, b;
1993
2
                av_spherical_tile_bounds(spherical, par->width, par->height,
1994
                                         &l, &t, &r, &b);
1995
2
                print_int("bound_left", l);
1996
2
                print_int("bound_top", t);
1997
2
                print_int("bound_right", r);
1998
2
                print_int("bound_bottom", b);
1999
            }
2000
2001
2
            print_int("yaw", (double) spherical->yaw / (1 << 16));
2002
2
            print_int("pitch", (double) spherical->pitch / (1 << 16));
2003
2
            print_int("roll", (double) spherical->roll / (1 << 16));
2004

204
        } else if (sd->type == AV_PKT_DATA_SKIP_SAMPLES && sd->size == 10) {
2005
5
            print_int("skip_samples",    AV_RL32(sd->data));
2006
5
            print_int("discard_padding", AV_RL32(sd->data + 4));
2007
5
            print_int("skip_reason",     AV_RL8(sd->data + 8));
2008
5
            print_int("discard_reason",  AV_RL8(sd->data + 9));
2009
199
        } else if (sd->type == AV_PKT_DATA_MASTERING_DISPLAY_METADATA) {
2010
1
            AVMasteringDisplayMetadata *metadata = (AVMasteringDisplayMetadata *)sd->data;
2011
2012
1
            if (metadata->has_primaries) {
2013
1
                print_q("red_x", metadata->display_primaries[0][0], '/');
2014
1
                print_q("red_y", metadata->display_primaries[0][1], '/');
2015
1
                print_q("green_x", metadata->display_primaries[1][0], '/');
2016
1
                print_q("green_y", metadata->display_primaries[1][1], '/');
2017
1
                print_q("blue_x", metadata->display_primaries[2][0], '/');
2018
1
                print_q("blue_y", metadata->display_primaries[2][1], '/');
2019
2020
1
                print_q("white_point_x", metadata->white_point[0], '/');
2021
1
                print_q("white_point_y", metadata->white_point[1], '/');
2022
            }
2023
2024
1
            if (metadata->has_luminance) {
2025
1
                print_q("min_luminance", metadata->min_luminance, '/');
2026
1
                print_q("max_luminance", metadata->max_luminance, '/');
2027
            }
2028
198
        } else if (sd->type == AV_PKT_DATA_CONTENT_LIGHT_LEVEL) {
2029
1
            AVContentLightMetadata *metadata = (AVContentLightMetadata *)sd->data;
2030
1
            print_int("max_content", metadata->MaxCLL);
2031
1
            print_int("max_average", metadata->MaxFALL);
2032
197
        } else if (sd->type == AV_PKT_DATA_DOVI_CONF) {
2033
            AVDOVIDecoderConfigurationRecord *dovi = (AVDOVIDecoderConfigurationRecord *)sd->data;
2034
            print_int("dv_version_major", dovi->dv_version_major);
2035
            print_int("dv_version_minor", dovi->dv_version_minor);
2036
            print_int("dv_profile", dovi->dv_profile);
2037
            print_int("dv_level", dovi->dv_level);
2038
            print_int("rpu_present_flag", dovi->rpu_present_flag);
2039
            print_int("el_present_flag", dovi->el_present_flag);
2040
            print_int("bl_present_flag", dovi->bl_present_flag);
2041
            print_int("dv_bl_signal_compatibility_id", dovi->dv_bl_signal_compatibility_id);
2042
        }
2043
210
        writer_print_section_footer(w);
2044
    }
2045
207
    writer_print_section_footer(w);
2046
207
}
2047
2048
494
static void print_color_range(WriterContext *w, enum AVColorRange color_range)
2049
{
2050
494
    const char *val = av_color_range_name(color_range);
2051

494
    if (!val || color_range == AVCOL_RANGE_UNSPECIFIED) {
2052
401
        print_str_opt("color_range", "unknown");
2053
    } else {
2054
93
        print_str("color_range", val);
2055
    }
2056
494
}
2057
2058
494
static void print_color_space(WriterContext *w, enum AVColorSpace color_space)
2059
{
2060
494
    const char *val = av_color_space_name(color_space);
2061

494
    if (!val || color_space == AVCOL_SPC_UNSPECIFIED) {
2062
416
        print_str_opt("color_space", "unknown");
2063
    } else {
2064
78
        print_str("color_space", val);
2065
    }
2066
494
}
2067
2068
494
static void print_primaries(WriterContext *w, enum AVColorPrimaries color_primaries)
2069
{
2070
494
    const char *val = av_color_primaries_name(color_primaries);
2071

494
    if (!val || color_primaries == AVCOL_PRI_UNSPECIFIED) {
2072
419
        print_str_opt("color_primaries", "unknown");
2073
    } else {
2074
75
        print_str("color_primaries", val);
2075
    }
2076
494
}
2077
2078
494
static void print_color_trc(WriterContext *w, enum AVColorTransferCharacteristic color_trc)
2079
{
2080
494
    const char *val = av_color_transfer_name(color_trc);
2081

494
    if (!val || color_trc == AVCOL_TRC_UNSPECIFIED) {
2082
418
        print_str_opt("color_transfer", "unknown");
2083
    } else {
2084
76
        print_str("color_transfer", val);
2085
    }
2086
494
}
2087
2088
494
static void print_chroma_location(WriterContext *w, enum AVChromaLocation chroma_location)
2089
{
2090
494
    const char *val = av_chroma_location_name(chroma_location);
2091

494
    if (!val || chroma_location == AVCHROMA_LOC_UNSPECIFIED) {
2092
402
        print_str_opt("chroma_location", "unspecified");
2093
    } else {
2094
92
        print_str("chroma_location", val);
2095
    }
2096
494
}
2097
2098
2099
5952
static void clear_log(int need_lock)
2100
{
2101
    int i;
2102
2103
5952
    if (need_lock)
2104
5952
        pthread_mutex_lock(&log_mutex);
2105
5952
    for (i=0; i<log_buffer_size; i++) {
2106
        av_freep(&log_buffer[i].context_name);
2107
        av_freep(&log_buffer[i].parent_name);
2108
        av_freep(&log_buffer[i].log_message);
2109
    }
2110
5952
    log_buffer_size = 0;
2111
5952
    if(need_lock)
2112
5952
        pthread_mutex_unlock(&log_mutex);
2113
5952
}
2114
2115
static int show_log(WriterContext *w, int section_ids, int section_id, int log_level)
2116
{
2117
    int i;
2118
    pthread_mutex_lock(&log_mutex);
2119
    if (!log_buffer_size) {
2120
        pthread_mutex_unlock(&log_mutex);
2121
        return 0;
2122
    }
2123
    writer_print_section_header(w, section_ids);
2124
2125
    for (i=0; i<log_buffer_size; i++) {
2126
        if (log_buffer[i].log_level <= log_level) {
2127
            writer_print_section_header(w, section_id);
2128
            print_str("context", log_buffer[i].context_name);
2129
            print_int("level", log_buffer[i].log_level);
2130
            print_int("category", log_buffer[i].category);
2131
            if (log_buffer[i].parent_name) {
2132
                print_str("parent_context", log_buffer[i].parent_name);
2133
                print_int("parent_category", log_buffer[i].parent_category);
2134
            } else {
2135
                print_str_opt("parent_context", "N/A");
2136
                print_str_opt("parent_category", "N/A");
2137
            }
2138
            print_str("message", log_buffer[i].log_message);
2139
            writer_print_section_footer(w);
2140
        }
2141
    }
2142
    clear_log(0);
2143
    pthread_mutex_unlock(&log_mutex);
2144
2145
    writer_print_section_footer(w);
2146
2147
    return 0;
2148
}
2149
2150
3588
static void show_packet(WriterContext *w, InputFile *ifile, AVPacket *pkt, int packet_idx)
2151
{
2152
    char val_str[128];
2153
3588
    AVStream *st = ifile->streams[pkt->stream_index].st;
2154
    AVBPrint pbuf;
2155
    const char *s;
2156
2157
3588
    av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
2158
2159
3588
    writer_print_section_header(w, SECTION_ID_PACKET);
2160
2161
3588
    s = av_get_media_type_string(st->codecpar->codec_type);
2162
3588
    if (s) print_str    ("codec_type", s);
2163
    else   print_str_opt("codec_type", "unknown");
2164
3588
    print_int("stream_index",     pkt->stream_index);
2165
3588
    print_ts  ("pts",             pkt->pts);
2166
3588
    print_time("pts_time",        pkt->pts, &st->time_base);
2167
3588
    print_ts  ("dts",             pkt->dts);
2168
3588
    print_time("dts_time",        pkt->dts, &st->time_base);
2169
3588
    print_duration_ts("duration",        pkt->duration);
2170
3588
    print_duration_time("duration_time", pkt->duration, &st->time_base);
2171
3588
    print_duration_ts("convergence_duration", pkt->convergence_duration);
2172
3588
    print_duration_time("convergence_duration_time", pkt->convergence_duration, &st->time_base);
2173
3588
    print_val("size",             pkt->size, unit_byte_str);
2174
3588
    if (pkt->pos != -1) print_fmt    ("pos", "%"PRId64, pkt->pos);
2175
82
    else                print_str_opt("pos", "N/A");
2176

3588
    print_fmt("flags", "%c%c",      pkt->flags & AV_PKT_FLAG_KEY ? 'K' : '_',
2177
              pkt->flags & AV_PKT_FLAG_DISCARD ? 'D' : '_');
2178
2179
3588
    if (pkt->side_data_elems) {
2180
        int size;
2181
        const uint8_t *side_metadata;
2182
2183
200
        side_metadata = av_packet_get_side_data(pkt, AV_PKT_DATA_STRINGS_METADATA, &size);
2184

200
        if (side_metadata && size && do_show_packet_tags) {
2185
131
            AVDictionary *dict = NULL;
2186
131
            if (av_packet_unpack_dictionary(side_metadata, size, &dict) >= 0)
2187
131
                show_tags(w, dict, SECTION_ID_PACKET_TAGS);
2188
131
            av_dict_free(&dict);
2189
        }
2190
2191
200
        print_pkt_side_data(w, st->codecpar, pkt->side_data, pkt->side_data_elems,
2192
                            SECTION_ID_PACKET_SIDE_DATA_LIST,
2193
                            SECTION_ID_PACKET_SIDE_DATA);
2194
    }
2195
2196
3588
    if (do_show_data)
2197
        writer_print_data(w, "data", pkt->data, pkt->size);
2198
3588
    writer_print_data_hash(w, "data_hash", pkt->data, pkt->size);
2199
3588
    writer_print_section_footer(w);
2200
2201
3588
    av_bprint_finalize(&pbuf, NULL);
2202
3588
    fflush(stdout);
2203
3588
}
2204
2205
static void show_subtitle(WriterContext *w, AVSubtitle *sub, AVStream *stream,
2206
                          AVFormatContext *fmt_ctx)
2207
{
2208
    AVBPrint pbuf;
2209
2210
    av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
2211
2212
    writer_print_section_header(w, SECTION_ID_SUBTITLE);
2213
2214
    print_str ("media_type",         "subtitle");
2215
    print_ts  ("pts",                 sub->pts);
2216
    print_time("pts_time",            sub->pts, &AV_TIME_BASE_Q);
2217
    print_int ("format",              sub->format);
2218
    print_int ("start_display_time",  sub->start_display_time);
2219
    print_int ("end_display_time",    sub->end_display_time);
2220
    print_int ("num_rects",           sub->num_rects);
2221
2222
    writer_print_section_footer(w);
2223
2224
    av_bprint_finalize(&pbuf, NULL);
2225
    fflush(stdout);
2226
}
2227
2228
3024
static void show_frame(WriterContext *w, AVFrame *frame, AVStream *stream,
2229
                       AVFormatContext *fmt_ctx)
2230
{
2231
    AVBPrint pbuf;
2232
    char val_str[128];
2233
    const char *s;
2234
    int i;
2235
2236
3024
    av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
2237
2238
3024
    writer_print_section_header(w, SECTION_ID_FRAME);
2239
2240
3024
    s = av_get_media_type_string(stream->codecpar->codec_type);
2241
3024
    if (s) print_str    ("media_type", s);
2242
    else   print_str_opt("media_type", "unknown");
2243
3024
    print_int("stream_index",           stream->index);
2244
3024
    print_int("key_frame",              frame->key_frame);
2245
3024
    print_ts  ("pkt_pts",               frame->pts);
2246
3024
    print_time("pkt_pts_time",          frame->pts, &stream->time_base);
2247
3024
    print_ts  ("pkt_dts",               frame->pkt_dts);
2248
3024
    print_time("pkt_dts_time",          frame->pkt_dts, &stream->time_base);
2249
3024
    print_ts  ("best_effort_timestamp", frame->best_effort_timestamp);
2250
3024
    print_time("best_effort_timestamp_time", frame->best_effort_timestamp, &stream->time_base);
2251
3024
    print_duration_ts  ("pkt_duration",      frame->pkt_duration);
2252
3024
    print_duration_time("pkt_duration_time", frame->pkt_duration, &stream->time_base);
2253
3024
    if (frame->pkt_pos != -1) print_fmt    ("pkt_pos", "%"PRId64, frame->pkt_pos);
2254
302
    else                      print_str_opt("pkt_pos", "N/A");
2255
3024
    if (frame->pkt_size != -1) print_val    ("pkt_size", frame->pkt_size, unit_byte_str);
2256
    else                       print_str_opt("pkt_size", "N/A");
2257
2258
3024
    switch (stream->codecpar->codec_type) {
2259
        AVRational sar;
2260
2261
454
    case AVMEDIA_TYPE_VIDEO:
2262
454
        print_int("width",                  frame->width);
2263
454
        print_int("height",                 frame->height);
2264
454
        s = av_get_pix_fmt_name(frame->format);
2265
454
        if (s) print_str    ("pix_fmt", s);
2266
        else   print_str_opt("pix_fmt", "unknown");
2267
454
        sar = av_guess_sample_aspect_ratio(fmt_ctx, stream, frame);
2268
454
        if (sar.num) {
2269
451
            print_q("sample_aspect_ratio", sar, ':');
2270
        } else {
2271
3
            print_str_opt("sample_aspect_ratio", "N/A");
2272
        }
2273
454
        print_fmt("pict_type",              "%c", av_get_picture_type_char(frame->pict_type));
2274
454
        print_int("coded_picture_number",   frame->coded_picture_number);
2275
454
        print_int("display_picture_number", frame->display_picture_number);
2276
454
        print_int("interlaced_frame",       frame->interlaced_frame);
2277
454
        print_int("top_field_first",        frame->top_field_first);
2278
454
        print_int("repeat_pict",            frame->repeat_pict);
2279
2280
454
        print_color_range(w, frame->color_range);
2281
454
        print_color_space(w, frame->colorspace);
2282
454
        print_primaries(w, frame->color_primaries);
2283
454
        print_color_trc(w, frame->color_trc);
2284
454
        print_chroma_location(w, frame->chroma_location);
2285
454
        break;
2286
2287
2570
    case AVMEDIA_TYPE_AUDIO:
2288
2570
        s = av_get_sample_fmt_name(frame->format);
2289
2570
        if (s) print_str    ("sample_fmt", s);
2290
        else   print_str_opt("sample_fmt", "unknown");
2291
2570
        print_int("nb_samples",         frame->nb_samples);
2292
2570
        print_int("channels", frame->channels);
2293
2570
        if (frame->channel_layout) {
2294
2352
            av_bprint_clear(&pbuf);
2295
2352
            av_bprint_channel_layout(&pbuf, frame->channels,
2296
                                     frame->channel_layout);
2297
2352
            print_str    ("channel_layout", pbuf.str);
2298
        } else
2299
218
            print_str_opt("channel_layout", "unknown");
2300
2570
        break;
2301
    }
2302
3024
    if (do_show_frame_tags)
2303
1043
        show_tags(w, frame->metadata, SECTION_ID_FRAME_TAGS);
2304
3024
    if (do_show_log)
2305
        show_log(w, SECTION_ID_FRAME_LOGS, SECTION_ID_FRAME_LOG, do_show_log);
2306
3024
    if (frame->nb_side_data) {
2307
70
        writer_print_section_header(w, SECTION_ID_FRAME_SIDE_DATA_LIST);
2308
144
        for (i = 0; i < frame->nb_side_data; i++) {
2309
74
            AVFrameSideData *sd = frame->side_data[i];
2310
            const char *name;
2311
2312
74
            writer_print_section_header(w, SECTION_ID_FRAME_SIDE_DATA);
2313
74
            name = av_frame_side_data_name(sd->type);
2314
74
            print_str("side_data_type", name ? name : "unknown");
2315

74
            if (sd->type == AV_FRAME_DATA_DISPLAYMATRIX && sd->size >= 9*4) {
2316
                writer_print_integers(w, "displaymatrix", sd->data, 9, " %11d", 3, 4, 1);
2317
                print_int("rotation", av_display_rotation_get((int32_t *)sd->data));
2318

74
            } else if (sd->type == AV_FRAME_DATA_GOP_TIMECODE && sd->size >= 8) {
2319
                char tcbuf[AV_TIMECODE_STR_SIZE];
2320
                av_timecode_make_mpeg_tc_string(tcbuf, *(int64_t *)(sd->data));
2321
                print_str("timecode", tcbuf);
2322

75
            } else if (sd->type == AV_FRAME_DATA_S12M_TIMECODE && sd->size == 16) {
2323
1
                uint32_t *tc = (uint32_t*)sd->data;
2324
1
                int m = FFMIN(tc[0],3);
2325
1
                writer_print_section_header(w, SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST);
2326
2
                for (int j = 1; j <= m ; j++) {
2327
                    char tcbuf[AV_TIMECODE_STR_SIZE];
2328
1
                    av_timecode_make_smpte_tc_string2(tcbuf, stream->avg_frame_rate, tc[j], 0, 0);
2329
1
                    writer_print_section_header(w, SECTION_ID_FRAME_SIDE_DATA_TIMECODE);
2330
1
                    print_str("value", tcbuf);
2331
1
                    writer_print_section_footer(w);
2332
                }
2333
1
                writer_print_section_footer(w);
2334
73
            } else if (sd->type == AV_FRAME_DATA_MASTERING_DISPLAY_METADATA) {
2335
1
                AVMasteringDisplayMetadata *metadata = (AVMasteringDisplayMetadata *)sd->data;
2336
2337
1
                if (metadata->has_primaries) {
2338
1
                    print_q("red_x", metadata->display_primaries[0][0], '/');
2339
1
                    print_q("red_y", metadata->display_primaries[0][1], '/');
2340
1
                    print_q("green_x", metadata->display_primaries[1][0], '/');
2341
1
                    print_q("green_y", metadata->display_primaries[1][1], '/');
2342
1
                    print_q("blue_x", metadata->display_primaries[2][0], '/');
2343
1
                    print_q("blue_y", metadata->display_primaries[2][1], '/');
2344
2345
1
                    print_q("white_point_x", metadata->white_point[0], '/');
2346
1
                    print_q("white_point_y", metadata->white_point[1], '/');
2347
                }
2348
2349
1
                if (metadata->has_luminance) {
2350
1
                    print_q("min_luminance", metadata->min_luminance, '/');
2351
1
                    print_q("max_luminance", metadata->max_luminance, '/');
2352
                }
2353
72
            } else if (sd->type == AV_FRAME_DATA_DYNAMIC_HDR_PLUS) {
2354
1
                AVDynamicHDRPlus *metadata = (AVDynamicHDRPlus *)sd->data;
2355
1
                print_dynamic_hdr10_plus(w, metadata);
2356
71
            } else if (sd->type == AV_FRAME_DATA_CONTENT_LIGHT_LEVEL) {
2357
1
                AVContentLightMetadata *metadata = (AVContentLightMetadata *)sd->data;
2358
1
                print_int("max_content", metadata->MaxCLL);
2359
1
                print_int("max_average", metadata->MaxFALL);
2360
70
            } else if (sd->type == AV_FRAME_DATA_ICC_PROFILE) {
2361
                AVDictionaryEntry *tag = av_dict_get(sd->metadata, "name", NULL, AV_DICT_MATCH_CASE);
2362
                if (tag)
2363
                    print_str(tag->key, tag->value);
2364
                print_int("size", sd->size);
2365
            }
2366
74
            writer_print_section_footer(w);
2367
        }
2368
70
        writer_print_section_footer(w);
2369
    }
2370
2371
3024
    writer_print_section_footer(w);
2372
2373
3024
    av_bprint_finalize(&pbuf, NULL);
2374
3024
    fflush(stdout);
2375
3024
}
2376
2377
5952
static av_always_inline int process_frame(WriterContext *w,
2378
                                          InputFile *ifile,
2379
                                          AVFrame *frame, AVPacket *pkt,
2380
                                          int *packet_new)
2381
{
2382
5952
    AVFormatContext *fmt_ctx = ifile->fmt_ctx;
2383
5952
    AVCodecContext *dec_ctx = ifile->streams[pkt->stream_index].dec_ctx;
2384
5952
    AVCodecParameters *par = ifile->streams[pkt->stream_index].st->codecpar;
2385
    AVSubtitle sub;
2386
5952
    int ret = 0, got_frame = 0;
2387
2388
5952
    clear_log(1);
2389

5952
    if (dec_ctx && dec_ctx->codec) {
2390
5952
        switch (par->codec_type) {
2391
5952
        case AVMEDIA_TYPE_VIDEO:
2392
        case AVMEDIA_TYPE_AUDIO:
2393
5952
            if (*packet_new) {
2394
2934
                ret = avcodec_send_packet(dec_ctx, pkt);
2395
2934
                if (ret == AVERROR(EAGAIN)) {
2396
                    ret = 0;
2397

2934
                } else if (ret >= 0 || ret == AVERROR_EOF) {
2398
2932
                    ret = 0;
2399
2932
                    *packet_new = 0;
2400
                }
2401
            }
2402
5952
            if (ret >= 0) {
2403
5950
                ret = avcodec_receive_frame(dec_ctx, frame);
2404
5950
                if (ret >= 0) {
2405
3024
                    got_frame = 1;
2406

2926
                } else if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
2407
2926
                    ret = 0;
2408
                }
2409
            }
2410
5952
            break;
2411
2412
        case AVMEDIA_TYPE_SUBTITLE:
2413
            if (*packet_new)
2414
                ret = avcodec_decode_subtitle2(dec_ctx, &sub, &got_frame, pkt);
2415
            *packet_new = 0;
2416
            break;
2417
        default:
2418
            *packet_new = 0;
2419
        }
2420
    } else {
2421
        *packet_new = 0;
2422
    }
2423
2424
5952
    if (ret < 0)
2425
2
        return ret;
2426
5950
    if (got_frame) {
2427
3024
        int is_sub = (par->codec_type == AVMEDIA_TYPE_SUBTITLE);
2428
3024
        nb_streams_frames[pkt->stream_index]++;
2429
3024
        if (do_show_frames)
2430
3024
            if (is_sub)
2431
                show_subtitle(w, &sub, ifile->streams[pkt->stream_index].st, fmt_ctx);
2432
            else
2433
3024
                show_frame(w, frame, ifile->streams[pkt->stream_index].st, fmt_ctx);
2434
3024
        if (is_sub)
2435
            avsubtitle_free(&sub);
2436
    }
2437

5950
    return got_frame || *packet_new;
2438
}
2439
2440
47
static void log_read_interval(const ReadInterval *interval, void *log_ctx, int log_level)
2441
{
2442
47
    av_log(log_ctx, log_level, "id:%d", interval->id);
2443
2444
47
    if (interval->has_start) {
2445
        av_log(log_ctx, log_level, " start:%s%s", interval->start_is_offset ? "+" : "",
2446
               av_ts2timestr(interval->start, &AV_TIME_BASE_Q));
2447
    } else {
2448
47
        av_log(log_ctx, log_level, " start:N/A");
2449
    }
2450
2451
47
    if (interval->has_end) {
2452
        av_log(log_ctx, log_level, " end:%s", interval->end_is_offset ? "+" : "");
2453
        if (interval->duration_frames)
2454
            av_log(log_ctx, log_level, "#%"PRId64, interval->end);
2455
        else
2456
            av_log(log_ctx, log_level, "%s", av_ts2timestr(interval->end, &AV_TIME_BASE_Q));
2457
    } else {
2458
47
        av_log(log_ctx, log_level, " end:N/A");
2459
    }
2460
2461
47
    av_log(log_ctx, log_level, "\n");
2462
47
}
2463
2464
47
static int read_interval_packets(WriterContext *w, InputFile *ifile,
2465
                                 const ReadInterval *interval, int64_t *cur_ts)
2466
{
2467
47
    AVFormatContext *fmt_ctx = ifile->fmt_ctx;
2468
    AVPacket pkt;
2469
47
    AVFrame *frame = NULL;
2470
47
    int ret = 0, i = 0, frame_count = 0;
2471
47
    int64_t start = -INT64_MAX, end = interval->end;
2472

47
    int has_start = 0, has_end = interval->has_end && !interval->end_is_offset;
2473
2474
47
    av_init_packet(&pkt);
2475
2476
47
    av_log(NULL, AV_LOG_VERBOSE, "Processing read interval ");
2477
47
    log_read_interval(interval, NULL, AV_LOG_VERBOSE);
2478
2479
47
    if (interval->has_start) {
2480
        int64_t target;
2481
        if (interval->start_is_offset) {
2482
            if (*cur_ts == AV_NOPTS_VALUE) {
2483
                av_log(NULL, AV_LOG_ERROR,
2484
                       "Could not seek to relative position since current "
2485
                       "timestamp is not defined\n");
2486
                ret = AVERROR(EINVAL);
2487
                goto end;
2488
            }
2489
            target = *cur_ts + interval->start;
2490
        } else {
2491
            target = interval->start;
2492
        }
2493
2494
        av_log(NULL, AV_LOG_VERBOSE, "Seeking to read interval start point %s\n",
2495
               av_ts2timestr(target, &AV_TIME_BASE_Q));
2496
        if ((ret = avformat_seek_file(fmt_ctx, -1, -INT64_MAX, target, INT64_MAX, 0)) < 0) {
2497
            av_log(NULL, AV_LOG_ERROR, "Could not seek to position %"PRId64": %s\n",
2498
                   interval->start, av_err2str(ret));
2499
            goto end;
2500
        }
2501
    }
2502
2503
47
    frame = av_frame_alloc();
2504
47
    if (!frame) {
2505
        ret = AVERROR(ENOMEM);
2506
        goto end;
2507
    }
2508
6335
    while (!av_read_frame(fmt_ctx, &pkt)) {
2509
6288
        if (fmt_ctx->nb_streams > nb_streams) {
2510
            REALLOCZ_ARRAY_STREAM(nb_streams_frames,  nb_streams, fmt_ctx->nb_streams);
2511
            REALLOCZ_ARRAY_STREAM(nb_streams_packets, nb_streams, fmt_ctx->nb_streams);
2512
            REALLOCZ_ARRAY_STREAM(selected_streams,   nb_streams, fmt_ctx->nb_streams);
2513
            nb_streams = fmt_ctx->nb_streams;
2514
        }
2515
6288
        if (selected_streams[pkt.stream_index]) {
2516
6285
            AVRational tb = ifile->streams[pkt.stream_index].st->time_base;
2517
2518
6285
            if (pkt.pts != AV_NOPTS_VALUE)
2519
6272
                *cur_ts = av_rescale_q(pkt.pts, tb, AV_TIME_BASE_Q);
2520
2521

6285
            if (!has_start && *cur_ts != AV_NOPTS_VALUE) {
2522
44
                start = *cur_ts;
2523
44
                has_start = 1;
2524
            }
2525
2526

6285
            if (has_start && !has_end && interval->end_is_offset) {
2527
                end = start + interval->end;
2528
                has_end = 1;
2529
            }
2530
2531

6285
            if (interval->end_is_offset && interval->duration_frames) {
2532
                if (frame_count >= interval->end)
2533
                    break;
2534

6285
            } else if (has_end && *cur_ts != AV_NOPTS_VALUE && *cur_ts >= end) {
2535
                break;
2536
            }
2537
2538
6285
            frame_count++;
2539
6285
            if (do_read_packets) {
2540
3588
                if (do_show_packets)
2541
3588
                    show_packet(w, ifile, &pkt, i++);
2542
3588
                nb_streams_packets[pkt.stream_index]++;
2543
            }
2544
6285
            if (do_read_frames) {
2545
2878
                int packet_new = 1;
2546
5896
                while (process_frame(w, ifile, frame, &pkt, &packet_new) > 0);
2547
            }
2548
        }
2549
6288
        av_packet_unref(&pkt);
2550
    }
2551
47
    av_packet_unref(&pkt);
2552
    //Flush remaining frames that are cached in the decoder
2553
117
    for (i = 0; i < fmt_ctx->nb_streams; i++) {
2554
70
        pkt.stream_index = i;
2555
70
        if (do_read_frames)
2556
56
            while (process_frame(w, ifile, frame, &pkt, &(int){1}) > 0);
2557
    }
2558
2559
47
end:
2560
47
    av_frame_free(&frame);
2561
47
    if (ret < 0) {
2562
        av_log(NULL, AV_LOG_ERROR, "Could not read packets in interval ");
2563
        log_read_interval(interval, NULL, AV_LOG_ERROR);
2564
    }
2565
47
    return ret;
2566
}
2567
2568
47
static int read_packets(WriterContext *w, InputFile *ifile)
2569
{
2570
47
    AVFormatContext *fmt_ctx = ifile->fmt_ctx;
2571
47
    int i, ret = 0;
2572
47
    int64_t cur_ts = fmt_ctx->start_time;
2573
2574
47
    if (read_intervals_nb == 0) {
2575
47
        ReadInterval interval = (ReadInterval) { .has_start = 0, .has_end = 0 };
2576
47
        ret = read_interval_packets(w, ifile, &interval, &cur_ts);
2577
    } else {
2578
        for (i = 0; i < read_intervals_nb; i++) {
2579
            ret = read_interval_packets(w, ifile, &read_intervals[i], &cur_ts);
2580
            if (ret < 0)
2581
                break;
2582
        }
2583
    }
2584
2585
47
    return ret;
2586
}
2587
2588
86
static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_idx, InputStream *ist, int in_program)
2589
{
2590
86
    AVStream *stream = ist->st;
2591
    AVCodecParameters *par;
2592
    AVCodecContext *dec_ctx;
2593
    char val_str[128];
2594
    const char *s;
2595
    AVRational sar, dar;
2596
    AVBPrint pbuf;
2597
    const AVCodecDescriptor *cd;
2598
86
    int ret = 0;
2599
86
    const char *profile = NULL;
2600
2601
86
    av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
2602
2603
86
    writer_print_section_header(w, in_program ? SECTION_ID_PROGRAM_STREAM : SECTION_ID_STREAM);
2604
2605
86
    print_int("index", stream->index);
2606
2607
86
    par     = stream->codecpar;
2608
86
    dec_ctx = ist->dec_ctx;
2609
86
    if (cd = avcodec_descriptor_get(par->codec_id)) {
2610
83
        print_str("codec_name", cd->name);
2611
83
        if (!do_bitexact) {
2612
9
            print_str("codec_long_name",
2613
                      cd->long_name ? cd->long_name : "unknown");
2614
        }
2615
    } else {
2616
3
        print_str_opt("codec_name", "unknown");
2617
3
        if (!do_bitexact) {
2618
            print_str_opt("codec_long_name", "unknown");
2619
        }
2620
    }
2621
2622

86
    if (!do_bitexact && (profile = avcodec_profile_name(par->codec_id, par->profile)))
2623
7
        print_str("profile", profile);
2624
    else {
2625
79
        if (par->profile != FF_PROFILE_UNKNOWN) {
2626
            char profile_num[12];
2627
28
            snprintf(profile_num, sizeof(profile_num), "%d", par->profile);
2628
28
            print_str("profile", profile_num);
2629
        } else
2630
51
            print_str_opt("profile", "unknown");
2631
    }
2632
2633
86
    s = av_get_media_type_string(par->codec_type);
2634
86
    if (s) print_str    ("codec_type", s);
2635
    else   print_str_opt("codec_type", "unknown");
2636
#if FF_API_LAVF_AVCTX
2637
86
    if (dec_ctx)
2638
80
        print_q("codec_time_base", dec_ctx->time_base, '/');
2639
#endif
2640
2641
    /* print AVI/FourCC tag */
2642
86
    print_str("codec_tag_string",    av_fourcc2str(par->codec_tag));
2643
86
    print_fmt("codec_tag", "0x%04"PRIx32, par->codec_tag);
2644
2645

86
    switch (par->codec_type) {
2646
40
    case AVMEDIA_TYPE_VIDEO:
2647
40
        print_int("width",        par->width);
2648
40
        print_int("height",       par->height);
2649
#if FF_API_LAVF_AVCTX
2650
40
        if (dec_ctx) {
2651
40
            print_int("coded_width",  dec_ctx->coded_width);
2652
40
            print_int("coded_height", dec_ctx->coded_height);
2653
40
            print_int("closed_captions", !!(dec_ctx->properties & FF_CODEC_PROPERTY_CLOSED_CAPTIONS));
2654
        }
2655
#endif
2656
40
        print_int("has_b_frames", par->video_delay);
2657
40
        sar = av_guess_sample_aspect_ratio(fmt_ctx, stream, NULL);
2658
40
        if (sar.num) {
2659
35
            print_q("sample_aspect_ratio", sar, ':');
2660
35
            av_reduce(&dar.num, &dar.den,
2661
35
                      par->width  * sar.num,
2662
35
                      par->height * sar.den,
2663
                      1024*1024);
2664
35
            print_q("display_aspect_ratio", dar, ':');
2665
        } else {
2666
5
            print_str_opt("sample_aspect_ratio", "N/A");
2667
5
            print_str_opt("display_aspect_ratio", "N/A");
2668
        }
2669
40
        s = av_get_pix_fmt_name(par->format);
2670
40
        if (s) print_str    ("pix_fmt", s);
2671
2
        else   print_str_opt("pix_fmt", "unknown");
2672
40
        print_int("level",   par->level);
2673
2674
40
        print_color_range(w, par->color_range);
2675
40
        print_color_space(w, par->color_space);
2676
40
        print_color_trc(w, par->color_trc);
2677
40
        print_primaries(w, par->color_primaries);
2678
40
        print_chroma_location(w, par->chroma_location);
2679
2680
40
        if (par->field_order == AV_FIELD_PROGRESSIVE)
2681
6
            print_str("field_order", "progressive");
2682
34
        else if (par->field_order == AV_FIELD_TT)
2683
3
            print_str("field_order", "tt");
2684
31
        else if (par->field_order == AV_FIELD_BB)
2685
1
            print_str("field_order", "bb");
2686
30
        else if (par->field_order == AV_FIELD_TB)
2687
2
            print_str("field_order", "tb");
2688
28
        else if (par->field_order == AV_FIELD_BT)
2689
            print_str("field_order", "bt");
2690
        else
2691
28
            print_str_opt("field_order", "unknown");
2692
2693
#if FF_API_PRIVATE_OPT
2694

40
        if (dec_ctx && dec_ctx->timecode_frame_start >= 0) {
2695
            char tcbuf[AV_TIMECODE_STR_SIZE];
2696
            av_timecode_make_mpeg_tc_string(tcbuf, dec_ctx->timecode_frame_start);
2697
            print_str("timecode", tcbuf);
2698
        } else {
2699
40
            print_str_opt("timecode", "N/A");
2700
        }
2701
#endif
2702
40
        if (dec_ctx)
2703
40
            print_int("refs", dec_ctx->refs);
2704
40
        break;
2705
2706
40
    case AVMEDIA_TYPE_AUDIO:
2707
40
        s = av_get_sample_fmt_name(par->format);
2708
40
        if (s) print_str    ("sample_fmt", s);
2709
        else   print_str_opt("sample_fmt", "unknown");
2710
40
        print_val("sample_rate",     par->sample_rate, unit_hertz_str);
2711
40
        print_int("channels",        par->channels);
2712
2713
40
        if (par->channel_layout) {
2714
23
            av_bprint_clear(&pbuf);
2715
23
            av_bprint_channel_layout(&pbuf, par->channels, par->channel_layout);
2716
23
            print_str    ("channel_layout", pbuf.str);
2717
        } else {
2718
17
            print_str_opt("channel_layout", "unknown");
2719
        }
2720
2721
40
        print_int("bits_per_sample", av_get_bits_per_sample(par->codec_id));
2722
40
        break;
2723
2724
    case AVMEDIA_TYPE_SUBTITLE:
2725
        if (par->width)
2726
            print_int("width",       par->width);
2727
        else
2728
            print_str_opt("width",   "N/A");
2729
        if (par->height)
2730
            print_int("height",      par->height);
2731
        else
2732
            print_str_opt("height",  "N/A");
2733
        break;
2734
    }
2735
2736


86
    if (dec_ctx && dec_ctx->codec && dec_ctx->codec->priv_class && show_private_data) {
2737
46
        const AVOption *opt = NULL;
2738
225
        while (opt = av_opt_next(dec_ctx->priv_data,opt)) {
2739
            uint8_t *str;
2740
179
            if (opt->flags) continue;
2741
51
            if (av_opt_get(dec_ctx->priv_data, opt->name, 0, &str) >= 0) {
2742
51
                print_str(opt->name, str);
2743
51
                av_free(str);
2744
            }
2745
        }
2746
    }
2747
2748
86
    if (fmt_ctx->iformat->flags & AVFMT_SHOW_IDS) print_fmt    ("id", "0x%x", stream->id);
2749
69
    else                                          print_str_opt("id", "N/A");
2750
86
    print_q("r_frame_rate",   stream->r_frame_rate,   '/');
2751
86
    print_q("avg_frame_rate", stream->avg_frame_rate, '/');
2752
86
    print_q("time_base",      stream->time_base,      '/');
2753
86
    print_ts  ("start_pts",   stream->start_time);
2754
86
    print_time("start_time",  stream->start_time, &stream->time_base);
2755
86
    print_ts  ("duration_ts", stream->duration);
2756
86
    print_time("duration",    stream->duration, &stream->time_base);
2757
86
    if (par->bit_rate > 0)     print_val    ("bit_rate", par->bit_rate, unit_bit_per_second_str);
2758
37
    else                       print_str_opt("bit_rate", "N/A");
2759
#if FF_API_LAVF_AVCTX
2760
86
    if (stream->codec->rc_max_rate > 0) print_val ("max_bit_rate", stream->codec->rc_max_rate, unit_bit_per_second_str);
2761
74
    else                                print_str_opt("max_bit_rate", "N/A");
2762
#endif
2763

86
    if (dec_ctx && dec_ctx->bits_per_raw_sample > 0) print_fmt("bits_per_raw_sample", "%d", dec_ctx->bits_per_raw_sample);
2764
73
    else                                             print_str_opt("bits_per_raw_sample", "N/A");
2765
86
    if (stream->nb_frames) print_fmt    ("nb_frames", "%"PRId64, stream->nb_frames);
2766
63
    else                   print_str_opt("nb_frames", "N/A");
2767
86
    if (nb_streams_frames[stream_idx])  print_fmt    ("nb_read_frames", "%"PRIu64, nb_streams_frames[stream_idx]);
2768
59
    else                                print_str_opt("nb_read_frames", "N/A");
2769
86
    if (nb_streams_packets[stream_idx]) print_fmt    ("nb_read_packets", "%"PRIu64, nb_streams_packets[stream_idx]);
2770
48
    else                                print_str_opt("nb_read_packets", "N/A");
2771
86
    if (do_show_data)
2772
        writer_print_data(w, "extradata", par->extradata,
2773
                                          par->extradata_size);
2774
86
    writer_print_data_hash(w, "extradata_hash", par->extradata,
2775
                                                par->extradata_size);
2776
2777
    /* Print disposition information */
2778
#define PRINT_DISPOSITION(flagname, name) do {                                \
2779
        print_int(name, !!(stream->disposition & AV_DISPOSITION_##flagname)); \
2780
    } while (0)
2781
2782
86
    if (do_show_stream_disposition) {
2783
46
        writer_print_section_header(w, in_program ? SECTION_ID_PROGRAM_STREAM_DISPOSITION : SECTION_ID_STREAM_DISPOSITION);
2784
46
        PRINT_DISPOSITION(DEFAULT,          "default");
2785
46
        PRINT_DISPOSITION(DUB,              "dub");
2786
46
        PRINT_DISPOSITION(ORIGINAL,         "original");
2787
46
        PRINT_DISPOSITION(COMMENT,          "comment");
2788
46
        PRINT_DISPOSITION(LYRICS,           "lyrics");
2789
46
        PRINT_DISPOSITION(KARAOKE,          "karaoke");
2790
46
        PRINT_DISPOSITION(FORCED,           "forced");
2791
46
        PRINT_DISPOSITION(HEARING_IMPAIRED, "hearing_impaired");
2792
46
        PRINT_DISPOSITION(VISUAL_IMPAIRED,  "visual_impaired");
2793
46
        PRINT_DISPOSITION(CLEAN_EFFECTS,    "clean_effects");
2794
46
        PRINT_DISPOSITION(ATTACHED_PIC,     "attached_pic");
2795
46
        PRINT_DISPOSITION(TIMED_THUMBNAILS, "timed_thumbnails");
2796
46
        writer_print_section_footer(w);
2797
    }
2798
2799
86
    if (do_show_stream_tags)
2800
46
        ret = show_tags(w, stream->metadata, in_program ? SECTION_ID_PROGRAM_STREAM_TAGS : SECTION_ID_STREAM_TAGS);
2801
2802
86
    if (stream->nb_side_data) {
2803
7
        print_pkt_side_data(w, stream->codecpar, stream->side_data, stream->nb_side_data,
2804
                            SECTION_ID_STREAM_SIDE_DATA_LIST,
2805
                            SECTION_ID_STREAM_SIDE_DATA);
2806
    }
2807
2808
86
    writer_print_section_footer(w);
2809
86
    av_bprint_finalize(&pbuf, NULL);
2810
86
    fflush(stdout);
2811
2812
86
    return ret;
2813
}
2814
2815
45
static int show_streams(WriterContext *w, InputFile *ifile)
2816
{
2817
45
    AVFormatContext *fmt_ctx = ifile->fmt_ctx;
2818
45
    int i, ret = 0;
2819
2820
45
    writer_print_section_header(w, SECTION_ID_STREAMS);
2821
130
    for (i = 0; i < ifile->nb_streams; i++)
2822
85
        if (selected_streams[i]) {
2823
78
            ret = show_stream(w, fmt_ctx, i, &ifile->streams[i], 0);
2824
78
            if (ret < 0)
2825
                break;
2826
        }
2827
45
    writer_print_section_footer(w);
2828
2829
45
    return ret;
2830
}
2831
2832
3
static int show_program(WriterContext *w, InputFile *ifile, AVProgram *program)
2833
{
2834
3
    AVFormatContext *fmt_ctx = ifile->fmt_ctx;
2835
3
    int i, ret = 0;
2836
2837
3
    writer_print_section_header(w, SECTION_ID_PROGRAM);
2838
3
    print_int("program_id", program->id);
2839
3
    print_int("program_num", program->program_num);
2840
3
    print_int("nb_streams", program->nb_stream_indexes);
2841
3
    print_int("pmt_pid", program->pmt_pid);
2842
3
    print_int("pcr_pid", program->pcr_pid);
2843
3
    print_ts("start_pts", program->start_time);
2844
3
    print_time("start_time", program->start_time, &AV_TIME_BASE_Q);
2845
3
    print_ts("end_pts", program->end_time);
2846
3
    print_time("end_time", program->end_time, &AV_TIME_BASE_Q);
2847
3
    if (do_show_program_tags)
2848
        ret = show_tags(w, program->metadata, SECTION_ID_PROGRAM_TAGS);
2849
3
    if (ret < 0)
2850
        goto end;
2851
2852
3
    writer_print_section_header(w, SECTION_ID_PROGRAM_STREAMS);
2853
12
    for (i = 0; i < program->nb_stream_indexes; i++) {
2854
9
        if (selected_streams[program->stream_index[i]]) {
2855
8
            ret = show_stream(w, fmt_ctx, program->stream_index[i], &ifile->streams[program->stream_index[i]], 1);
2856
8
            if (ret < 0)
2857
                break;
2858
        }
2859
    }
2860
3
    writer_print_section_footer(w);
2861
2862
3
end:
2863
3
    writer_print_section_footer(w);
2864
3
    return ret;
2865
}
2866
2867
28
static int show_programs(WriterContext *w, InputFile *ifile)
2868
{
2869
28
    AVFormatContext *fmt_ctx = ifile->fmt_ctx;
2870
28
    int i, ret = 0;
2871
2872
28
    writer_print_section_header(w, SECTION_ID_PROGRAMS);
2873
31
    for (i = 0; i < fmt_ctx->nb_programs; i++) {
2874
3
        AVProgram *program = fmt_ctx->programs[i];
2875
3
        if (!program)
2876
            continue;
2877
3
        ret = show_program(w, ifile, program);
2878
3
        if (ret < 0)
2879
            break;
2880
    }
2881
28
    writer_print_section_footer(w);
2882
28
    return ret;
2883
}
2884
2885
3
static int show_chapters(WriterContext *w, InputFile *ifile)
2886
{
2887
3
    AVFormatContext *fmt_ctx = ifile->fmt_ctx;
2888
3
    int i, ret = 0;
2889
2890
3
    writer_print_section_header(w, SECTION_ID_CHAPTERS);
2891
16
    for (i = 0; i < fmt_ctx->nb_chapters; i++) {
2892
13
        AVChapter *chapter = fmt_ctx->chapters[i];
2893
2894
13
        writer_print_section_header(w, SECTION_ID_CHAPTER);
2895
13
        print_int("id", chapter->id);
2896
13
        print_q  ("time_base", chapter->time_base, '/');
2897
13
        print_int("start", chapter->start);
2898
13
        print_time("start_time", chapter->start, &chapter->time_base);
2899
13
        print_int("end", chapter->end);
2900
13
        print_time("end_time", chapter->end, &chapter->time_base);
2901
13
        if (do_show_chapter_tags)
2902
13
            ret = show_tags(w, chapter->metadata, SECTION_ID_CHAPTER_TAGS);
2903
13
        writer_print_section_footer(w);
2904
    }
2905
3
    writer_print_section_footer(w);
2906
2907
3
    return ret;
2908
}
2909
2910
20
static int show_format(WriterContext *w, InputFile *ifile)
2911
{
2912
20
    AVFormatContext *fmt_ctx = ifile->fmt_ctx;
2913
    char val_str[128];
2914
20
    int64_t size = fmt_ctx->pb ? avio_size(fmt_ctx->pb) : -1;
2915
20
    int ret = 0;
2916
2917
20
    writer_print_section_header(w, SECTION_ID_FORMAT);
2918
20
    print_str_validate("filename", fmt_ctx->url);
2919
20
    print_int("nb_streams",       fmt_ctx->nb_streams);
2920
20
    print_int("nb_programs",      fmt_ctx->nb_programs);
2921
20
    print_str("format_name",      fmt_ctx->iformat->name);
2922
20
    if (!do_bitexact) {
2923
5
        if (fmt_ctx->iformat->long_name) print_str    ("format_long_name", fmt_ctx->iformat->long_name);
2924
        else                             print_str_opt("format_long_name", "unknown");
2925
    }
2926
20
    print_time("start_time",      fmt_ctx->start_time, &AV_TIME_BASE_Q);
2927
20
    print_time("duration",        fmt_ctx->duration,   &AV_TIME_BASE_Q);
2928
20
    if (size >= 0) print_val    ("size", size, unit_byte_str);
2929
    else           print_str_opt("size", "N/A");
2930
20
    if (fmt_ctx->bit_rate > 0) print_val    ("bit_rate", fmt_ctx->bit_rate, unit_bit_per_second_str);
2931
    else                       print_str_opt("bit_rate", "N/A");
2932
20
    print_int("probe_score", fmt_ctx->probe_score);
2933
20
    if (do_show_format_tags)
2934
12
        ret = show_tags(w, fmt_ctx->metadata, SECTION_ID_FORMAT_TAGS);
2935
2936
20
    writer_print_section_footer(w);
2937
20
    fflush(stdout);
2938
20
    return ret;
2939
}
2940
2941
static void show_error(WriterContext *w, int err)
2942
{
2943
    char errbuf[128];
2944
    const char *errbuf_ptr = errbuf;
2945
2946
    if (av_strerror(err, errbuf, sizeof(errbuf)) < 0)
2947
        errbuf_ptr = strerror(AVUNERROR(err));
2948
2949
    writer_print_section_header(w, SECTION_ID_ERROR);
2950
    print_int("code", err);
2951
    print_str("string", errbuf_ptr);
2952
    writer_print_section_footer(w);
2953
}
2954
2955
76
static int open_input_file(InputFile *ifile, const char *filename,
2956
                           const char *print_filename)
2957
{
2958
    int err, i;
2959
76
    AVFormatContext *fmt_ctx = NULL;
2960
76
    AVDictionaryEntry *t = NULL;
2961
76
    int scan_all_pmts_set = 0;
2962
2963
76
    fmt_ctx = avformat_alloc_context();
2964
76
    if (!fmt_ctx) {
2965
        print_error(filename, AVERROR(ENOMEM));
2966
        exit_program(1);
2967
    }
2968
2969
76
    if (!av_dict_get(format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE)) {
2970
76
        av_dict_set(&format_opts, "scan_all_pmts", "1", AV_DICT_DONT_OVERWRITE);
2971
76
        scan_all_pmts_set = 1;
2972
    }
2973
76
    if ((err = avformat_open_input(&fmt_ctx, filename,
2974
                                   iformat, &format_opts)) < 0) {
2975
        print_error(filename, err);
2976
        return err;
2977
    }
2978
76
    if (print_filename) {
2979
7
        av_freep(&fmt_ctx->url);
2980
7
        fmt_ctx->url = av_strdup(print_filename);
2981
    }
2982
76
    ifile->fmt_ctx = fmt_ctx;
2983
76
    if (scan_all_pmts_set)
2984
76
        av_dict_set(&format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE);
2985
76
    while ((t = av_dict_get(format_opts, "", t, AV_DICT_IGNORE_SUFFIX)))
2986
        av_log(NULL, AV_LOG_WARNING, "Option %s skipped - not known to demuxer.\n", t->key);
2987
2988
76
    if (find_stream_info) {
2989
76
        AVDictionary **opts = setup_find_stream_info_opts(fmt_ctx, codec_opts);
2990
76
        int orig_nb_streams = fmt_ctx->nb_streams;
2991
2992
76
        err = avformat_find_stream_info(fmt_ctx, opts);
2993
2994
190
        for (i = 0; i < orig_nb_streams; i++)
2995
114
            av_dict_free(&opts[i]);
2996
76
        av_freep(&opts);
2997
2998
76
        if (err < 0) {
2999
            print_error(filename, err);
3000
            return err;
3001
        }
3002
    }
3003
3004
76
    av_dump_format(fmt_ctx, 0, filename, 0);
3005
3006
76
    ifile->streams = av_mallocz_array(fmt_ctx->nb_streams,
3007
                                      sizeof(*ifile->streams));
3008
76
    if (!ifile->streams)
3009
        exit(1);
3010
76
    ifile->nb_streams = fmt_ctx->nb_streams;
3011
3012
    /* bind a decoder to each input stream */
3013
197
    for (i = 0; i < fmt_ctx->nb_streams; i++) {
3014
121
        InputStream *ist = &ifile->streams[i];
3015
121
        AVStream *stream = fmt_ctx->streams[i];
3016
        AVCodec *codec;
3017
3018
121
        ist->st = stream;
3019
3020
121
        if (stream->codecpar->codec_id == AV_CODEC_ID_PROBE) {
3021
            av_log(NULL, AV_LOG_WARNING,
3022
                   "Failed to probe codec for input stream %d\n",
3023
                    stream->index);
3024
            continue;
3025
        }
3026
3027
121
        codec = avcodec_find_decoder(stream->codecpar->codec_id);
3028
121
        if (!codec) {
3029
7
            av_log(NULL, AV_LOG_WARNING,
3030
                    "Unsupported codec with id %d for input stream %d\n",
3031
7
                    stream->codecpar->codec_id, stream->index);
3032
7
            continue;
3033
        }
3034
        {
3035
114
            AVDictionary *opts = filter_codec_opts(codec_opts, stream->codecpar->codec_id,
3036
                                                   fmt_ctx, stream, codec);
3037
3038
114
            ist->dec_ctx = avcodec_alloc_context3(codec);
3039
114
            if (!ist->dec_ctx)
3040
                exit(1);
3041
3042
114
            err = avcodec_parameters_to_context(ist->dec_ctx, stream->codecpar);
3043
114
            if (err < 0)
3044
                exit(1);
3045
3046
114
            if (do_show_log) {
3047
                // For loging it is needed to disable at least frame threads as otherwise
3048
                // the log information would need to be reordered and matches up to contexts and frames
3049
                // That is in fact possible but not trivial
3050
                av_dict_set(&codec_opts, "threads", "1", 0);
3051
            }
3052
3053
114
            ist->dec_ctx->pkt_timebase = stream->time_base;
3054
114
            ist->dec_ctx->framerate = stream->avg_frame_rate;
3055
#if FF_API_LAVF_AVCTX
3056
114
            ist->dec_ctx->properties = stream->codec->properties;
3057
114
            ist->dec_ctx->coded_width = stream->codec->coded_width;
3058
114
            ist->dec_ctx->coded_height = stream->codec->coded_height;
3059
#endif
3060
3061
114
            if (avcodec_open2(ist->dec_ctx, codec, &opts) < 0) {
3062
                av_log(NULL, AV_LOG_WARNING, "Could not open codec for input stream %d\n",
3063
                       stream->index);
3064
                exit(1);
3065
            }
3066
3067
114
            if ((t = av_dict_get(opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
3068
                av_log(NULL, AV_LOG_ERROR, "Option %s for input stream %d not found\n",
3069
                       t->key, stream->index);
3070
                return AVERROR_OPTION_NOT_FOUND;
3071
            }
3072
        }
3073
    }
3074
3075
76
    ifile->fmt_ctx = fmt_ctx;
3076
76
    return 0;
3077
}
3078
3079
76
static void close_input_file(InputFile *ifile)
3080
{
3081
    int i;
3082
3083
    /* close decoder for each stream */
3084
197
    for (i = 0; i < ifile->nb_streams; i++)
3085
121
        if (ifile->streams[i].st->codecpar->codec_id != AV_CODEC_ID_NONE)
3086
117
            avcodec_free_context(&ifile->streams[i].dec_ctx);
3087
3088
76
    av_freep(&ifile->streams);
3089
76
    ifile->nb_streams = 0;
3090
3091
76
    avformat_close_input(&ifile->fmt_ctx);
3092
76
}
3093
3094
76
static int probe_file(WriterContext *wctx, const char *filename,
3095
                      const char *print_filename)
3096
{
3097
76
    InputFile ifile = { 0 };
3098
    int ret, i;
3099
    int section_id;
3100
3101

76
    do_read_frames = do_show_frames || do_count_frames;
3102

76
    do_read_packets = do_show_packets || do_count_packets;
3103
3104
76
    ret = open_input_file(&ifile, filename, print_filename);
3105
76
    if (ret < 0)
3106
        goto end;
3107
3108
#define CHECK_END if (ret < 0) goto end
3109
3110
76
    nb_streams = ifile.fmt_ctx->nb_streams;
3111
76
    REALLOCZ_ARRAY_STREAM(nb_streams_frames,0,ifile.fmt_ctx->nb_streams);
3112
76
    REALLOCZ_ARRAY_STREAM(nb_streams_packets,0,ifile.fmt_ctx->nb_streams);
3113
76
    REALLOCZ_ARRAY_STREAM(selected_streams,0,ifile.fmt_ctx->nb_streams);
3114
3115
197
    for (i = 0; i < ifile.fmt_ctx->nb_streams; i++) {
3116
121
        if (stream_specifier) {
3117
31
            ret = avformat_match_stream_specifier(ifile.fmt_ctx,
3118
31
                                                  ifile.fmt_ctx->streams[i],
3119
                                                  stream_specifier);
3120
31
            CHECK_END;
3121
            else
3122
31
                selected_streams[i] = ret;
3123
31
            ret = 0;
3124
        } else {
3125
90
            selected_streams[i] = 1;
3126
        }
3127
121
        if (!selected_streams[i])
3128
8
            ifile.fmt_ctx->streams[i]->discard = AVDISCARD_ALL;
3129
    }
3130
3131

76
    if (do_read_frames || do_read_packets) {
3132

47
        if (do_show_frames && do_show_packets &&
3133
9
            wctx->writer->flags & WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER)
3134
4
            section_id = SECTION_ID_PACKETS_AND_FRAMES;
3135

43
        else if (do_show_packets && !do_show_frames)
3136
13
            section_id = SECTION_ID_PACKETS;
3137
        else // (!do_show_packets && do_show_frames)
3138
30
            section_id = SECTION_ID_FRAMES;
3139

47
        if (do_show_frames || do_show_packets)
3140
47
            writer_print_section_header(wctx, section_id);
3141
47
        ret = read_packets(wctx, &ifile);
3142

47
        if (do_show_frames || do_show_packets)
3143
47
            writer_print_section_footer(wctx);
3144
47
        CHECK_END;
3145
    }
3146
3147
76
    if (do_show_programs) {
3148
28
        ret = show_programs(wctx, &ifile);
3149
28
        CHECK_END;
3150
    }
3151
3152
76
    if (do_show_streams) {
3153
45
        ret = show_streams(wctx, &ifile);
3154
45
        CHECK_END;
3155
    }
3156
76
    if (do_show_chapters) {
3157
3
        ret = show_chapters(wctx, &ifile);
3158
3
        CHECK_END;
3159
    }
3160
76
    if (do_show_format) {
3161
20
        ret = show_format(wctx, &ifile);
3162
20
        CHECK_END;
3163
    }
3164
3165
76
end:
3166
76
    if (ifile.fmt_ctx)
3167
76
        close_input_file(&ifile);
3168
76
    av_freep(&nb_streams_frames);
3169
76
    av_freep(&nb_streams_packets);
3170
76
    av_freep(&selected_streams);
3171
3172
76
    return ret;
3173
}
3174
3175
static void show_usage(void)
3176
{
3177
    av_log(NULL, AV_LOG_INFO, "Simple multimedia streams analyzer\n");
3178
    av_log(NULL, AV_LOG_INFO, "usage: %s [OPTIONS] [INPUT_FILE]\n", program_name);
3179
    av_log(NULL, AV_LOG_INFO, "\n");
3180
}
3181
3182
static void ffprobe_show_program_version(WriterContext *w)
3183
{
3184
    AVBPrint pbuf;
3185
    av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
3186
3187
    writer_print_section_header(w, SECTION_ID_PROGRAM_VERSION);
3188
    print_str("version", FFMPEG_VERSION);
3189
    print_fmt("copyright", "Copyright (c) %d-%d the FFmpeg developers",
3190
              program_birth_year, CONFIG_THIS_YEAR);
3191
    print_str("compiler_ident", CC_IDENT);
3192
    print_str("configuration", FFMPEG_CONFIGURATION);
3193
    writer_print_section_footer(w);
3194
3195
    av_bprint_finalize(&pbuf, NULL);
3196
}
3197
3198
#define SHOW_LIB_VERSION(libname, LIBNAME)                              \
3199
    do {                                                                \
3200
        if (CONFIG_##LIBNAME) {                                         \
3201
            unsigned int version = libname##_version();                 \
3202
            writer_print_section_header(w, SECTION_ID_LIBRARY_VERSION); \
3203
            print_str("name",    "lib" #libname);                       \
3204
            print_int("major",   LIB##LIBNAME##_VERSION_MAJOR);         \
3205
            print_int("minor",   LIB##LIBNAME##_VERSION_MINOR);         \
3206
            print_int("micro",   LIB##LIBNAME##_VERSION_MICRO);         \
3207
            print_int("version", version);                              \
3208
            print_str("ident",   LIB##LIBNAME##_IDENT);                 \
3209
            writer_print_section_footer(w);                             \
3210
        }                                                               \
3211
    } while (0)
3212
3213
static void ffprobe_show_library_versions(WriterContext *w)
3214
{
3215
    writer_print_section_header(w, SECTION_ID_LIBRARY_VERSIONS);
3216
    SHOW_LIB_VERSION(avutil,     AVUTIL);
3217
    SHOW_LIB_VERSION(avcodec,    AVCODEC);
3218
    SHOW_LIB_VERSION(avformat,   AVFORMAT);
3219
    SHOW_LIB_VERSION(avdevice,   AVDEVICE);
3220
    SHOW_LIB_VERSION(avfilter,   AVFILTER);
3221
    SHOW_LIB_VERSION(swscale,    SWSCALE);
3222
    SHOW_LIB_VERSION(swresample, SWRESAMPLE);
3223
    SHOW_LIB_VERSION(postproc,   POSTPROC);
3224
    writer_print_section_footer(w);
3225
}
3226
3227
#define PRINT_PIX_FMT_FLAG(flagname, name)                                \
3228
    do {                                                                  \
3229
        print_int(name, !!(pixdesc->flags & AV_PIX_FMT_FLAG_##flagname)); \
3230
    } while (0)
3231
3232
static void ffprobe_show_pixel_formats(WriterContext *w)
3233
{
3234
    const AVPixFmtDescriptor *pixdesc = NULL;
3235
    int i, n;
3236
3237
    writer_print_section_header(w, SECTION_ID_PIXEL_FORMATS);
3238
    while (pixdesc = av_pix_fmt_desc_next(pixdesc)) {
3239
        writer_print_section_header(w, SECTION_ID_PIXEL_FORMAT);
3240
        print_str("name", pixdesc->name);
3241
        print_int("nb_components", pixdesc->nb_components);
3242
        if ((pixdesc->nb_components >= 3) && !(pixdesc->flags & AV_PIX_FMT_FLAG_RGB)) {
3243
            print_int    ("log2_chroma_w", pixdesc->log2_chroma_w);
3244
            print_int    ("log2_chroma_h", pixdesc->log2_chroma_h);
3245
        } else {
3246
            print_str_opt("log2_chroma_w", "N/A");
3247
            print_str_opt("log2_chroma_h", "N/A");
3248
        }
3249
        n = av_get_bits_per_pixel(pixdesc);
3250
        if (n) print_int    ("bits_per_pixel", n);
3251
        else   print_str_opt("bits_per_pixel", "N/A");
3252
        if (do_show_pixel_format_flags) {
3253
            writer_print_section_header(w, SECTION_ID_PIXEL_FORMAT_FLAGS);
3254
            PRINT_PIX_FMT_FLAG(BE,        "big_endian");
3255
            PRINT_PIX_FMT_FLAG(PAL,       "palette");
3256
            PRINT_PIX_FMT_FLAG(BITSTREAM, "bitstream");
3257
            PRINT_PIX_FMT_FLAG(HWACCEL,   "hwaccel");
3258
            PRINT_PIX_FMT_FLAG(PLANAR,    "planar");
3259
            PRINT_PIX_FMT_FLAG(RGB,       "rgb");
3260
#if FF_API_PSEUDOPAL
3261
            PRINT_PIX_FMT_FLAG(PSEUDOPAL, "pseudopal");
3262
#endif
3263
            PRINT_PIX_FMT_FLAG(ALPHA,     "alpha");
3264
            writer_print_section_footer(w);
3265
        }
3266
        if (do_show_pixel_format_components && (pixdesc->nb_components > 0)) {
3267
            writer_print_section_header(w, SECTION_ID_PIXEL_FORMAT_COMPONENTS);
3268
            for (i = 0; i < pixdesc->nb_components; i++) {
3269
                writer_print_section_header(w, SECTION_ID_PIXEL_FORMAT_COMPONENT);
3270
                print_int("index", i + 1);
3271
                print_int("bit_depth", pixdesc->comp[i].depth);
3272
                writer_print_section_footer(w);
3273
            }
3274
            writer_print_section_footer(w);
3275
        }
3276
        writer_print_section_footer(w);
3277
    }
3278
    writer_print_section_footer(w);
3279
}
3280
3281
12
static int opt_format(void *optctx, const char *opt, const char *arg)
3282
{
3283
12
    iformat = av_find_input_format(arg);
3284
12
    if (!iformat) {
3285
        av_log(NULL, AV_LOG_ERROR, "Unknown input format: %s\n", arg);
3286
        return AVERROR(EINVAL);
3287
    }
3288
12
    return 0;
3289
}
3290
3291
534
static inline void mark_section_show_entries(SectionID section_id,
3292
                                             int show_all_entries, AVDictionary *entries)
3293
{
3294
534
    struct section *section = &sections[section_id];
3295
3296
534
    section->show_all_entries = show_all_entries;
3297
534
    if (show_all_entries) {
3298
        SectionID *id;
3299
807
        for (id = section->children_ids; *id != -1; id++)
3300
357
            mark_section_show_entries(*id, show_all_entries, entries);
3301
    } else {
3302
84
        av_dict_copy(&section->entries_to_show, entries, 0);
3303
    }
3304
534
}
3305
3306
88
static int match_section(const char *section_name,
3307
                         int show_all_entries, AVDictionary *entries)
3308
{
3309
88
    int i, ret = 0;
3310
3311
3960
    for (i = 0; i < FF_ARRAY_ELEMS(sections); i++) {
3312
3872
        const struct section *section = &sections[i];
3313
3872
        if (!strcmp(section_name, section->name) ||
3314

3780
            (section->unique_name && !strcmp(section_name, section->unique_name))) {
3315
116
            av_log(NULL, AV_LOG_DEBUG,
3316
                   "'%s' matches section with unique name '%s'\n", section_name,
3317
116
                   (char *)av_x_if_null(section->unique_name, section->name));
3318
116
            ret++;
3319
116
            mark_section_show_entries(section->id, show_all_entries, entries);
3320
        }
3321
    }
3322
88
    return ret;
3323
}
3324
3325
50
static int opt_show_entries(void *optctx, const char *opt, const char *arg)
3326
{
3327
50
    const char *p = arg;
3328
50
    int ret = 0;
3329
3330
138
    while (*p) {
3331
88
        AVDictionary *entries = NULL;
3332
88
        char *section_name = av_get_token(&p, "=:");
3333
88
        int show_all_entries = 0;
3334
3335
88
        if (!section_name) {
3336
            av_log(NULL, AV_LOG_ERROR,
3337
                   "Missing section name for option '%s'\n", opt);
3338
            return AVERROR(EINVAL);
3339
        }
3340
3341
88
        if (*p == '=') {
3342
60
            p++;
3343

180
            while (*p && *p != ':') {
3344
120
                char *entry = av_get_token(&p, ",:");
3345
120
                if (!entry)
3346
                    break;
3347
120
                av_log(NULL, AV_LOG_VERBOSE,
3348
                       "Adding '%s' to the entries to show in section '%s'\n",
3349
                       entry, section_name);
3350
120
                av_dict_set(&entries, entry, "", AV_DICT_DONT_STRDUP_KEY);
3351
120
                if (*p == ',')
3352
60
                    p++;
3353
            }
3354
        } else {
3355
28
            show_all_entries = 1;
3356
        }
3357
3358
88
        ret = match_section(section_name, show_all_entries, entries);
3359
88
        if (ret == 0) {
3360
            av_log(NULL, AV_LOG_ERROR, "No match for section '%s'\n", section_name);
3361
            ret = AVERROR(EINVAL);
3362
        }
3363
88
        av_dict_free(&entries);
3364
88
        av_free(section_name);
3365
3366
88
        if (ret <= 0)
3367
            break;
3368
88
        if (*p)
3369
38
            p++;
3370
    }
3371
3372
50
    return ret;
3373
}
3374
3375
static int opt_show_format_entry(void *optctx, const char *opt, const char *arg)
3376
{
3377
    char *buf = av_asprintf("format=%s", arg);
3378
    int ret;
3379
3380
    if (!buf)
3381
        return AVERROR(ENOMEM);
3382
3383
    av_log(NULL, AV_LOG_WARNING,
3384
           "Option '%s' is deprecated, use '-show_entries format=%s' instead\n",
3385
           opt, arg);
3386
    ret = opt_show_entries(optctx, opt, buf);
3387
    av_free(buf);
3388
    return ret;
3389
}
3390
3391
76
static void opt_input_file(void *optctx, const char *arg)
3392
{
3393
76
    if (input_filename) {
3394
        av_log(NULL, AV_LOG_ERROR,
3395
                "Argument '%s' provided as input filename, but '%s' was already specified.\n",
3396
                arg, input_filename);
3397
        exit_program(1);
3398
    }
3399
76
    if (!strcmp(arg, "-"))
3400
        arg = "pipe:";
3401
76
    input_filename = arg;
3402
76
}
3403
3404
7
static int opt_input_file_i(void *optctx, const char *opt, const char *arg)
3405
{
3406
7
    opt_input_file(optctx, arg);
3407
7
    return 0;
3408
}
3409
3410
7
static int opt_print_filename(void *optctx, const char *opt, const char *arg)
3411
{
3412
7
    print_input_filename = arg;
3413
7
    return 0;
3414
}
3415
3416
void show_help_default(const char *opt, const char *arg)
3417
{
3418
    av_log_set_callback(log_callback_help);
3419
    show_usage();
3420
    show_help_options(options, "Main options:", 0, 0, 0);
3421
    printf("\n");
3422
3423
    show_help_children(avformat_get_class(), AV_OPT_FLAG_DECODING_PARAM);
3424
    show_help_children(avcodec_get_class(), AV_OPT_FLAG_DECODING_PARAM);
3425
}
3426
3427
/**
3428
 * Parse interval specification, according to the format:
3429
 * INTERVAL ::= [START|+START_OFFSET][%[END|+END_OFFSET]]
3430
 * INTERVALS ::= INTERVAL[,INTERVALS]
3431
*/
3432
static int parse_read_interval(const char *interval_spec,
3433
                               ReadInterval *interval)
3434
{
3435
    int ret = 0;
3436
    char *next, *p, *spec = av_strdup(interval_spec);
3437
    if (!spec)
3438
        return AVERROR(ENOMEM);
3439
3440
    if (!*spec) {
3441
</