GCC Code Coverage Report
Directory: ../../../ffmpeg/ Exec Total Coverage
File: src/fftools/ffprobe.c Lines: 1312 1893 69.3 %
Date: 2020-04-02 13:49:07 Branches: 734 1191 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 const char *print_input_filename;
258
static AVInputFormat *iformat = NULL;
259
260
static struct AVHashContext *hash;
261
262
static const struct {
263
    double bin_val;
264
    double dec_val;
265
    const char *bin_str;
266
    const char *dec_str;
267
} si_prefixes[] = {
268
    { 1.0, 1.0, "", "" },
269
    { 1.024e3, 1e3, "Ki", "K" },
270
    { 1.048576e6, 1e6, "Mi", "M" },
271
    { 1.073741824e9, 1e9, "Gi", "G" },
272
    { 1.099511627776e12, 1e12, "Ti", "T" },
273
    { 1.125899906842624e15, 1e15, "Pi", "P" },
274
};
275
276
static const char unit_second_str[]         = "s"    ;
277
static const char unit_hertz_str[]          = "Hz"   ;
278
static const char unit_byte_str[]           = "byte" ;
279
static const char unit_bit_per_second_str[] = "bit/s";
280
281
static int nb_streams;
282
static uint64_t *nb_streams_packets;
283
static uint64_t *nb_streams_frames;
284
static int *selected_streams;
285
286
#if HAVE_THREADS
287
pthread_mutex_t log_mutex;
288
#endif
289
typedef struct LogBuffer {
290
    char *context_name;
291
    int log_level;
292
    char *log_message;
293
    AVClassCategory category;
294
    char *parent_name;
295
    AVClassCategory parent_category;
296
}LogBuffer;
297
298
static LogBuffer *log_buffer;
299
static int log_buffer_size;
300
301
static void log_callback(void *ptr, int level, const char *fmt, va_list vl)
302
{
303
    AVClass* avc = ptr ? *(AVClass **) ptr : NULL;
304
    va_list vl2;
305
    char line[1024];
306
    static int print_prefix = 1;
307
    void *new_log_buffer;
308
309
    va_copy(vl2, vl);
310
    av_log_default_callback(ptr, level, fmt, vl);
311
    av_log_format_line(ptr, level, fmt, vl2, line, sizeof(line), &print_prefix);
312
    va_end(vl2);
313
314
#if HAVE_THREADS
315
    pthread_mutex_lock(&log_mutex);
316
317
    new_log_buffer = av_realloc_array(log_buffer, log_buffer_size + 1, sizeof(*log_buffer));
318
    if (new_log_buffer) {
319
        char *msg;
320
        int i;
321
322
        log_buffer = new_log_buffer;
323
        memset(&log_buffer[log_buffer_size], 0, sizeof(log_buffer[log_buffer_size]));
324
        log_buffer[log_buffer_size].context_name= avc ? av_strdup(avc->item_name(ptr)) : NULL;
325
        if (avc) {
326
            if (avc->get_category) log_buffer[log_buffer_size].category = avc->get_category(ptr);
327
            else                   log_buffer[log_buffer_size].category = avc->category;
328
        }
329
        log_buffer[log_buffer_size].log_level   = level;
330
        msg = log_buffer[log_buffer_size].log_message = av_strdup(line);
331
        for (i=strlen(msg) - 1; i>=0 && msg[i] == '\n'; i--) {
332
            msg[i] = 0;
333
        }
334
        if (avc && avc->parent_log_context_offset) {
335
            AVClass** parent = *(AVClass ***) (((uint8_t *) ptr) +
336
                                   avc->parent_log_context_offset);
337
            if (parent && *parent) {
338
                log_buffer[log_buffer_size].parent_name = av_strdup((*parent)->item_name(parent));
339
                log_buffer[log_buffer_size].parent_category =
340
                    (*parent)->get_category ? (*parent)->get_category(parent) :(*parent)->category;
341
            }
342
        }
343
        log_buffer_size ++;
344
    }
345
346
    pthread_mutex_unlock(&log_mutex);
347
#endif
348
}
349
350
static void ffprobe_cleanup(int ret)
351
{
352
    int i;
353
    for (i = 0; i < FF_ARRAY_ELEMS(sections); i++)
354
        av_dict_free(&(sections[i].entries_to_show));
355
356
#if HAVE_THREADS
357
    pthread_mutex_destroy(&log_mutex);
358
#endif
359
}
360
361
struct unit_value {
362
    union { double d; long long int i; } val;
363
    const char *unit;
364
};
365
366
29187
static char *value_string(char *buf, int buf_size, struct unit_value uv)
367
{
368
    double vald;
369
    long long int vali;
370
29187
    int show_float = 0;
371
372
29187
    if (uv.unit == unit_second_str) {
373
22456
        vald = uv.val.d;
374
22456
        show_float = 1;
375
    } else {
376
6731
        vald = vali = uv.val.i;
377
    }
378
379

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

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

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

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


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

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

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

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

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


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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

67
    do_read_frames = do_show_frames || do_count_frames;
2988

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

67
    if (do_read_frames || do_read_packets) {
3018

42
        if (do_show_frames && do_show_packets &&
3019
9
            wctx->writer->flags & WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER)
3020
4
            section_id = SECTION_ID_PACKETS_AND_FRAMES;
3021

38
        else if (do_show_packets && !do_show_frames)
3022
13
            section_id = SECTION_ID_PACKETS;
3023
        else // (!do_show_packets && do_show_frames)
3024
25
            section_id = SECTION_ID_FRAMES;
3025

42
        if (do_show_frames || do_show_packets)
3026
42
            writer_print_section_header(wctx, section_id);
3027
42
        ret = read_packets(wctx, &ifile);
3028

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

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

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