GCC Code Coverage Report
Directory: ../../../ffmpeg/ Exec Total Coverage
File: src/fftools/ffprobe.c Lines: 1306 1887 69.2 %
Date: 2019-11-22 03:34:36 Branches: 732 1189 61.6 %

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

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

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

29187
        if (show_float || (use_value_prefix && vald != (long long int)vald))
408
22456
            snprintf(buf, buf_size, "%f", vald);
409
        else
410
6731
            snprintf(buf, buf_size, "%lld", vali);
411

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


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

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

76358
        if (!invalid || wctx->string_validation == WRITER_STRING_VALIDATION_IGNORE)
722
76358
            av_bprint_append_data(&dstbuf, p0, p-p0);
723
    }
724
725

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

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


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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

200
        } else if (sd->type == AV_PKT_DATA_SKIP_SAMPLES && sd->size == 10) {
1903
5
            print_int("skip_samples",    AV_RL32(sd->data));
1904
5
            print_int("discard_padding", AV_RL32(sd->data + 4));
1905
5
            print_int("skip_reason",     AV_RL8(sd->data + 8));
1906
5
            print_int("discard_reason",  AV_RL8(sd->data + 9));
1907
195
        } else if (sd->type == AV_PKT_DATA_MASTERING_DISPLAY_METADATA) {
1908
            AVMasteringDisplayMetadata *metadata = (AVMasteringDisplayMetadata *)sd->data;
1909
1910
            if (metadata->has_primaries) {
1911
                print_q("red_x", metadata->display_primaries[0][0], '/');
1912
                print_q("red_y", metadata->display_primaries[0][1], '/');
1913
                print_q("green_x", metadata->display_primaries[1][0], '/');
1914
                print_q("green_y", metadata->display_primaries[1][1], '/');
1915
                print_q("blue_x", metadata->display_primaries[2][0], '/');
1916
                print_q("blue_y", metadata->display_primaries[2][1], '/');
1917
1918
                print_q("white_point_x", metadata->white_point[0], '/');
1919
                print_q("white_point_y", metadata->white_point[1], '/');
1920
            }
1921
1922
            if (metadata->has_luminance) {
1923
                print_q("min_luminance", metadata->min_luminance, '/');
1924
                print_q("max_luminance", metadata->max_luminance, '/');
1925
            }
1926
195
        } else if (sd->type == AV_PKT_DATA_CONTENT_LIGHT_LEVEL) {
1927
            AVContentLightMetadata *metadata = (AVContentLightMetadata *)sd->data;
1928
            print_int("max_content", metadata->MaxCLL);
1929
            print_int("max_average", metadata->MaxFALL);
1930
        }
1931
206
        writer_print_section_footer(w);
1932
    }
1933
204
    writer_print_section_footer(w);
