LCOV - code coverage report
Current view: top level - fftools - ffprobe.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1281 1886 67.9 %
Date: 2017-10-22 09:09:27 Functions: 88 122 72.1 %

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

Generated by: LCOV version 1.13