1934
204
}
1935
1936
478
static void print_color_range(WriterContext *w, enum AVColorRange color_range)
1937
{
1938
478
    const char *val = av_color_range_name(color_range);
1939

478
    if (!val || color_range == AVCOL_RANGE_UNSPECIFIED) {
1940
390
        print_str_opt("color_range", "unknown");
1941
    } else {
1942
88
        print_str("color_range", val);
1943
    }
1944
478
}
1945
1946
478
static void print_color_space(WriterContext *w, enum AVColorSpace color_space)
1947
{
1948
478
    const char *val = av_color_space_name(color_space);
1949

478
    if (!val || color_space == AVCOL_SPC_UNSPECIFIED) {
1950
403
        print_str_opt("color_space", "unknown");
1951
    } else {
1952
75
        print_str("color_space", val);
1953
    }
1954
478
}
1955
1956
478
static void print_primaries(WriterContext *w, enum AVColorPrimaries color_primaries)
1957
{
1958
478
    const char *val = av_color_primaries_name(color_primaries);
1959

478
    if (!val || color_primaries == AVCOL_PRI_UNSPECIFIED) {
1960
407
        print_str_opt("color_primaries", "unknown");
1961
    } else {
1962
71
        print_str("color_primaries", val);
1963
    }
1964
478
}
1965
1966
478
static void print_color_trc(WriterContext *w, enum AVColorTransferCharacteristic color_trc)
1967
{
1968
478
    const char *val = av_color_transfer_name(color_trc);
1969

478
    if (!val || color_trc == AVCOL_TRC_UNSPECIFIED) {
1970
407
        print_str_opt("color_transfer", "unknown");
1971
    } else {
1972
71
        print_str("color_transfer", val);
1973
    }
1974
478
}
1975
1976
478
static void print_chroma_location(WriterContext *w, enum AVChromaLocation chroma_location)
1977
{
1978
478
    const char *val = av_chroma_location_name(chroma_location);
1979

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

3588
    print_fmt("flags", "%c%c",      pkt->flags & AV_PKT_FLAG_KEY ? 'K' : '_',
2065
              pkt->flags & AV_PKT_FLAG_DISCARD ? 'D' : '_');
2066
2067
3588
    if (pkt->side_data_elems) {
2068
        int size;
2069
        const uint8_t *side_metadata;
2070
2071
200
        side_metadata = av_packet_get_side_data(pkt, AV_PKT_DATA_STRINGS_METADATA, &size);
2072

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

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

4
            } else if (sd->type == AV_FRAME_DATA_GOP_TIMECODE && sd->size >= 8) {
2207
                char tcbuf[AV_TIMECODE_STR_SIZE];
2208
                av_timecode_make_mpeg_tc_string(tcbuf, *(int64_t *)(sd->data));
2209
                print_str("timecode", tcbuf);
2210

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

5917
    if (dec_ctx && dec_ctx->codec) {
2275
5917
        switch (par->codec_type) {
2276
5917
        case AVMEDIA_TYPE_VIDEO:
2277
        case AVMEDIA_TYPE_AUDIO:
2278
5917
            if (*packet_new) {
2279
2914
                ret = avcodec_send_packet(dec_ctx, pkt);
2280
2914
                if (ret == AVERROR(EAGAIN)) {
2281
                    ret = 0;
2282

2914
                } else if (ret >= 0 || ret == AVERROR_EOF) {
2283
2912
                    ret = 0;
2284
2912
                    *packet_new = 0;
2285
                }
2286
            }
2287
5917
            if (ret >= 0) {
2288
5915
                ret = avcodec_receive_frame(dec_ctx, frame);
2289
5915
                if (ret >= 0) {
2290
3009
                    got_frame = 1;
2291

2906
                } else if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
2292
2906
                    ret = 0;
2293
                }
2294
            }
2295
5917
            break;
2296
2297
        case AVMEDIA_TYPE_SUBTITLE:
2298
            if (*packet_new)
2299
                ret = avcodec_decode_subtitle2(dec_ctx, &sub, &got_frame, pkt);
2300
            *packet_new = 0;
2301
            break;
2302
        default:
2303
            *packet_new = 0;
2304
        }
2305
    } else {
2306
        *packet_new = 0;
2307
    }
2308
2309
5917
    if (ret < 0)
2310
2
        return ret;
2311
5915
    if (got_frame) {
2312
3009
        int is_sub = (par->codec_type == AVMEDIA_TYPE_SUBTITLE);
2313
3009
        nb_streams_frames[pkt->stream_index]++;
2314
3009
        if (do_show_frames)
2315
3009
            if (is_sub)
2316
                show_subtitle(w, &sub, ifile->streams[pkt->stream_index].st, fmt_ctx);
2317
            else
2318
3009
                show_frame(w, frame, ifile->streams[pkt->stream_index].st, fmt_ctx);
2319
3009
        if (is_sub)
2320
            avsubtitle_free(&sub);
2321
    }
2322

5915
    return got_frame || *packet_new;
2323
}
2324
2325
42
static void log_read_interval(const ReadInterval *interval, void *log_ctx, int log_level)
2326
{
2327
42
    av_log(log_ctx, log_level, "id:%d", interval->id);
2328
2329
42
    if (interval->has_start) {
2330
        av_log(log_ctx, log_level, " start:%s%s", interval->start_is_offset ? "+" : "",
2331
               av_ts2timestr(interval->start, &AV_TIME_BASE_Q));
2332
    } else {
2333
42
        av_log(log_ctx, log_level, " start:N/A");
2334
    }
2335
2336
42
    if (interval->has_end) {
2337
        av_log(log_ctx, log_level, " end:%s", interval->end_is_offset ? "+" : "");
2338
        if (interval->duration_frames)
2339
            av_log(log_ctx, log_level, "#%"PRId64, interval->end);
2340
        else
2341
            av_log(log_ctx, log_level, "%s", av_ts2timestr(interval->end, &AV_TIME_BASE_Q));
2342
    } else {
2343
42
        av_log(log_ctx, log_level, " end:N/A");
2344
    }
2345
2346
42
    av_log(log_ctx, log_level, "\n");
2347
42
}
2348
2349
42
static int read_interval_packets(WriterContext *w, InputFile *ifile,
2350
                                 const ReadInterval *interval, int64_t *cur_ts)
2351
{
2352
42
    AVFormatContext *fmt_ctx = ifile->fmt_ctx;
2353
    AVPacket pkt;
2354
42
    AVFrame *frame = NULL;
2355
42
    int ret = 0, i = 0, frame_count = 0;
2356
42
    int64_t start = -INT64_MAX, end = interval->end;
2357

42
    int has_start = 0, has_end = interval->has_end && !interval->end_is_offset;
2358
2359
42
    av_init_packet(&pkt);
2360
2361
42
    av_log(NULL, AV_LOG_VERBOSE, "Processing read interval ");
2362
42
    log_read_interval(interval, NULL, AV_LOG_VERBOSE);
2363
2364
42
    if (interval->has_start) {
2365
        int64_t target;
2366
        if (interval->start_is_offset) {
2367
            if (*cur_ts == AV_NOPTS_VALUE) {
2368
                av_log(NULL, AV_LOG_ERROR,
2369
                       "Could not seek to relative position since current "
2370
                       "timestamp is not defined\n");
2371
                ret = AVERROR(EINVAL);
2372
                goto end;
2373
            }
2374
            target = *cur_ts + interval->start;
2375
        } else {
2376
            target = interval->start;
2377
        }
2378
2379
        av_log(NULL, AV_LOG_VERBOSE, "Seeking to read interval start point %s\n",
2380
               av_ts2timestr(target, &AV_TIME_BASE_Q));
2381
        if ((ret = avformat_seek_file(fmt_ctx, -1, -INT64_MAX, target, INT64_MAX, 0)) < 0) {
2382
            av_log(NULL, AV_LOG_ERROR, "Could not seek to position %"PRId64": %s\n",
2383
                   interval->start, av_err2str(ret));
2384
            goto end;
2385
        }
2386
    }
2387
2388
42
    frame = av_frame_alloc();
2389
42
    if (!frame) {
2390
        ret = AVERROR(ENOMEM);
2391
        goto end;
2392
    }
2393
6315
    while (!av_read_frame(fmt_ctx, &pkt)) {
2394
6273
        if (fmt_ctx->nb_streams > nb_streams) {
2395
            REALLOCZ_ARRAY_STREAM(nb_streams_frames,  nb_streams, fmt_ctx->nb_streams);
2396
            REALLOCZ_ARRAY_STREAM(nb_streams_packets, nb_streams, fmt_ctx->nb_streams);
2397
            REALLOCZ_ARRAY_STREAM(selected_streams,   nb_streams, fmt_ctx->nb_streams);
2398
            nb_streams = fmt_ctx->nb_streams;
2399
        }
2400
6273
        if (selected_streams[pkt.stream_index]) {
2401
6270
            AVRational tb = ifile->streams[pkt.stream_index].st->time_base;
2402
2403
6270
            if (pkt.pts != AV_NOPTS_VALUE)
2404
6258
                *cur_ts = av_rescale_q(pkt.pts, tb, AV_TIME_BASE_Q);
2405
2406

6270
            if (!has_start && *cur_ts != AV_NOPTS_VALUE) {
2407
40
                start = *cur_ts;
2408
40
                has_start = 1;
2409
            }
2410
2411

6270
            if (has_start && !has_end && interval->end_is_offset) {
2412
                end = start + interval->end;
2413
                has_end = 1;
2414
            }
2415
2416

6270
            if (interval->end_is_offset && interval->duration_frames) {
2417
                if (frame_count >= interval->end)
2418
                    break;
2419

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

82
    if (!do_bitexact && (profile = avcodec_profile_name(par->codec_id, par->profile)))
2508
7
        print_str("profile", profile);
2509
    else {
2510
75
        if (par->profile != FF_PROFILE_UNKNOWN) {
2511
            char profile_num[12];
2512
27
            snprintf(profile_num, sizeof(profile_num), "%d", par->profile);
2513
27
            print_str("profile", profile_num);
2514
        } else
2515
48
            print_str_opt("profile", "unknown");
2516
    }
2517
2518
82
    s = av_get_media_type_string(par->codec_type);
2519
82
    if (s) print_str    ("codec_type", s);
2520
    else   print_str_opt("codec_type", "unknown");
2521
#if FF_API_LAVF_AVCTX
2522
82
    if (dec_ctx)
2523
76
        print_q("codec_time_base", dec_ctx->time_base, '/');
2524
#endif
2525
2526
    /* print AVI/FourCC tag */
2527
82
    print_str("codec_tag_string",    av_fourcc2str(par->codec_tag));
2528
82
    print_fmt("codec_tag", "0x%04"PRIx32, par->codec_tag);
2529
2530

82
    switch (par->codec_type) {
2531
39
    case AVMEDIA_TYPE_VIDEO:
2532
39
        print_int("width",        par->width);
2533
39
        print_int("height",       par->height);
2534
#if FF_API_LAVF_AVCTX
2535
39
        if (dec_ctx) {
2536
39
            print_int("coded_width",  dec_ctx->coded_width);
2537
39
            print_int("coded_height", dec_ctx->coded_height);
2538
        }
2539
#endif
2540
39
        print_int("has_b_frames", par->video_delay);
2541
39
        sar = av_guess_sample_aspect_ratio(fmt_ctx, stream, NULL);
2542
39
        if (sar.num) {
2543
34
            print_q("sample_aspect_ratio", sar, ':');
2544
34
            av_reduce(&dar.num, &dar.den,
2545
34
                      par->width  * sar.num,
2546
34
                      par->height * sar.den,
2547
                      1024*1024);
2548
34
            print_q("display_aspect_ratio", dar, ':');
2549
        } else {
2550
5
            print_str_opt("sample_aspect_ratio", "N/A");
2551
5
            print_str_opt("display_aspect_ratio", "N/A");
2552
        }
2553
39
        s = av_get_pix_fmt_name(par->format);
2554
39
        if (s) print_str    ("pix_fmt", s);
2555
2
        else   print_str_opt("pix_fmt", "unknown");
2556
39
        print_int("level",   par->level);
2557
2558
39
        print_color_range(w, par->color_range);
2559
39
        print_color_space(w, par->color_space);
2560
39
        print_color_trc(w, par->color_trc);
2561
39
        print_primaries(w, par->color_primaries);
2562
39
        print_chroma_location(w, par->chroma_location);
2563
2564
39
        if (par->field_order == AV_FIELD_PROGRESSIVE)
2565
5
            print_str("field_order", "progressive");
2566
34
        else if (par->field_order == AV_FIELD_TT)
2567
5
            print_str("field_order", "tt");
2568
29
        else if (par->field_order == AV_FIELD_BB)
2569
1
            print_str("field_order", "bb");
2570
28
        else if (par->field_order == AV_FIELD_TB)
2571
            print_str("field_order", "tb");
2572
28
        else if (par->field_order == AV_FIELD_BT)
2573
            print_str("field_order", "bt");
2574
        else
2575
28
            print_str_opt("field_order", "unknown");
2576
2577
#if FF_API_PRIVATE_OPT
2578

39
        if (dec_ctx && dec_ctx->timecode_frame_start >= 0) {
2579
            char tcbuf[AV_TIMECODE_STR_SIZE];
2580
            av_timecode_make_mpeg_tc_string(tcbuf, dec_ctx->timecode_frame_start);
2581
            print_str("timecode", tcbuf);
2582
        } else {
2583
39
            print_str_opt("timecode", "N/A");
2584
        }
2585
#endif
2586
39
        if (dec_ctx)
2587
39
            print_int("refs", dec_ctx->refs);
2588
39
        break;
2589
2590
37
    case AVMEDIA_TYPE_AUDIO:
2591
37
        s = av_get_sample_fmt_name(par->format);
2592
37
        if (s) print_str    ("sample_fmt", s);
2593
        else   print_str_opt("sample_fmt", "unknown");
2594
37
        print_val("sample_rate",     par->sample_rate, unit_hertz_str);
2595
37
        print_int("channels",        par->channels);
2596
2597
37
        if (par->channel_layout) {
2598
22
            av_bprint_clear(&pbuf);
2599
22
            av_bprint_channel_layout(&pbuf, par->channels, par->channel_layout);
2600
22
            print_str    ("channel_layout", pbuf.str);
2601
        } else {
2602
15
            print_str_opt("channel_layout", "unknown");
2603
        }
2604
2605
37
        print_int("bits_per_sample", av_get_bits_per_sample(par->codec_id));
2606
37
        break;
2607
2608
    case AVMEDIA_TYPE_SUBTITLE:
2609
        if (par->width)
2610
            print_int("width",       par->width);
2611
        else
2612
            print_str_opt("width",   "N/A");
2613
        if (par->height)
2614
            print_int("height",      par->height);
2615
        else
2616
            print_str_opt("height",  "N/A");
2617
        break;
2618
    }
2619
2620


82
    if (dec_ctx && dec_ctx->codec && dec_ctx->codec->priv_class && show_private_data) {
2621
45
        const AVOption *opt = NULL;
2622
215
        while (opt = av_opt_next(dec_ctx->priv_data,opt)) {
2623
            uint8_t *str;
2624
170
            if (opt->flags) continue;
2625
46
            if (av_opt_get(dec_ctx->priv_data, opt->name, 0, &str) >= 0) {
2626
46
                print_str(opt->name, str);
2627
46
                av_free(str);
2628
            }
2629
        }
2630
    }
2631
2632
82
    if (fmt_ctx->iformat->flags & AVFMT_SHOW_IDS) print_fmt    ("id", "0x%x", stream->id);
2633
65
    else                                          print_str_opt("id", "N/A");
2634
82
    print_q("r_frame_rate",   stream->r_frame_rate,   '/');
2635
82
    print_q("avg_frame_rate", stream->avg_frame_rate, '/');
2636
82
    print_q("time_base",      stream->time_base,      '/');
2637
82
    print_ts  ("start_pts",   stream->start_time);
2638
82
    print_time("start_time",  stream->start_time, &stream->time_base);
2639
82
    print_ts  ("duration_ts", stream->duration);
2640
82
    print_time("duration",    stream->duration, &stream->time_base);
2641
82
    if (par->bit_rate > 0)     print_val    ("bit_rate", par->bit_rate, unit_bit_per_second_str);
2642
35
    else                       print_str_opt("bit_rate", "N/A");
2643
#if FF_API_LAVF_AVCTX
2644
82
    if (stream->codec->rc_max_rate > 0) print_val ("max_bit_rate", stream->codec->rc_max_rate, unit_bit_per_second_str);
2645
70
    else                                print_str_opt("max_bit_rate", "N/A");
2646
#endif
2647

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

67
    do_read_frames = do_show_frames || do_count_frames;
2981

67
    do_read_packets = do_show_packets || do_count_packets;
2982
2983
67
    ret = open_input_file(&ifile, filename);
2984
67
    if (ret < 0)
2985
        goto end;
2986
2987
#define CHECK_END if (ret < 0) goto end
2988
2989
67
    nb_streams = ifile.fmt_ctx->nb_streams;
2990
67
    REALLOCZ_ARRAY_STREAM(nb_streams_frames,0,ifile.fmt_ctx->nb_streams);
2991
67
    REALLOCZ_ARRAY_STREAM(nb_streams_packets,0,ifile.fmt_ctx->nb_streams);
2992
67
    REALLOCZ_ARRAY_STREAM(selected_streams,0,ifile.fmt_ctx->nb_streams);
2993
2994
177
    for (i = 0; i < ifile.fmt_ctx->nb_streams; i++) {
2995
110
        if (stream_specifier) {
2996
31
            ret = avformat_match_stream_specifier(ifile.fmt_ctx,
2997
31
                                                  ifile.fmt_ctx->streams[i],
2998
                                                  stream_specifier);
2999
31
            CHECK_END;
3000
            else
3001
31
                selected_streams[i] = ret;
3002
31
            ret = 0;
3003
        } else {
3004
79
            selected_streams[i] = 1;
3005
        }
3006
110
        if (!selected_streams[i])
3007
8
            ifile.fmt_ctx->streams[i]->discard = AVDISCARD_ALL;
3008
    }
3009
3010

67
    if (do_read_frames || do_read_packets) {
3011

42
        if (do_show_frames && do_show_packets &&
3012
9
            wctx->writer->flags & WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER)
3013
4
            section_id = SECTION_ID_PACKETS_AND_FRAMES;
3014

38
        else if (do_show_packets && !do_show_frames)
3015
13
            section_id = SECTION_ID_PACKETS;
3016
        else // (!do_show_packets && do_show_frames)
3017
25
            section_id = SECTION_ID_FRAMES;
3018

42
        if (do_show_frames || do_show_packets)
3019
42
            writer_print_section_header(wctx, section_id);
3020
42
        ret = read_packets(wctx, &ifile);
3021

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

3218
            (section->unique_name && !strcmp(section_name, section->unique_name))) {
3194
101
            av_log(NULL, AV_LOG_DEBUG,
3195
                   "'%s' matches section with unique name '%s'\n", section_name,
3196
101
                   (char *)av_x_if_null(section->unique_name, section->name));
3197
101
            ret++;
3198
101
            mark_section_show_entries(section->id, show_all_entries, entries);
3199
        }
3200
    }
3201
75
    return ret;
3202
}
3203
3204
43
static int opt_show_entries(void *optctx, const char *opt, const char *arg)
3205
{
3206
43
    const char *p = arg;
3207
43
    int ret = 0;
3208
3209
118
    while (*p) {
3210
75
        AVDictionary *entries = NULL;
3211
75
        char *section_name = av_get_token(&p, "=:");
3212
75
        int show_all_entries = 0;
3213
3214
75
        if (!section_name) {
3215
            av_log(NULL, AV_LOG_ERROR,
3216
                   "Missing section name for option '%s'\n", opt);
3217
            return AVERROR(EINVAL);
3218
        }
3219
3220
75
        if (*p == '=') {
3221
53
            p++;
3222

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