LCOV - code coverage report
Current view: top level - src - ffprobe.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1228 1855 66.2 %
Date: 2017-07-20 10:18:08 Functions: 82 117 70.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       30327 : static char *value_string(char *buf, int buf_size, struct unit_value uv)
     362             : {
     363             :     double vald;
     364             :     long long int vali;
     365       30327 :     int show_float = 0;
     366             : 
     367       30327 :     if (uv.unit == unit_second_str) {
     368       23381 :         vald = uv.val.d;
     369       23381 :         show_float = 1;
     370             :     } else {
     371        6946 :         vald = vali = uv.val.i;
     372             :     }
     373             : 
     374       30327 :     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       30327 :         const char *prefix_string = "";
     385             : 
     386       30327 :         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       30327 :         if (show_float || (use_value_prefix && vald != (long long int)vald))
     404       23381 :             snprintf(buf, buf_size, "%f", vald);
     405             :         else
     406        6946 :             snprintf(buf, buf_size, "%lld", vali);
     407       30327 :         av_strlcatf(buf, buf_size, "%s%s%s", *prefix_string || show_value_unit ? " " : "",
     408       30327 :                  prefix_string, show_value_unit ? uv.unit : "");
     409             :     }
     410             : 
     411       30327 :     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          52 : static void writer_close(WriterContext **wctx)
     512             : {
     513             :     int i;
     514             : 
     515          52 :     if (!*wctx)
     516           0 :         return;
     517             : 
     518          52 :     if ((*wctx)->writer->uninit)
     519           0 :         (*wctx)->writer->uninit(*wctx);
     520         572 :     for (i = 0; i < SECTION_MAX_NB_LEVELS; i++)
     521         520 :         av_bprint_finalize(&(*wctx)->section_pbuf[i], NULL);
     522          52 :     if ((*wctx)->writer->priv_class)
     523          52 :         av_opt_free((*wctx)->priv);
     524          52 :     av_freep(&((*wctx)->priv));
     525          52 :     av_opt_free(*wctx);
     526          52 :     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          52 : static int writer_open(WriterContext **wctx, const Writer *writer, const char *args,
     539             :                        const struct section *sections, int nb_sections)
     540             : {
     541          52 :     int i, ret = 0;
     542             : 
     543          52 :     if (!(*wctx = av_mallocz(sizeof(WriterContext)))) {
     544           0 :         ret = AVERROR(ENOMEM);
     545           0 :         goto fail;
     546             :     }
     547             : 
     548          52 :     if (!((*wctx)->priv = av_mallocz(writer->priv_size))) {
     549           0 :         ret = AVERROR(ENOMEM);
     550           0 :         goto fail;
     551             :     }
     552             : 
     553          52 :     (*wctx)->class = &writer_class;
     554          52 :     (*wctx)->writer = writer;
     555          52 :     (*wctx)->level = -1;
     556          52 :     (*wctx)->sections = sections;
     557          52 :     (*wctx)->nb_sections = nb_sections;
     558             : 
     559          52 :     av_opt_set_defaults(*wctx);
     560             : 
     561          52 :     if (writer->priv_class) {
     562          52 :         void *priv_ctx = (*wctx)->priv;
     563          52 :         *((const AVClass **)priv_ctx) = writer->priv_class;
     564          52 :         av_opt_set_defaults(priv_ctx);
     565             :     }
     566             : 
     567             :     /* convert options to dictionary */
     568          52 :     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          52 :         const uint8_t *p = (*wctx)->string_validation_replacement;
     593          52 :         const uint8_t *endp = p + strlen(p);
     594         156 :         while (*p) {
     595          52 :             const uint8_t *p0 = p;
     596             :             int32_t code;
     597          52 :             ret = av_utf8_decode(&code, &p, endp, (*wctx)->string_validation_utf8_flags);
     598          52 :             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         572 :     for (i = 0; i < SECTION_MAX_NB_LEVELS; i++)
     611         520 :         av_bprint_init(&(*wctx)->section_pbuf[i], 1, AV_BPRINT_SIZE_UNLIMITED);
     612             : 
     613          52 :     if ((*wctx)->writer->init)
     614          28 :         ret = (*wctx)->writer->init(*wctx);
     615          52 :     if (ret < 0)
     616           0 :         goto fail;
     617             : 
     618          52 :     return 0;
     619             : 
     620           0 : fail:
     621           0 :     writer_close(wctx);
     622           0 :     return ret;
     623             : }
     624             : 
     625        8095 : static inline void writer_print_section_header(WriterContext *wctx,
     626             :                                                int section_id)
     627             : {
     628             :     int parent_section_id;
     629        8095 :     wctx->level++;
     630        8095 :     av_assert0(wctx->level < SECTION_MAX_NB_LEVELS);
     631       16190 :     parent_section_id = wctx->level ?
     632        8095 :         (wctx->section[wctx->level-1])->id : SECTION_ID_NONE;
     633             : 
     634        8095 :     wctx->nb_item[wctx->level] = 0;
     635        8095 :     wctx->section[wctx->level] = &wctx->sections[section_id];
     636             : 
     637        8095 :     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        8091 :     } 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        8095 :     if (wctx->writer->print_section_header)
     646        8095 :         wctx->writer->print_section_header(wctx);
     647        8095 : }
     648             : 
     649        8095 : static inline void writer_print_section_footer(WriterContext *wctx)
     650             : {
     651        8095 :     int section_id = wctx->section[wctx->level]->id;
     652       16190 :     int parent_section_id = wctx->level ?
     653        8095 :         wctx->section[wctx->level-1]->id : SECTION_ID_NONE;
     654             : 
     655        8095 :     if (parent_section_id != SECTION_ID_NONE)
     656        8043 :         wctx->nb_item[wctx->level-1]++;
     657        8095 :     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        8095 :     if (wctx->writer->print_section_footer)
     662        8011 :         wctx->writer->print_section_footer(wctx);
     663        8095 :     wctx->level--;
     664        8095 : }
     665             : 
     666       41729 : static inline void writer_print_integer(WriterContext *wctx,
     667             :                                         const char *key, long long int val)
     668             : {
     669       41729 :     const struct section *section = wctx->section[wctx->level];
     670             : 
     671       41729 :     if (section->show_all_entries || av_dict_get(section->entries_to_show, key, NULL, 0)) {
     672       27120 :         wctx->writer->print_integer(wctx, key, val);
     673       27120 :         wctx->nb_item[wctx->level]++;
     674             :     }
     675       41729 : }
     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       66332 : static inline int writer_print_string(WriterContext *wctx,
     736             :                                       const char *key, const char *val, int flags)
     737             : {
     738       66332 :     const struct section *section = wctx->section[wctx->level];
     739       66332 :     int ret = 0;
     740             : 
     741       66332 :     if ((flags & PRINT_STRING_OPT)
     742        9066 :         && !(wctx->writer->flags & WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS))
     743         144 :         return 0;
     744             : 
     745       66188 :     if (section->show_all_entries || av_dict_get(section->entries_to_show, key, NULL, 0)) {
     746       23883 :         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       21502 :             wctx->writer->print_string(wctx, key, val);
     763             :         }
     764             : 
     765       23883 :         wctx->nb_item[wctx->level]++;
     766             :     }
     767             : 
     768       66188 :     return ret;
     769             : }
     770             : 
     771         458 : static inline void writer_print_rational(WriterContext *wctx,
     772             :                                          const char *key, AVRational q, char sep)
     773             : {
     774             :     AVBPrint buf;
     775         458 :     av_bprint_init(&buf, 0, AV_BPRINT_SIZE_AUTOMATIC);
     776         458 :     av_bprintf(&buf, "%d%c%d", q.num, sep, q.den);
     777         458 :     writer_print_string(wctx, key, buf.str, 0);
     778         458 : }
     779             : 
     780       27508 : 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       27508 :     if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0)) {
     786        4127 :         writer_print_string(wctx, key, "N/A", PRINT_STRING_OPT);
     787             :     } else {
     788       23381 :         double d = ts * av_q2d(*time_base);
     789             :         struct unit_value uv;
     790       23381 :         uv.val.d = d;
     791       23381 :         uv.unit = unit_second_str;
     792       23381 :         value_string(buf, sizeof(buf), uv);
     793       23381 :         writer_print_string(wctx, key, buf, 0);
     794             :     }
     795       27508 : }
     796             : 
     797       27464 : static void writer_print_ts(WriterContext *wctx, const char *key, int64_t ts, int is_duration)
     798             : {
     799       27464 :     if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0)) {
     800        4127 :         writer_print_string(wctx, key, "N/A", PRINT_STRING_OPT);
     801             :     } else {
     802       23337 :         writer_print_integer(wctx, key, ts);
     803             :     }
     804       27464 : }
     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        3642 : static void writer_print_data_hash(WriterContext *wctx, const char *name,
     835             :                                    uint8_t *data, int size)
     836             : {
     837        3642 :     char *p, buf[AV_HASH_MAX_SIZE * 2 + 64] = { 0 };
     838             : 
     839        3642 :     if (!hash)
     840        3642 :         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         364 : static int writer_register(const Writer *writer)
     880             : {
     881             :     static int next_registered_writer_idx = 0;
     882             : 
     883         364 :     if (next_registered_writer_idx == MAX_REGISTERED_WRITERS_NB)
     884           0 :         return AVERROR(ENOMEM);
     885             : 
     886         364 :     registered_writers[next_registered_writer_idx++] = writer;
     887         364 :     return 0;
     888             : }
     889             : 
     890          52 : static const Writer *writer_get_by_name(const char *name)
     891             : {
     892             :     int i;
     893             : 
     894          96 :     for (i = 0; registered_writers[i]; i++)
     895          96 :         if (!strcmp(registered_writers[i]->name, name))
     896          52 :             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        2165 : static inline char *upcase_string(char *dst, size_t dst_size, const char *src)
     939             : {
     940             :     int i;
     941       15710 :     for (i = 0; src[i] && i < dst_size-1; i++)
     942       13545 :         dst[i] = av_toupper(src[i]);
     943        2165 :     dst[i] = 0;
     944        2165 :     return dst;
     945             : }
     946             : 
     947        1263 : static void default_print_section_header(WriterContext *wctx)
     948             : {
     949        1263 :     DefaultContext *def = wctx->priv;
     950             :     char buf[32];
     951        1263 :     const struct section *section = wctx->section[wctx->level];
     952        2526 :     const struct section *parent_section = wctx->level ?
     953        1263 :         wctx->section[wctx->level-1] : NULL;
     954             : 
     955        1263 :     av_bprint_clear(&wctx->section_pbuf[wctx->level]);
     956        2503 :     if (parent_section &&
     957        1240 :         !(parent_section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))) {
     958         247 :         def->nested_section[wctx->level] = 1;
     959         494 :         av_bprintf(&wctx->section_pbuf[wctx->level], "%s%s:",
     960         247 :                    wctx->section_pbuf[wctx->level-1].str,
     961             :                    upcase_string(buf, sizeof(buf),
     962         247 :                                  av_x_if_null(section->element_name, section->name)));
     963             :     }
     964             : 
     965        1263 :     if (def->noprint_wrappers || def->nested_section[wctx->level])
     966         255 :         return;
     967             : 
     968        1008 :     if (!(section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY)))
     969         959 :         printf("[%s]\n", upcase_string(buf, sizeof(buf), section->name));
     970             : }
     971             : 
     972        1263 : static void default_print_section_footer(WriterContext *wctx)
     973             : {
     974        1263 :     DefaultContext *def = wctx->priv;
     975        1263 :     const struct section *section = wctx->section[wctx->level];
     976             :     char buf[32];
     977             : 
     978        1263 :     if (def->noprint_wrappers || def->nested_section[wctx->level])
     979         255 :         return;
     980             : 
     981        1008 :     if (!(section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY)))
     982         959 :         printf("[/%s]\n", upcase_string(buf, sizeof(buf), section->name));
     983             : }
     984             : 
     985        8179 : static void default_print_str(WriterContext *wctx, const char *key, const char *value)
     986             : {
     987        8179 :     DefaultContext *def = wctx->priv;
     988             : 
     989        8179 :     if (!def->nokey)
     990        8175 :         printf("%s%s=", wctx->section_pbuf[wctx->level].str, key);
     991        8179 :     printf("%s\n", value);
     992        8179 : }
     993             : 
     994        3870 : static void default_print_int(WriterContext *wctx, const char *key, long long int value)
     995             : {
     996        3870 :     DefaultContext *def = wctx->priv;
     997             : 
     998        3870 :     if (!def->nokey)
     999        3870 :         printf("%s%s=", wctx->section_pbuf[wctx->level].str, key);
    1000        3870 :     printf("%lld\n", value);
    1001        3870 : }
    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       14073 : static const char *c_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
    1020             : {
    1021             :     const char *p;
    1022             : 
    1023       82226 :     for (p = src; *p; p++) {
    1024       68153 :         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       68149 :         default:
    1031       68149 :             if (*p == sep)
    1032           0 :                 av_bprint_chars(dst, '\\', 1);
    1033       68149 :             av_bprint_chars(dst, *p, 1);
    1034             :         }
    1035             :     }
    1036       14073 :     return dst->str;
    1037             : }
    1038             : 
    1039             : /**
    1040             :  * Quote fields containing special characters, check RFC4180.
    1041             :  */
    1042         355 : static const char *csv_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
    1043             : {
    1044         355 :     char meta_chars[] = { sep, '"', '\n', '\r', '\0' };
    1045         355 :     int needs_quoting = !!src[strcspn(src, meta_chars)];
    1046             : 
    1047         355 :     if (needs_quoting)
    1048           1 :         av_bprint_chars(dst, '"', 1);
    1049             : 
    1050        2452 :     for (; *src; src++) {
    1051        2097 :         if (*src == '"')
    1052           2 :             av_bprint_chars(dst, '"', 1);
    1053        2097 :         av_bprint_chars(dst, *src, 1);
    1054             :     }
    1055         355 :     if (needs_quoting)
    1056           1 :         av_bprint_chars(dst, '"', 1);
    1057         355 :     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       14428 : static void compact_print_str(WriterContext *wctx, const char *key, const char *value)
    1158             : {
    1159       14428 :     CompactContext *compact = wctx->priv;
    1160             :     AVBPrint buf;
    1161             : 
    1162       14428 :     if (wctx->nb_item[wctx->level]) printf("%c", compact->item_sep);
    1163       14428 :     if (!compact->nokey)
    1164       10908 :         printf("%s%s=", wctx->section_pbuf[wctx->level].str, key);
    1165       14428 :     av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
    1166       14428 :     printf("%s", compact->escape_str(&buf, value, compact->item_sep, wctx));
    1167       14428 :     av_bprint_finalize(&buf, NULL);
    1168       14428 : }
    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         355 : static const char *flat_escape_key_str(AVBPrint *dst, const char *src, const char sep)
    1260             : {
    1261             :     const char *p;
    1262             : 
    1263        4445 :     for (p = src; *p; p++) {
    1264        8594 :         if (!((*p >= '0' && *p <= '9') ||
    1265        7763 :               (*p >= 'a' && *p <= 'z') ||
    1266         830 :               (*p >= 'A' && *p <= 'Z')))
    1267         414 :             av_bprint_chars(dst, '_', 1);
    1268             :         else
    1269        3676 :             av_bprint_chars(dst, *p, 1);
    1270             :     }
    1271         355 :     return dst->str;
    1272             : }
    1273             : 
    1274         355 : static const char *flat_escape_value_str(AVBPrint *dst, const char *src)
    1275             : {
    1276             :     const char *p;
    1277             : 
    1278        2452 :     for (p = src; *p; p++) {
    1279        2097 :         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        2095 :         default:   av_bprint_chars(dst, *p, 1);   break;
    1287             :         }
    1288             :     }
    1289         355 :     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         355 : static void flat_print_str(WriterContext *wctx, const char *key, const char *value)
    1324             : {
    1325         355 :     FlatContext *flat = wctx->priv;
    1326             :     AVBPrint buf;
    1327             : 
    1328         355 :     printf("%s", wctx->section_pbuf[wctx->level].str);
    1329         355 :     av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
    1330         355 :     printf("%s=", flat_escape_key_str(&buf, key, flat->sep));
    1331         355 :     av_bprint_clear(&buf);
    1332         355 :     printf("\"%s\"\n", flat_escape_value_str(&buf, value));
    1333         355 :     av_bprint_finalize(&buf, NULL);
    1334         355 : }
    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         710 : static char *ini_escape_str(AVBPrint *dst, const char *src)
    1366             : {
    1367         710 :     int i = 0;
    1368         710 :     char c = 0;
    1369             : 
    1370        7607 :     while (c = src[i++]) {
    1371        6187 :         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        6187 :         default:
    1382        6187 :             if ((unsigned char)c < 32)
    1383           0 :                 av_bprintf(dst, "\\x00%02x", c & 0xff);
    1384             :             else
    1385        6187 :                 av_bprint_chars(dst, c, 1);
    1386        6187 :             break;
    1387             :         }
    1388             :     }
    1389         710 :     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         355 : static void ini_print_str(WriterContext *wctx, const char *key, const char *value)
    1426             : {
    1427             :     AVBPrint buf;
    1428             : 
    1429         355 :     av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
    1430         355 :     printf("%s=", ini_escape_str(&buf, key));
    1431         355 :     av_bprint_clear(&buf);
    1432         355 :     printf("%s\n", ini_escape_str(&buf, value));
    1433         355 :     av_bprint_finalize(&buf, NULL);
    1434         355 : }
    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          52 : static void writer_register_all(void)
    1786             : {
    1787             :     static int initialized;
    1788             : 
    1789          52 :     if (initialized)
    1790           0 :         return;
    1791          52 :     initialized = 1;
    1792             : 
    1793          52 :     writer_register(&default_writer);
    1794          52 :     writer_register(&compact_writer);
    1795          52 :     writer_register(&csv_writer);
    1796          52 :     writer_register(&flat_writer);
    1797          52 :     writer_register(&ini_writer);
    1798          52 :     writer_register(&json_writer);
    1799          52 :     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        1457 : static inline int show_tags(WriterContext *w, AVDictionary *tags, int section_id)
    1836             : {
    1837        1457 :     AVDictionaryEntry *tag = NULL;
    1838        1457 :     int ret = 0;
    1839             : 
    1840        1457 :     if (!tags)
    1841         866 :         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        6394 : static void clear_log(int need_lock)
    1929             : {
    1930             :     int i;
    1931             : 
    1932        6394 :     if (need_lock)
    1933        6394 :         pthread_mutex_lock(&log_mutex);
    1934        6394 :     for (i=0; i<log_buffer_size; i++) {
    1935           0 :         av_freep(&log_buffer[i].context_name);
    1936           0 :         av_freep(&log_buffer[i].parent_name);
    1937           0 :         av_freep(&log_buffer[i].log_message);
    1938             :     }
    1939        6394 :     log_buffer_size = 0;
    1940        6394 :     if(need_lock)
    1941        6394 :         pthread_mutex_unlock(&log_mutex);
    1942        6394 : }
    1943             : 
    1944           0 : static int show_log(WriterContext *w, int section_ids, int section_id, int log_level)
    1945             : {
    1946             :     int i;
    1947           0 :     pthread_mutex_lock(&log_mutex);
    1948           0 :     if (!log_buffer_size) {
    1949           0 :         pthread_mutex_unlock(&log_mutex);
    1950           0 :         return 0;
    1951             :     }
    1952           0 :     writer_print_section_header(w, section_ids);
    1953             : 
    1954           0 :     for (i=0; i<log_buffer_size; i++) {
    1955           0 :         if (log_buffer[i].log_level <= log_level) {
    1956           0 :             writer_print_section_header(w, section_id);
    1957           0 :             print_str("context", log_buffer[i].context_name);
    1958           0 :             print_int("level", log_buffer[i].log_level);
    1959           0 :             print_int("category", log_buffer[i].category);
    1960           0 :             if (log_buffer[i].parent_name) {
    1961           0 :                 print_str("parent_context", log_buffer[i].parent_name);
    1962           0 :                 print_int("parent_category", log_buffer[i].parent_category);
    1963             :             } else {
    1964           0 :                 print_str_opt("parent_context", "N/A");
    1965           0 :                 print_str_opt("parent_category", "N/A");
    1966             :             }
    1967           0 :             print_str("message", log_buffer[i].log_message);
    1968           0 :             writer_print_section_footer(w);
    1969             :         }
    1970             :     }
    1971           0 :     clear_log(0);
    1972           0 :     pthread_mutex_unlock(&log_mutex);
    1973             : 
    1974           0 :     writer_print_section_footer(w);
    1975             : 
    1976           0 :     return 0;
    1977             : }
    1978             : 
    1979        3586 : static void show_packet(WriterContext *w, InputFile *ifile, AVPacket *pkt, int packet_idx)
    1980             : {
    1981             :     char val_str[128];
    1982        3586 :     AVStream *st = ifile->streams[pkt->stream_index].st;
    1983             :     AVBPrint pbuf;
    1984             :     const char *s;
    1985             : 
    1986        3586 :     av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
    1987             : 
    1988        3586 :     writer_print_section_header(w, SECTION_ID_PACKET);
    1989             : 
    1990        3586 :     s = av_get_media_type_string(st->codecpar->codec_type);
    1991        3586 :     if (s) print_str    ("codec_type", s);
    1992           0 :     else   print_str_opt("codec_type", "unknown");
    1993        3586 :     print_int("stream_index",     pkt->stream_index);
    1994        3586 :     print_ts  ("pts",             pkt->pts);
    1995        3586 :     print_time("pts_time",        pkt->pts, &st->time_base);
    1996        3586 :     print_ts  ("dts",             pkt->dts);
    1997        3586 :     print_time("dts_time",        pkt->dts, &st->time_base);
    1998        3586 :     print_duration_ts("duration",        pkt->duration);
    1999        3586 :     print_duration_time("duration_time", pkt->duration, &st->time_base);
    2000        3586 :     print_duration_ts("convergence_duration", pkt->convergence_duration);
    2001        3586 :     print_duration_time("convergence_duration_time", pkt->convergence_duration, &st->time_base);
    2002        3586 :     print_val("size",             pkt->size, unit_byte_str);
    2003        3586 :     if (pkt->pos != -1) print_fmt    ("pos", "%"PRId64, pkt->pos);
    2004          82 :     else                print_str_opt("pos", "N/A");
    2005        3586 :     print_fmt("flags", "%c%c",      pkt->flags & AV_PKT_FLAG_KEY ? 'K' : '_',
    2006             :               pkt->flags & AV_PKT_FLAG_DISCARD ? 'D' : '_');
    2007             : 
    2008        3586 :     if (pkt->side_data_elems) {
    2009             :         int size;
    2010             :         const uint8_t *side_metadata;
    2011             : 
    2012         200 :         side_metadata = av_packet_get_side_data(pkt, AV_PKT_DATA_STRINGS_METADATA, &size);
    2013         200 :         if (side_metadata && size && do_show_packet_tags) {
    2014         131 :             AVDictionary *dict = NULL;
    2015         131 :             if (av_packet_unpack_dictionary(side_metadata, size, &dict) >= 0)
    2016         131 :                 show_tags(w, dict, SECTION_ID_PACKET_TAGS);
    2017         131 :             av_dict_free(&dict);
    2018             :         }
    2019             : 
    2020         200 :         print_pkt_side_data(w, st->codecpar, pkt->side_data, pkt->side_data_elems,
    2021             :                             SECTION_ID_PACKET_SIDE_DATA_LIST,
    2022             :                             SECTION_ID_PACKET_SIDE_DATA);
    2023             :     }
    2024             : 
    2025        3586 :     if (do_show_data)
    2026           0 :         writer_print_data(w, "data", pkt->data, pkt->size);
    2027        3586 :     writer_print_data_hash(w, "data_hash", pkt->data, pkt->size);
    2028        3586 :     writer_print_section_footer(w);
    2029             : 
    2030        3586 :     av_bprint_finalize(&pbuf, NULL);
    2031        3586 :     fflush(stdout);
    2032        3586 : }
    2033             : 
    2034           0 : static void show_subtitle(WriterContext *w, AVSubtitle *sub, AVStream *stream,
    2035             :                           AVFormatContext *fmt_ctx)
    2036             : {
    2037             :     AVBPrint pbuf;
    2038             : 
    2039           0 :     av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
    2040             : 
    2041           0 :     writer_print_section_header(w, SECTION_ID_SUBTITLE);
    2042             : 
    2043           0 :     print_str ("media_type",         "subtitle");
    2044           0 :     print_ts  ("pts",                 sub->pts);
    2045           0 :     print_time("pts_time",            sub->pts, &AV_TIME_BASE_Q);
    2046           0 :     print_int ("format",              sub->format);
    2047           0 :     print_int ("start_display_time",  sub->start_display_time);
    2048           0 :     print_int ("end_display_time",    sub->end_display_time);
    2049           0 :     print_int ("num_rects",           sub->num_rects);
    2050             : 
    2051           0 :     writer_print_section_footer(w);
    2052             : 
    2053           0 :     av_bprint_finalize(&pbuf, NULL);
    2054           0 :     fflush(stdout);
    2055           0 : }
    2056             : 
    2057        3252 : static void show_frame(WriterContext *w, AVFrame *frame, AVStream *stream,
    2058             :                        AVFormatContext *fmt_ctx)
    2059             : {
    2060             :     AVBPrint pbuf;
    2061             :     char val_str[128];
    2062             :     const char *s;
    2063             :     int i;
    2064             : 
    2065        3252 :     av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
    2066             : 
    2067        3252 :     writer_print_section_header(w, SECTION_ID_FRAME);
    2068             : 
    2069        3252 :     s = av_get_media_type_string(stream->codecpar->codec_type);
    2070        3252 :     if (s) print_str    ("media_type", s);
    2071           0 :     else   print_str_opt("media_type", "unknown");
    2072        3252 :     print_int("stream_index",           stream->index);
    2073        3252 :     print_int("key_frame",              frame->key_frame);
    2074        3252 :     print_ts  ("pkt_pts",               frame->pts);
    2075        3252 :     print_time("pkt_pts_time",          frame->pts, &stream->time_base);
    2076        3252 :     print_ts  ("pkt_dts",               frame->pkt_dts);
    2077        3252 :     print_time("pkt_dts_time",          frame->pkt_dts, &stream->time_base);
    2078        3252 :     print_ts  ("best_effort_timestamp", frame->best_effort_timestamp);
    2079        3252 :     print_time("best_effort_timestamp_time", frame->best_effort_timestamp, &stream->time_base);
    2080        3252 :     print_duration_ts  ("pkt_duration",      frame->pkt_duration);
    2081        3252 :     print_duration_time("pkt_duration_time", frame->pkt_duration, &stream->time_base);
    2082        3252 :     if (frame->pkt_pos != -1) print_fmt    ("pkt_pos", "%"PRId64, frame->pkt_pos);
    2083          49 :     else                      print_str_opt("pkt_pos", "N/A");
    2084        3252 :     if (frame->pkt_size != -1) print_val    ("pkt_size", frame->pkt_size, unit_byte_str);
    2085           0 :     else                       print_str_opt("pkt_size", "N/A");
    2086             : 
    2087        3252 :     switch (stream->codecpar->codec_type) {
    2088             :         AVRational sar;
    2089             : 
    2090         182 :     case AVMEDIA_TYPE_VIDEO:
    2091         182 :         print_int("width",                  frame->width);
    2092         182 :         print_int("height",                 frame->height);
    2093         182 :         s = av_get_pix_fmt_name(frame->format);
    2094         182 :         if (s) print_str    ("pix_fmt", s);
    2095           0 :         else   print_str_opt("pix_fmt", "unknown");
    2096         182 :         sar = av_guess_sample_aspect_ratio(fmt_ctx, stream, frame);
    2097         182 :         if (sar.num) {
    2098         181 :             print_q("sample_aspect_ratio", sar, ':');
    2099             :         } else {
    2100           1 :             print_str_opt("sample_aspect_ratio", "N/A");
    2101             :         }
    2102         182 :         print_fmt("pict_type",              "%c", av_get_picture_type_char(frame->pict_type));
    2103         182 :         print_int("coded_picture_number",   frame->coded_picture_number);
    2104         182 :         print_int("display_picture_number", frame->display_picture_number);
    2105         182 :         print_int("interlaced_frame",       frame->interlaced_frame);
    2106         182 :         print_int("top_field_first",        frame->top_field_first);
    2107         182 :         print_int("repeat_pict",            frame->repeat_pict);
    2108         182 :         break;
    2109             : 
    2110        3070 :     case AVMEDIA_TYPE_AUDIO:
    2111        3070 :         s = av_get_sample_fmt_name(frame->format);
    2112        3070 :         if (s) print_str    ("sample_fmt", s);
    2113           0 :         else   print_str_opt("sample_fmt", "unknown");
    2114        3070 :         print_int("nb_samples",         frame->nb_samples);
    2115        3070 :         print_int("channels", frame->channels);
    2116        3070 :         if (frame->channel_layout) {
    2117        2852 :             av_bprint_clear(&pbuf);
    2118        2852 :             av_bprint_channel_layout(&pbuf, frame->channels,
    2119             :                                      frame->channel_layout);
    2120        2852 :             print_str    ("channel_layout", pbuf.str);
    2121             :         } else
    2122         218 :             print_str_opt("channel_layout", "unknown");
    2123        3070 :         break;
    2124             :     }
    2125        3252 :     if (do_show_frame_tags)
    2126        1271 :         show_tags(w, frame->metadata, SECTION_ID_FRAME_TAGS);
    2127        3252 :     if (do_show_log)
    2128           0 :         show_log(w, SECTION_ID_FRAME_LOGS, SECTION_ID_FRAME_LOG, do_show_log);
    2129        3252 :     if (frame->nb_side_data) {
    2130           0 :         writer_print_section_header(w, SECTION_ID_FRAME_SIDE_DATA_LIST);
    2131           0 :         for (i = 0; i < frame->nb_side_data; i++) {
    2132           0 :             AVFrameSideData *sd = frame->side_data[i];
    2133             :             const char *name;
    2134             : 
    2135           0 :             writer_print_section_header(w, SECTION_ID_FRAME_SIDE_DATA);
    2136           0 :             name = av_frame_side_data_name(sd->type);
    2137           0 :             print_str("side_data_type", name ? name : "unknown");
    2138           0 :             if (sd->type == AV_FRAME_DATA_DISPLAYMATRIX && sd->size >= 9*4) {
    2139           0 :                 writer_print_integers(w, "displaymatrix", sd->data, 9, " %11d", 3, 4, 1);
    2140           0 :                 print_int("rotation", av_display_rotation_get((int32_t *)sd->data));
    2141           0 :             } else if (sd->type == AV_FRAME_DATA_GOP_TIMECODE && sd->size >= 8) {
    2142             :                 char tcbuf[AV_TIMECODE_STR_SIZE];
    2143           0 :                 av_timecode_make_mpeg_tc_string(tcbuf, *(int64_t *)(sd->data));
    2144           0 :                 print_str("timecode", tcbuf);
    2145           0 :             } else if (sd->type == AV_FRAME_DATA_MASTERING_DISPLAY_METADATA) {
    2146           0 :                 AVMasteringDisplayMetadata *metadata = (AVMasteringDisplayMetadata *)sd->data;
    2147             : 
    2148           0 :                 if (metadata->has_primaries) {
    2149           0 :                     print_q("red_x", metadata->display_primaries[0][0], '/');
    2150           0 :                     print_q("red_y", metadata->display_primaries[0][1], '/');
    2151           0 :                     print_q("green_x", metadata->display_primaries[1][0], '/');
    2152           0 :                     print_q("green_y", metadata->display_primaries[1][1], '/');
    2153           0 :                     print_q("blue_x", metadata->display_primaries[2][0], '/');
    2154           0 :                     print_q("blue_y", metadata->display_primaries[2][1], '/');
    2155             : 
    2156           0 :                     print_q("white_point_x", metadata->white_point[0], '/');
    2157           0 :                     print_q("white_point_y", metadata->white_point[1], '/');
    2158             :                 }
    2159             : 
    2160           0 :                 if (metadata->has_luminance) {
    2161           0 :                     print_q("min_luminance", metadata->min_luminance, '/');
    2162           0 :                     print_q("max_luminance", metadata->max_luminance, '/');
    2163             :                 }
    2164           0 :             } else if (sd->type == AV_FRAME_DATA_CONTENT_LIGHT_LEVEL) {
    2165           0 :                 AVContentLightMetadata *metadata = (AVContentLightMetadata *)sd->data;
    2166           0 :                 print_int("max_content", metadata->MaxCLL);
    2167           0 :                 print_int("max_average", metadata->MaxFALL);
    2168             :             }
    2169           0 :             writer_print_section_footer(w);
    2170             :         }
    2171           0 :         writer_print_section_footer(w);
    2172             :     }
    2173             : 
    2174        3252 :     writer_print_section_footer(w);
    2175             : 
    2176        3252 :     av_bprint_finalize(&pbuf, NULL);
    2177        3252 :     fflush(stdout);
    2178        3252 : }
    2179             : 
    2180        6394 : static av_always_inline int process_frame(WriterContext *w,
    2181             :                                           InputFile *ifile,
    2182             :                                           AVFrame *frame, AVPacket *pkt,
    2183             :                                           int *packet_new)
    2184             : {
    2185        6394 :     AVFormatContext *fmt_ctx = ifile->fmt_ctx;
    2186        6394 :     AVCodecContext *dec_ctx = ifile->streams[pkt->stream_index].dec_ctx;
    2187        6394 :     AVCodecParameters *par = ifile->streams[pkt->stream_index].st->codecpar;
    2188             :     AVSubtitle sub;
    2189        6394 :     int ret = 0, got_frame = 0;
    2190             : 
    2191        6394 :     clear_log(1);
    2192        6394 :     if (dec_ctx && dec_ctx->codec) {
    2193        6394 :         switch (par->codec_type) {
    2194        6394 :         case AVMEDIA_TYPE_VIDEO:
    2195             :         case AVMEDIA_TYPE_AUDIO:
    2196        6394 :             if (*packet_new) {
    2197        3143 :                 ret = avcodec_send_packet(dec_ctx, pkt);
    2198        3143 :                 if (ret == AVERROR(EAGAIN)) {
    2199           0 :                     ret = 0;
    2200        3143 :                 } else if (ret >= 0 || ret == AVERROR_EOF) {
    2201        3141 :                     ret = 0;
    2202        3141 :                     *packet_new = 0;
    2203             :                 }
    2204             :             }
    2205        6394 :             if (ret >= 0) {
    2206        6392 :                 ret = avcodec_receive_frame(dec_ctx, frame);
    2207        6392 :                 if (ret >= 0) {
    2208        3252 :                     got_frame = 1;
    2209        3140 :                 } else if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
    2210        3140 :                     ret = 0;
    2211             :                 }
    2212             :             }
    2213        6394 :             break;
    2214             : 
    2215           0 :         case AVMEDIA_TYPE_SUBTITLE:
    2216           0 :             ret = avcodec_decode_subtitle2(dec_ctx, &sub, &got_frame, pkt);
    2217           0 :             *packet_new = 0;
    2218           0 :             break;
    2219           0 :         default:
    2220           0 :             *packet_new = 0;
    2221             :         }
    2222        6394 :     } else {
    2223           0 :         *packet_new = 0;
    2224             :     }
    2225             : 
    2226        6394 :     if (ret < 0)
    2227           2 :         return ret;
    2228        6392 :     if (got_frame) {
    2229        3252 :         int is_sub = (par->codec_type == AVMEDIA_TYPE_SUBTITLE);
    2230        3252 :         nb_streams_frames[pkt->stream_index]++;
    2231        3252 :         if (do_show_frames)
    2232        3252 :             if (is_sub)
    2233           0 :                 show_subtitle(w, &sub, ifile->streams[pkt->stream_index].st, fmt_ctx);
    2234             :             else
    2235        3252 :                 show_frame(w, frame, ifile->streams[pkt->stream_index].st, fmt_ctx);
    2236        3252 :         if (is_sub)
    2237           0 :             avsubtitle_free(&sub);
    2238             :     }
    2239        6392 :     return got_frame || *packet_new;
    2240             : }
    2241             : 
    2242          37 : static void log_read_interval(const ReadInterval *interval, void *log_ctx, int log_level)
    2243             : {
    2244          37 :     av_log(log_ctx, log_level, "id:%d", interval->id);
    2245             : 
    2246          37 :     if (interval->has_start) {
    2247           0 :         av_log(log_ctx, log_level, " start:%s%s", interval->start_is_offset ? "+" : "",
    2248           0 :                av_ts2timestr(interval->start, &AV_TIME_BASE_Q));
    2249             :     } else {
    2250          37 :         av_log(log_ctx, log_level, " start:N/A");
    2251             :     }
    2252             : 
    2253          37 :     if (interval->has_end) {
    2254           0 :         av_log(log_ctx, log_level, " end:%s", interval->end_is_offset ? "+" : "");
    2255           0 :         if (interval->duration_frames)
    2256           0 :             av_log(log_ctx, log_level, "#%"PRId64, interval->end);
    2257             :         else
    2258           0 :             av_log(log_ctx, log_level, "%s", av_ts2timestr(interval->end, &AV_TIME_BASE_Q));
    2259             :     } else {
    2260          37 :         av_log(log_ctx, log_level, " end:N/A");
    2261             :     }
    2262             : 
    2263          37 :     av_log(log_ctx, log_level, "\n");
    2264          37 : }
    2265             : 
    2266          37 : static int read_interval_packets(WriterContext *w, InputFile *ifile,
    2267             :                                  const ReadInterval *interval, int64_t *cur_ts)
    2268             : {
    2269          37 :     AVFormatContext *fmt_ctx = ifile->fmt_ctx;
    2270             :     AVPacket pkt;
    2271          37 :     AVFrame *frame = NULL;
    2272          37 :     int ret = 0, i = 0, frame_count = 0;
    2273          37 :     int64_t start = -INT64_MAX, end = interval->end;
    2274          37 :     int has_start = 0, has_end = interval->has_end && !interval->end_is_offset;
    2275             : 
    2276          37 :     av_init_packet(&pkt);
    2277             : 
    2278          37 :     av_log(NULL, AV_LOG_VERBOSE, "Processing read interval ");
    2279          37 :     log_read_interval(interval, NULL, AV_LOG_VERBOSE);
    2280             : 
    2281          37 :     if (interval->has_start) {
    2282             :         int64_t target;
    2283           0 :         if (interval->start_is_offset) {
    2284           0 :             if (*cur_ts == AV_NOPTS_VALUE) {
    2285           0 :                 av_log(NULL, AV_LOG_ERROR,
    2286             :                        "Could not seek to relative position since current "
    2287             :                        "timestamp is not defined\n");
    2288           0 :                 ret = AVERROR(EINVAL);
    2289           0 :                 goto end;
    2290             :             }
    2291           0 :             target = *cur_ts + interval->start;
    2292             :         } else {
    2293           0 :             target = interval->start;
    2294             :         }
    2295             : 
    2296           0 :         av_log(NULL, AV_LOG_VERBOSE, "Seeking to read interval start point %s\n",
    2297           0 :                av_ts2timestr(target, &AV_TIME_BASE_Q));
    2298           0 :         if ((ret = avformat_seek_file(fmt_ctx, -1, -INT64_MAX, target, INT64_MAX, 0)) < 0) {
    2299           0 :             av_log(NULL, AV_LOG_ERROR, "Could not seek to position %"PRId64": %s\n",
    2300           0 :                    interval->start, av_err2str(ret));
    2301           0 :             goto end;
    2302             :         }
    2303             :     }
    2304             : 
    2305          37 :     frame = av_frame_alloc();
    2306          37 :     if (!frame) {
    2307           0 :         ret = AVERROR(ENOMEM);
    2308           0 :         goto end;
    2309             :     }
    2310        6582 :     while (!av_read_frame(fmt_ctx, &pkt)) {
    2311        6508 :         if (ifile->nb_streams > nb_streams) {
    2312           0 :             REALLOCZ_ARRAY_STREAM(nb_streams_frames,  nb_streams, fmt_ctx->nb_streams);
    2313           0 :             REALLOCZ_ARRAY_STREAM(nb_streams_packets, nb_streams, fmt_ctx->nb_streams);
    2314           0 :             REALLOCZ_ARRAY_STREAM(selected_streams,   nb_streams, fmt_ctx->nb_streams);
    2315           0 :             nb_streams = ifile->nb_streams;
    2316             :         }
    2317        6508 :         if (selected_streams[pkt.stream_index]) {
    2318        6505 :             AVRational tb = ifile->streams[pkt.stream_index].st->time_base;
    2319             : 
    2320        6505 :             if (pkt.pts != AV_NOPTS_VALUE)
    2321        6504 :                 *cur_ts = av_rescale_q(pkt.pts, tb, AV_TIME_BASE_Q);
    2322             : 
    2323        6505 :             if (!has_start && *cur_ts != AV_NOPTS_VALUE) {
    2324          37 :                 start = *cur_ts;
    2325          37 :                 has_start = 1;
    2326             :             }
    2327             : 
    2328        6505 :             if (has_start && !has_end && interval->end_is_offset) {
    2329           0 :                 end = start + interval->end;
    2330           0 :                 has_end = 1;
    2331             :             }
    2332             : 
    2333        6505 :             if (interval->end_is_offset && interval->duration_frames) {
    2334           0 :                 if (frame_count >= interval->end)
    2335           0 :                     break;
    2336        6505 :             } else if (has_end && *cur_ts != AV_NOPTS_VALUE && *cur_ts >= end) {
    2337           0 :                 break;
    2338             :             }
    2339             : 
    2340        6505 :             frame_count++;
    2341        6505 :             if (do_read_packets) {
    2342        3586 :                 if (do_show_packets)
    2343        3586 :                     show_packet(w, ifile, &pkt, i++);
    2344        3586 :                 nb_streams_packets[pkt.stream_index]++;
    2345             :             }
    2346        6505 :             if (do_read_frames) {
    2347        3100 :                 int packet_new = 1;
    2348        3100 :                 while (process_frame(w, ifile, frame, &pkt, &packet_new) > 0);
    2349             :             }
    2350             :         }
    2351        6508 :         av_packet_unref(&pkt);
    2352             :     }
    2353          37 :     av_init_packet(&pkt);
    2354          37 :     pkt.data = NULL;
    2355          37 :     pkt.size = 0;
    2356             :     //Flush remaining frames that are cached in the decoder
    2357          97 :     for (i = 0; i < fmt_ctx->nb_streams; i++) {
    2358          60 :         pkt.stream_index = i;
    2359          60 :         if (do_read_frames)
    2360          42 :             while (process_frame(w, ifile, frame, &pkt, &(int){1}) > 0);
    2361             :     }
    2362             : 
    2363          37 : end:
    2364          37 :     av_frame_free(&frame);
    2365          37 :     if (ret < 0) {
    2366           0 :         av_log(NULL, AV_LOG_ERROR, "Could not read packets in interval ");
    2367           0 :         log_read_interval(interval, NULL, AV_LOG_ERROR);
    2368             :     }
    2369          37 :     return ret;
    2370             : }
    2371             : 
    2372          37 : static int read_packets(WriterContext *w, InputFile *ifile)
    2373             : {
    2374          37 :     AVFormatContext *fmt_ctx = ifile->fmt_ctx;
    2375          37 :     int i, ret = 0;
    2376          37 :     int64_t cur_ts = fmt_ctx->start_time;
    2377             : 
    2378          37 :     if (read_intervals_nb == 0) {
    2379          37 :         ReadInterval interval = (ReadInterval) { .has_start = 0, .has_end = 0 };
    2380          37 :         ret = read_interval_packets(w, ifile, &interval, &cur_ts);
    2381             :     } else {
    2382           0 :         for (i = 0; i < read_intervals_nb; i++) {
    2383           0 :             ret = read_interval_packets(w, ifile, &read_intervals[i], &cur_ts);
    2384           0 :             if (ret < 0)
    2385           0 :                 break;
    2386             :         }
    2387             :     }
    2388             : 
    2389          37 :     return ret;
    2390             : }
    2391             : 
    2392          56 : static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_idx, InputStream *ist, int in_program)
    2393             : {
    2394          56 :     AVStream *stream = ist->st;
    2395             :     AVCodecParameters *par;
    2396             :     AVCodecContext *dec_ctx;
    2397             :     char val_str[128];
    2398             :     const char *s;
    2399             :     AVRational sar, dar;
    2400             :     AVBPrint pbuf;
    2401             :     const AVCodecDescriptor *cd;
    2402          56 :     int ret = 0;
    2403          56 :     const char *profile = NULL;
    2404             : 
    2405          56 :     av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
    2406             : 
    2407          56 :     writer_print_section_header(w, in_program ? SECTION_ID_PROGRAM_STREAM : SECTION_ID_STREAM);
    2408             : 
    2409          56 :     print_int("index", stream->index);
    2410             : 
    2411          56 :     par     = stream->codecpar;
    2412          56 :     dec_ctx = ist->dec_ctx;
    2413          56 :     if (cd = avcodec_descriptor_get(par->codec_id)) {
    2414          53 :         print_str("codec_name", cd->name);
    2415          53 :         if (!do_bitexact) {
    2416           3 :             print_str("codec_long_name",
    2417             :                       cd->long_name ? cd->long_name : "unknown");
    2418             :         }
    2419             :     } else {
    2420           3 :         print_str_opt("codec_name", "unknown");
    2421           3 :         if (!do_bitexact) {
    2422           0 :             print_str_opt("codec_long_name", "unknown");
    2423             :         }
    2424             :     }
    2425             : 
    2426          56 :     if (!do_bitexact && (profile = avcodec_profile_name(par->codec_id, par->profile)))
    2427           3 :         print_str("profile", profile);
    2428             :     else {
    2429          53 :         if (par->profile != FF_PROFILE_UNKNOWN) {
    2430             :             char profile_num[12];
    2431          20 :             snprintf(profile_num, sizeof(profile_num), "%d", par->profile);
    2432          20 :             print_str("profile", profile_num);
    2433             :         } else
    2434          33 :             print_str_opt("profile", "unknown");
    2435             :     }
    2436             : 
    2437          56 :     s = av_get_media_type_string(par->codec_type);
    2438          56 :     if (s) print_str    ("codec_type", s);
    2439           0 :     else   print_str_opt("codec_type", "unknown");
    2440             : #if FF_API_LAVF_AVCTX
    2441          56 :     if (dec_ctx)
    2442          53 :         print_q("codec_time_base", dec_ctx->time_base, '/');
    2443             : #endif
    2444             : 
    2445             :     /* print AVI/FourCC tag */
    2446          56 :     print_str("codec_tag_string",    av_fourcc2str(par->codec_tag));
    2447          56 :     print_fmt("codec_tag", "0x%04"PRIx32, par->codec_tag);
    2448             : 
    2449          56 :     switch (par->codec_type) {
    2450          26 :     case AVMEDIA_TYPE_VIDEO:
    2451          26 :         print_int("width",        par->width);
    2452          26 :         print_int("height",       par->height);
    2453          26 :         if (dec_ctx) {
    2454          26 :             print_int("coded_width",  dec_ctx->coded_width);
    2455          26 :             print_int("coded_height", dec_ctx->coded_height);
    2456             :         }
    2457          26 :         print_int("has_b_frames", par->video_delay);
    2458          26 :         sar = av_guess_sample_aspect_ratio(fmt_ctx, stream, NULL);
    2459          26 :         if (sar.den) {
    2460          26 :             print_q("sample_aspect_ratio", sar, ':');
    2461          52 :             av_reduce(&dar.num, &dar.den,
    2462          26 :                       par->width  * sar.num,
    2463          26 :                       par->height * sar.den,
    2464             :                       1024*1024);
    2465          26 :             print_q("display_aspect_ratio", dar, ':');
    2466             :         } else {
    2467           0 :             print_str_opt("sample_aspect_ratio", "N/A");
    2468           0 :             print_str_opt("display_aspect_ratio", "N/A");
    2469             :         }
    2470          26 :         s = av_get_pix_fmt_name(par->format);
    2471          26 :         if (s) print_str    ("pix_fmt", s);
    2472           0 :         else   print_str_opt("pix_fmt", "unknown");
    2473          26 :         print_int("level",   par->level);
    2474          26 :         if (par->color_range != AVCOL_RANGE_UNSPECIFIED)
    2475           8 :             print_str    ("color_range", av_color_range_name(par->color_range));
    2476             :         else
    2477          18 :             print_str_opt("color_range", "N/A");
    2478             : 
    2479          26 :         if (par->color_space != AVCOL_SPC_UNSPECIFIED)
    2480           3 :             print_str("color_space", av_color_space_name(par->color_space));
    2481             :         else
    2482          23 :             print_str_opt("color_space", av_color_space_name(par->color_space));
    2483             : 
    2484          26 :         if (par->color_trc != AVCOL_TRC_UNSPECIFIED)
    2485           2 :             print_str("color_transfer", av_color_transfer_name(par->color_trc));
    2486             :         else
    2487          24 :             print_str_opt("color_transfer", av_color_transfer_name(par->color_trc));
    2488             : 
    2489          26 :         if (par->color_primaries != AVCOL_PRI_UNSPECIFIED)
    2490           2 :             print_str("color_primaries", av_color_primaries_name(par->color_primaries));
    2491             :         else
    2492          24 :             print_str_opt("color_primaries", av_color_primaries_name(par->color_primaries));
    2493             : 
    2494          26 :         if (par->chroma_location != AVCHROMA_LOC_UNSPECIFIED)
    2495          11 :             print_str("chroma_location", av_chroma_location_name(par->chroma_location));
    2496             :         else
    2497          15 :             print_str_opt("chroma_location", av_chroma_location_name(par->chroma_location));
    2498             : 
    2499          26 :         if (par->field_order == AV_FIELD_PROGRESSIVE)
    2500           5 :             print_str("field_order", "progressive");
    2501          21 :         else if (par->field_order == AV_FIELD_TT)
    2502           3 :             print_str("field_order", "tt");
    2503          18 :         else if (par->field_order == AV_FIELD_BB)
    2504           1 :             print_str("field_order", "bb");
    2505          17 :         else if (par->field_order == AV_FIELD_TB)
    2506           0 :             print_str("field_order", "tb");
    2507          17 :         else if (par->field_order == AV_FIELD_BT)
    2508           0 :             print_str("field_order", "bt");
    2509             :         else
    2510          17 :             print_str_opt("field_order", "unknown");
    2511             : 
    2512             : #if FF_API_PRIVATE_OPT
    2513          26 :         if (dec_ctx && dec_ctx->timecode_frame_start >= 0) {
    2514             :             char tcbuf[AV_TIMECODE_STR_SIZE];
    2515           0 :             av_timecode_make_mpeg_tc_string(tcbuf, dec_ctx->timecode_frame_start);
    2516           0 :             print_str("timecode", tcbuf);
    2517             :         } else {
    2518          26 :             print_str_opt("timecode", "N/A");
    2519             :         }
    2520             : #endif
    2521          26 :         if (dec_ctx)
    2522          26 :             print_int("refs", dec_ctx->refs);
    2523          26 :         break;
    2524             : 
    2525          27 :     case AVMEDIA_TYPE_AUDIO:
    2526          27 :         s = av_get_sample_fmt_name(par->format);
    2527          27 :         if (s) print_str    ("sample_fmt", s);
    2528           0 :         else   print_str_opt("sample_fmt", "unknown");
    2529          27 :         print_val("sample_rate",     par->sample_rate, unit_hertz_str);
    2530          27 :         print_int("channels",        par->channels);
    2531             : 
    2532          27 :         if (par->channel_layout) {
    2533          13 :             av_bprint_clear(&pbuf);
    2534          13 :             av_bprint_channel_layout(&pbuf, par->channels, par->channel_layout);
    2535          13 :             print_str    ("channel_layout", pbuf.str);
    2536             :         } else {
    2537          14 :             print_str_opt("channel_layout", "unknown");
    2538             :         }
    2539             : 
    2540          27 :         print_int("bits_per_sample", av_get_bits_per_sample(par->codec_id));
    2541          27 :         break;
    2542             : 
    2543           0 :     case AVMEDIA_TYPE_SUBTITLE:
    2544           0 :         if (par->width)
    2545           0 :             print_int("width",       par->width);
    2546             :         else
    2547           0 :             print_str_opt("width",   "N/A");
    2548           0 :         if (par->height)
    2549           0 :             print_int("height",      par->height);
    2550             :         else
    2551           0 :             print_str_opt("height",  "N/A");
    2552           0 :         break;
    2553             :     }
    2554             : 
    2555          56 :     if (dec_ctx && dec_ctx->codec && dec_ctx->codec->priv_class && show_private_data) {
    2556          30 :         const AVOption *opt = NULL;
    2557         146 :         while (opt = av_opt_next(dec_ctx->priv_data,opt)) {
    2558             :             uint8_t *str;
    2559          86 :             if (opt->flags) continue;
    2560           8 :             if (av_opt_get(dec_ctx->priv_data, opt->name, 0, &str) >= 0) {
    2561           8 :                 print_str(opt->name, str);
    2562           8 :                 av_free(str);
    2563             :             }
    2564             :         }
    2565             :     }
    2566             : 
    2567          56 :     if (fmt_ctx->iformat->flags & AVFMT_SHOW_IDS) print_fmt    ("id", "0x%x", stream->id);
    2568          56 :     else                                          print_str_opt("id", "N/A");
    2569          56 :     print_q("r_frame_rate",   stream->r_frame_rate,   '/');
    2570          56 :     print_q("avg_frame_rate", stream->avg_frame_rate, '/');
    2571          56 :     print_q("time_base",      stream->time_base,      '/');
    2572          56 :     print_ts  ("start_pts",   stream->start_time);
    2573          56 :     print_time("start_time",  stream->start_time, &stream->time_base);
    2574          56 :     print_ts  ("duration_ts", stream->duration);
    2575          56 :     print_time("duration",    stream->duration, &stream->time_base);
    2576          56 :     if (par->bit_rate > 0)     print_val    ("bit_rate", par->bit_rate, unit_bit_per_second_str);
    2577          23 :     else                       print_str_opt("bit_rate", "N/A");
    2578             : #if FF_API_LAVF_AVCTX
    2579          56 :     if (stream->codec->rc_max_rate > 0) print_val ("max_bit_rate", stream->codec->rc_max_rate, unit_bit_per_second_str);
    2580          44 :     else                                print_str_opt("max_bit_rate", "N/A");
    2581             : #endif
    2582          56 :     if (dec_ctx && dec_ctx->bits_per_raw_sample > 0) print_fmt("bits_per_raw_sample", "%d", dec_ctx->bits_per_raw_sample);
    2583          51 :     else                                             print_str_opt("bits_per_raw_sample", "N/A");
    2584          56 :     if (stream->nb_frames) print_fmt    ("nb_frames", "%"PRId64, stream->nb_frames);
    2585          41 :     else                   print_str_opt("nb_frames", "N/A");
    2586          56 :     if (nb_streams_frames[stream_idx])  print_fmt    ("nb_read_frames", "%"PRIu64, nb_streams_frames[stream_idx]);
    2587          30 :     else                                print_str_opt("nb_read_frames", "N/A");
    2588          56 :     if (nb_streams_packets[stream_idx]) print_fmt    ("nb_read_packets", "%"PRIu64, nb_streams_packets[stream_idx]);
    2589          20 :     else                                print_str_opt("nb_read_packets", "N/A");
    2590          56 :     if (do_show_data)
    2591           0 :         writer_print_data(w, "extradata", par->extradata,
    2592             :                                           par->extradata_size);
    2593          56 :     writer_print_data_hash(w, "extradata_hash", par->extradata,
    2594             :                                                 par->extradata_size);
    2595             : 
    2596             :     /* Print disposition information */
    2597             : #define PRINT_DISPOSITION(flagname, name) do {                                \
    2598             :         print_int(name, !!(stream->disposition & AV_DISPOSITION_##flagname)); \
    2599             :     } while (0)
    2600             : 
    2601          56 :     if (do_show_stream_disposition) {
    2602          41 :     writer_print_section_header(w, in_program ? SECTION_ID_PROGRAM_STREAM_DISPOSITION : SECTION_ID_STREAM_DISPOSITION);
    2603          41 :     PRINT_DISPOSITION(DEFAULT,          "default");
    2604          41 :     PRINT_DISPOSITION(DUB,              "dub");
    2605          41 :     PRINT_DISPOSITION(ORIGINAL,         "original");
    2606          41 :     PRINT_DISPOSITION(COMMENT,          "comment");
    2607          41 :     PRINT_DISPOSITION(LYRICS,           "lyrics");
    2608          41 :     PRINT_DISPOSITION(KARAOKE,          "karaoke");
    2609          41 :     PRINT_DISPOSITION(FORCED,           "forced");
    2610          41 :     PRINT_DISPOSITION(HEARING_IMPAIRED, "hearing_impaired");
    2611          41 :     PRINT_DISPOSITION(VISUAL_IMPAIRED,  "visual_impaired");
    2612          41 :     PRINT_DISPOSITION(CLEAN_EFFECTS,    "clean_effects");
    2613          41 :     PRINT_DISPOSITION(ATTACHED_PIC,     "attached_pic");
    2614          41 :     PRINT_DISPOSITION(TIMED_THUMBNAILS, "timed_thumbnails");
    2615          41 :     writer_print_section_footer(w);
    2616             :     }
    2617             : 
    2618          56 :     if (do_show_stream_tags)
    2619          41 :         ret = show_tags(w, stream->metadata, in_program ? SECTION_ID_PROGRAM_STREAM_TAGS : SECTION_ID_STREAM_TAGS);
    2620             : 
    2621          56 :     if (stream->nb_side_data) {
    2622           4 :         print_pkt_side_data(w, stream->codecpar, stream->side_data, stream->nb_side_data,
    2623             :                             SECTION_ID_STREAM_SIDE_DATA_LIST,
    2624             :                             SECTION_ID_STREAM_SIDE_DATA);
    2625             :     }
    2626             : 
    2627          56 :     writer_print_section_footer(w);
    2628          56 :     av_bprint_finalize(&pbuf, NULL);
    2629          56 :     fflush(stdout);
    2630             : 
    2631          56 :     return ret;
    2632             : }
    2633             : 
    2634          31 : static int show_streams(WriterContext *w, InputFile *ifile)
    2635             : {
    2636          31 :     AVFormatContext *fmt_ctx = ifile->fmt_ctx;
    2637          31 :     int i, ret = 0;
    2638             : 
    2639          31 :     writer_print_section_header(w, SECTION_ID_STREAMS);
    2640          90 :     for (i = 0; i < ifile->nb_streams; i++)
    2641          59 :         if (selected_streams[i]) {
    2642          56 :             ret = show_stream(w, fmt_ctx, i, &ifile->streams[i], 0);
    2643          56 :             if (ret < 0)
    2644           0 :                 break;
    2645             :         }
    2646          31 :     writer_print_section_footer(w);
    2647             : 
    2648          31 :     return ret;
    2649             : }
    2650             : 
    2651           0 : static int show_program(WriterContext *w, InputFile *ifile, AVProgram *program)
    2652             : {
    2653           0 :     AVFormatContext *fmt_ctx = ifile->fmt_ctx;
    2654           0 :     int i, ret = 0;
    2655             : 
    2656           0 :     writer_print_section_header(w, SECTION_ID_PROGRAM);
    2657           0 :     print_int("program_id", program->id);
    2658           0 :     print_int("program_num", program->program_num);
    2659           0 :     print_int("nb_streams", program->nb_stream_indexes);
    2660           0 :     print_int("pmt_pid", program->pmt_pid);
    2661           0 :     print_int("pcr_pid", program->pcr_pid);
    2662           0 :     print_ts("start_pts", program->start_time);
    2663           0 :     print_time("start_time", program->start_time, &AV_TIME_BASE_Q);
    2664           0 :     print_ts("end_pts", program->end_time);
    2665           0 :     print_time("end_time", program->end_time, &AV_TIME_BASE_Q);
    2666           0 :     if (do_show_program_tags)
    2667           0 :         ret = show_tags(w, program->metadata, SECTION_ID_PROGRAM_TAGS);
    2668           0 :     if (ret < 0)
    2669           0 :         goto end;
    2670             : 
    2671           0 :     writer_print_section_header(w, SECTION_ID_PROGRAM_STREAMS);
    2672           0 :     for (i = 0; i < program->nb_stream_indexes; i++) {
    2673           0 :         if (selected_streams[program->stream_index[i]]) {
    2674           0 :             ret = show_stream(w, fmt_ctx, program->stream_index[i], &ifile->streams[program->stream_index[i]], 1);
    2675           0 :             if (ret < 0)
    2676           0 :                 break;
    2677             :         }
    2678             :     }
    2679           0 :     writer_print_section_footer(w);
    2680             : 
    2681           0 : end:
    2682           0 :     writer_print_section_footer(w);
    2683           0 :     return ret;
    2684             : }
    2685             : 
    2686          16 : static int show_programs(WriterContext *w, InputFile *ifile)
    2687             : {
    2688          16 :     AVFormatContext *fmt_ctx = ifile->fmt_ctx;
    2689          16 :     int i, ret = 0;
    2690             : 
    2691          16 :     writer_print_section_header(w, SECTION_ID_PROGRAMS);
    2692          16 :     for (i = 0; i < fmt_ctx->nb_programs; i++) {
    2693           0 :         AVProgram *program = fmt_ctx->programs[i];
    2694           0 :         if (!program)
    2695           0 :             continue;
    2696           0 :         ret = show_program(w, ifile, program);
    2697           0 :         if (ret < 0)
    2698           0 :             break;
    2699             :     }
    2700          16 :     writer_print_section_footer(w);
    2701          16 :     return ret;
    2702             : }
    2703             : 
    2704           1 : static int show_chapters(WriterContext *w, InputFile *ifile)
    2705             : {
    2706           1 :     AVFormatContext *fmt_ctx = ifile->fmt_ctx;
    2707           1 :     int i, ret = 0;
    2708             : 
    2709           1 :     writer_print_section_header(w, SECTION_ID_CHAPTERS);
    2710           5 :     for (i = 0; i < fmt_ctx->nb_chapters; i++) {
    2711           4 :         AVChapter *chapter = fmt_ctx->chapters[i];
    2712             : 
    2713           4 :         writer_print_section_header(w, SECTION_ID_CHAPTER);
    2714           4 :         print_int("id", chapter->id);
    2715           4 :         print_q  ("time_base", chapter->time_base, '/');
    2716           4 :         print_int("start", chapter->start);
    2717           4 :         print_time("start_time", chapter->start, &chapter->time_base);
    2718           4 :         print_int("end", chapter->end);
    2719           4 :         print_time("end_time", chapter->end, &chapter->time_base);
    2720           4 :         if (do_show_chapter_tags)
    2721           4 :             ret = show_tags(w, chapter->metadata, SECTION_ID_CHAPTER_TAGS);
    2722           4 :         writer_print_section_footer(w);
    2723             :     }
    2724           1 :     writer_print_section_footer(w);
    2725             : 
    2726           1 :     return ret;
    2727             : }
    2728             : 
    2729          18 : static int show_format(WriterContext *w, InputFile *ifile)
    2730             : {
    2731          18 :     AVFormatContext *fmt_ctx = ifile->fmt_ctx;
    2732             :     char val_str[128];
    2733          18 :     int64_t size = fmt_ctx->pb ? avio_size(fmt_ctx->pb) : -1;
    2734          18 :     int ret = 0;
    2735             : 
    2736          18 :     writer_print_section_header(w, SECTION_ID_FORMAT);
    2737          18 :     print_str_validate("filename", fmt_ctx->filename);
    2738          18 :     print_int("nb_streams",       fmt_ctx->nb_streams);
    2739          18 :     print_int("nb_programs",      fmt_ctx->nb_programs);
    2740          18 :     print_str("format_name",      fmt_ctx->iformat->name);
    2741          18 :     if (!do_bitexact) {
    2742           4 :         if (fmt_ctx->iformat->long_name) print_str    ("format_long_name", fmt_ctx->iformat->long_name);
    2743           0 :         else                             print_str_opt("format_long_name", "unknown");
    2744             :     }
    2745          18 :     print_time("start_time",      fmt_ctx->start_time, &AV_TIME_BASE_Q);
    2746          18 :     print_time("duration",        fmt_ctx->duration,   &AV_TIME_BASE_Q);
    2747          18 :     if (size >= 0) print_val    ("size", size, unit_byte_str);
    2748           0 :     else           print_str_opt("size", "N/A");
    2749          18 :     if (fmt_ctx->bit_rate > 0) print_val    ("bit_rate", fmt_ctx->bit_rate, unit_bit_per_second_str);
    2750           0 :     else                       print_str_opt("bit_rate", "N/A");
    2751          18 :     print_int("probe_score", av_format_get_probe_score(fmt_ctx));
    2752          18 :     if (do_show_format_tags)
    2753          10 :         ret = show_tags(w, fmt_ctx->metadata, SECTION_ID_FORMAT_TAGS);
    2754             : 
    2755          18 :     writer_print_section_footer(w);
    2756          18 :     fflush(stdout);
    2757          18 :     return ret;
    2758             : }
    2759             : 
    2760           0 : static void show_error(WriterContext *w, int err)
    2761             : {
    2762             :     char errbuf[128];
    2763           0 :     const char *errbuf_ptr = errbuf;
    2764             : 
    2765           0 :     if (av_strerror(err, errbuf, sizeof(errbuf)) < 0)
    2766           0 :         errbuf_ptr = strerror(AVUNERROR(err));
    2767             : 
    2768           0 :     writer_print_section_header(w, SECTION_ID_ERROR);
    2769           0 :     print_int("code", err);
    2770           0 :     print_str("string", errbuf_ptr);
    2771           0 :     writer_print_section_footer(w);
    2772           0 : }
    2773             : 
    2774          52 : static int open_input_file(InputFile *ifile, const char *filename)
    2775             : {
    2776             :     int err, i;
    2777          52 :     AVFormatContext *fmt_ctx = NULL;
    2778             :     AVDictionaryEntry *t;
    2779          52 :     int scan_all_pmts_set = 0;
    2780             : 
    2781          52 :     fmt_ctx = avformat_alloc_context();
    2782          52 :     if (!fmt_ctx) {
    2783           0 :         print_error(filename, AVERROR(ENOMEM));
    2784           0 :         exit_program(1);
    2785             :     }
    2786             : 
    2787          52 :     fmt_ctx->flags |= AVFMT_FLAG_KEEP_SIDE_DATA;
    2788             : 
    2789          52 :     if (!av_dict_get(format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE)) {
    2790          52 :         av_dict_set(&format_opts, "scan_all_pmts", "1", AV_DICT_DONT_OVERWRITE);
    2791          52 :         scan_all_pmts_set = 1;
    2792             :     }
    2793          52 :     if ((err = avformat_open_input(&fmt_ctx, filename,
    2794             :                                    iformat, &format_opts)) < 0) {
    2795           0 :         print_error(filename, err);
    2796           0 :         return err;
    2797             :     }
    2798          52 :     ifile->fmt_ctx = fmt_ctx;
    2799          52 :     if (scan_all_pmts_set)
    2800          52 :         av_dict_set(&format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE);
    2801          52 :     if ((t = av_dict_get(format_opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
    2802           0 :         av_log(NULL, AV_LOG_ERROR, "Option %s not found.\n", t->key);
    2803           0 :         return AVERROR_OPTION_NOT_FOUND;
    2804             :     }
    2805             : 
    2806          52 :     if (find_stream_info) {
    2807          52 :         AVDictionary **opts = setup_find_stream_info_opts(fmt_ctx, codec_opts);
    2808          52 :         int orig_nb_streams = fmt_ctx->nb_streams;
    2809             : 
    2810          52 :         err = avformat_find_stream_info(fmt_ctx, opts);
    2811             : 
    2812         132 :         for (i = 0; i < orig_nb_streams; i++)
    2813          80 :             av_dict_free(&opts[i]);
    2814          52 :         av_freep(&opts);
    2815             : 
    2816          52 :         if (err < 0) {
    2817           0 :             print_error(filename, err);
    2818           0 :             return err;
    2819             :         }
    2820             :     }
    2821             : 
    2822          52 :     av_dump_format(fmt_ctx, 0, filename, 0);
    2823             : 
    2824          52 :     ifile->streams = av_mallocz_array(fmt_ctx->nb_streams,
    2825             :                                       sizeof(*ifile->streams));
    2826          52 :     if (!ifile->streams)
    2827           0 :         exit(1);
    2828          52 :     ifile->nb_streams = fmt_ctx->nb_streams;
    2829             : 
    2830             :     /* bind a decoder to each input stream */
    2831         137 :     for (i = 0; i < fmt_ctx->nb_streams; i++) {
    2832          85 :         InputStream *ist = &ifile->streams[i];
    2833          85 :         AVStream *stream = fmt_ctx->streams[i];
    2834             :         AVCodec *codec;
    2835             : 
    2836          85 :         ist->st = stream;
    2837             : 
    2838          85 :         if (stream->codecpar->codec_id == AV_CODEC_ID_PROBE) {
    2839           0 :             av_log(NULL, AV_LOG_WARNING,
    2840             :                    "Failed to probe codec for input stream %d\n",
    2841             :                     stream->index);
    2842           0 :             continue;
    2843             :         }
    2844             : 
    2845          85 :         codec = avcodec_find_decoder(stream->codecpar->codec_id);
    2846          85 :         if (!codec) {
    2847           6 :             av_log(NULL, AV_LOG_WARNING,
    2848             :                     "Unsupported codec with id %d for input stream %d\n",
    2849           3 :                     stream->codecpar->codec_id, stream->index);
    2850           3 :             continue;
    2851             :         }
    2852             :         {
    2853          82 :             AVDictionary *opts = filter_codec_opts(codec_opts, stream->codecpar->codec_id,
    2854             :                                                    fmt_ctx, stream, codec);
    2855             : 
    2856          82 :             ist->dec_ctx = avcodec_alloc_context3(codec);
    2857          82 :             if (!ist->dec_ctx)
    2858           0 :                 exit(1);
    2859             : 
    2860          82 :             err = avcodec_parameters_to_context(ist->dec_ctx, stream->codecpar);
    2861          82 :             if (err < 0)
    2862           0 :                 exit(1);
    2863             : 
    2864          82 :             if (do_show_log) {
    2865             :                 // For loging it is needed to disable at least frame threads as otherwise
    2866             :                 // the log information would need to be reordered and matches up to contexts and frames
    2867             :                 // That is in fact possible but not trivial
    2868           0 :                 av_dict_set(&codec_opts, "threads", "1", 0);
    2869             :             }
    2870             : 
    2871          82 :             av_codec_set_pkt_timebase(ist->dec_ctx, stream->time_base);
    2872          82 :             ist->dec_ctx->framerate = stream->avg_frame_rate;
    2873             : 
    2874          82 :             if (avcodec_open2(ist->dec_ctx, codec, &opts) < 0) {
    2875           0 :                 av_log(NULL, AV_LOG_WARNING, "Could not open codec for input stream %d\n",
    2876             :                        stream->index);
    2877           0 :                 exit(1);
    2878             :             }
    2879             : 
    2880          82 :             if ((t = av_dict_get(opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
    2881           0 :                 av_log(NULL, AV_LOG_ERROR, "Option %s for input stream %d not found\n",
    2882             :                        t->key, stream->index);
    2883           0 :                 return AVERROR_OPTION_NOT_FOUND;
    2884             :             }
    2885             :         }
    2886             :     }
    2887             : 
    2888          52 :     ifile->fmt_ctx = fmt_ctx;
    2889          52 :     return 0;
    2890             : }
    2891             : 
    2892          52 : static void close_input_file(InputFile *ifile)
    2893             : {
    2894             :     int i;
    2895             : 
    2896             :     /* close decoder for each stream */
    2897         137 :     for (i = 0; i < ifile->nb_streams; i++)
    2898          85 :         if (ifile->streams[i].st->codecpar->codec_id != AV_CODEC_ID_NONE)
    2899          82 :             avcodec_free_context(&ifile->streams[i].dec_ctx);
    2900             : 
    2901          52 :     av_freep(&ifile->streams);
    2902          52 :     ifile->nb_streams = 0;
    2903             : 
    2904          52 :     avformat_close_input(&ifile->fmt_ctx);
    2905          52 : }
    2906             : 
    2907          52 : static int probe_file(WriterContext *wctx, const char *filename)
    2908             : {
    2909          52 :     InputFile ifile = { 0 };
    2910             :     int ret, i;
    2911             :     int section_id;
    2912             : 
    2913          52 :     do_read_frames = do_show_frames || do_count_frames;
    2914          52 :     do_read_packets = do_show_packets || do_count_packets;
    2915             : 
    2916          52 :     ret = open_input_file(&ifile, filename);
    2917          52 :     if (ret < 0)
    2918           0 :         goto end;
    2919             : 
    2920             : #define CHECK_END if (ret < 0) goto end
    2921             : 
    2922          52 :     nb_streams = ifile.fmt_ctx->nb_streams;
    2923          52 :     REALLOCZ_ARRAY_STREAM(nb_streams_frames,0,ifile.fmt_ctx->nb_streams);
    2924          52 :     REALLOCZ_ARRAY_STREAM(nb_streams_packets,0,ifile.fmt_ctx->nb_streams);
    2925          52 :     REALLOCZ_ARRAY_STREAM(selected_streams,0,ifile.fmt_ctx->nb_streams);
    2926             : 
    2927         137 :     for (i = 0; i < ifile.fmt_ctx->nb_streams; i++) {
    2928          85 :         if (stream_specifier) {
    2929          40 :             ret = avformat_match_stream_specifier(ifile.fmt_ctx,
    2930          20 :                                                   ifile.fmt_ctx->streams[i],
    2931             :                                                   stream_specifier);
    2932          20 :             CHECK_END;
    2933             :             else
    2934          20 :                 selected_streams[i] = ret;
    2935          20 :             ret = 0;
    2936             :         } else {
    2937          65 :             selected_streams[i] = 1;
    2938             :         }
    2939          85 :         if (!selected_streams[i])
    2940           4 :             ifile.fmt_ctx->streams[i]->discard = AVDISCARD_ALL;
    2941             :     }
    2942             : 
    2943          52 :     if (do_read_frames || do_read_packets) {
    2944          46 :         if (do_show_frames && do_show_packets &&
    2945           9 :             wctx->writer->flags & WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER)
    2946           4 :             section_id = SECTION_ID_PACKETS_AND_FRAMES;
    2947          33 :         else if (do_show_packets && !do_show_frames)
    2948          11 :             section_id = SECTION_ID_PACKETS;
    2949             :         else // (!do_show_packets && do_show_frames)
    2950          22 :             section_id = SECTION_ID_FRAMES;
    2951          37 :         if (do_show_frames || do_show_packets)
    2952          37 :             writer_print_section_header(wctx, section_id);
    2953          37 :         ret = read_packets(wctx, &ifile);
    2954          37 :         if (do_show_frames || do_show_packets)
    2955          37 :             writer_print_section_footer(wctx);
    2956          37 :         CHECK_END;
    2957             :     }
    2958             : 
    2959          52 :     if (do_show_programs) {
    2960          16 :         ret = show_programs(wctx, &ifile);
    2961          16 :         CHECK_END;
    2962             :     }
    2963             : 
    2964          52 :     if (do_show_streams) {
    2965          31 :         ret = show_streams(wctx, &ifile);
    2966          31 :         CHECK_END;
    2967             :     }
    2968          52 :     if (do_show_chapters) {
    2969           1 :         ret = show_chapters(wctx, &ifile);
    2970           1 :         CHECK_END;
    2971             :     }
    2972          52 :     if (do_show_format) {
    2973          18 :         ret = show_format(wctx, &ifile);
    2974          18 :         CHECK_END;
    2975             :     }
    2976             : 
    2977         104 : end:
    2978          52 :     if (ifile.fmt_ctx)
    2979          52 :         close_input_file(&ifile);
    2980          52 :     av_freep(&nb_streams_frames);
    2981          52 :     av_freep(&nb_streams_packets);
    2982          52 :     av_freep(&selected_streams);
    2983             : 
    2984          52 :     return ret;
    2985             : }
    2986             : 
    2987           0 : static void show_usage(void)
    2988             : {
    2989           0 :     av_log(NULL, AV_LOG_INFO, "Simple multimedia streams analyzer\n");
    2990           0 :     av_log(NULL, AV_LOG_INFO, "usage: %s [OPTIONS] [INPUT_FILE]\n", program_name);
    2991           0 :     av_log(NULL, AV_LOG_INFO, "\n");
    2992           0 : }
    2993             : 
    2994           0 : static void ffprobe_show_program_version(WriterContext *w)
    2995             : {
    2996             :     AVBPrint pbuf;
    2997           0 :     av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
    2998             : 
    2999           0 :     writer_print_section_header(w, SECTION_ID_PROGRAM_VERSION);
    3000           0 :     print_str("version", FFMPEG_VERSION);
    3001           0 :     print_fmt("copyright", "Copyright (c) %d-%d the FFmpeg developers",
    3002             :               program_birth_year, CONFIG_THIS_YEAR);
    3003           0 :     print_str("compiler_ident", CC_IDENT);
    3004           0 :     print_str("configuration", FFMPEG_CONFIGURATION);
    3005           0 :     writer_print_section_footer(w);
    3006             : 
    3007           0 :     av_bprint_finalize(&pbuf, NULL);
    3008           0 : }
    3009             : 
    3010             : #define SHOW_LIB_VERSION(libname, LIBNAME)                              \
    3011             :     do {                                                                \
    3012             :         if (CONFIG_##LIBNAME) {                                         \
    3013             :             unsigned int version = libname##_version();                 \
    3014             :             writer_print_section_header(w, SECTION_ID_LIBRARY_VERSION); \
    3015             :             print_str("name",    "lib" #libname);                       \
    3016             :             print_int("major",   LIB##LIBNAME##_VERSION_MAJOR);         \
    3017             :             print_int("minor",   LIB##LIBNAME##_VERSION_MINOR);         \
    3018             :             print_int("micro",   LIB##LIBNAME##_VERSION_MICRO);         \
    3019             :             print_int("version", version);                              \
    3020             :             print_str("ident",   LIB##LIBNAME##_IDENT);                 \
    3021             :             writer_print_section_footer(w);                             \
    3022             :         }                                                               \
    3023             :     } while (0)
    3024             : 
    3025           0 : static void ffprobe_show_library_versions(WriterContext *w)
    3026             : {
    3027           0 :     writer_print_section_header(w, SECTION_ID_LIBRARY_VERSIONS);
    3028           0 :     SHOW_LIB_VERSION(avutil,     AVUTIL);
    3029           0 :     SHOW_LIB_VERSION(avcodec,    AVCODEC);
    3030           0 :     SHOW_LIB_VERSION(avformat,   AVFORMAT);
    3031           0 :     SHOW_LIB_VERSION(avdevice,   AVDEVICE);
    3032           0 :     SHOW_LIB_VERSION(avfilter,   AVFILTER);
    3033           0 :     SHOW_LIB_VERSION(swscale,    SWSCALE);
    3034           0 :     SHOW_LIB_VERSION(swresample, SWRESAMPLE);
    3035           0 :     SHOW_LIB_VERSION(postproc,   POSTPROC);
    3036           0 :     writer_print_section_footer(w);
    3037           0 : }
    3038             : 
    3039             : #define PRINT_PIX_FMT_FLAG(flagname, name)                                \
    3040             :     do {                                                                  \
    3041             :         print_int(name, !!(pixdesc->flags & AV_PIX_FMT_FLAG_##flagname)); \
    3042             :     } while (0)
    3043             : 
    3044           0 : static void ffprobe_show_pixel_formats(WriterContext *w)
    3045             : {
    3046           0 :     const AVPixFmtDescriptor *pixdesc = NULL;
    3047             :     int i, n;
    3048             : 
    3049           0 :     writer_print_section_header(w, SECTION_ID_PIXEL_FORMATS);
    3050           0 :     while (pixdesc = av_pix_fmt_desc_next(pixdesc)) {
    3051           0 :         writer_print_section_header(w, SECTION_ID_PIXEL_FORMAT);
    3052           0 :         print_str("name", pixdesc->name);
    3053           0 :         print_int("nb_components", pixdesc->nb_components);
    3054           0 :         if ((pixdesc->nb_components >= 3) && !(pixdesc->flags & AV_PIX_FMT_FLAG_RGB)) {
    3055           0 :             print_int    ("log2_chroma_w", pixdesc->log2_chroma_w);
    3056           0 :             print_int    ("log2_chroma_h", pixdesc->log2_chroma_h);
    3057             :         } else {
    3058           0 :             print_str_opt("log2_chroma_w", "N/A");
    3059           0 :             print_str_opt("log2_chroma_h", "N/A");
    3060             :         }
    3061           0 :         n = av_get_bits_per_pixel(pixdesc);
    3062           0 :         if (n) print_int    ("bits_per_pixel", n);
    3063           0 :         else   print_str_opt("bits_per_pixel", "N/A");
    3064           0 :         if (do_show_pixel_format_flags) {
    3065           0 :             writer_print_section_header(w, SECTION_ID_PIXEL_FORMAT_FLAGS);
    3066           0 :             PRINT_PIX_FMT_FLAG(BE,        "big_endian");
    3067           0 :             PRINT_PIX_FMT_FLAG(PAL,       "palette");
    3068           0 :             PRINT_PIX_FMT_FLAG(BITSTREAM, "bitstream");
    3069           0 :             PRINT_PIX_FMT_FLAG(HWACCEL,   "hwaccel");
    3070           0 :             PRINT_PIX_FMT_FLAG(PLANAR,    "planar");
    3071           0 :             PRINT_PIX_FMT_FLAG(RGB,       "rgb");
    3072           0 :             PRINT_PIX_FMT_FLAG(PSEUDOPAL, "pseudopal");
    3073           0 :             PRINT_PIX_FMT_FLAG(ALPHA,     "alpha");
    3074           0 :             writer_print_section_footer(w);
    3075             :         }
    3076           0 :         if (do_show_pixel_format_components && (pixdesc->nb_components > 0)) {
    3077           0 :             writer_print_section_header(w, SECTION_ID_PIXEL_FORMAT_COMPONENTS);
    3078           0 :             for (i = 0; i < pixdesc->nb_components; i++) {
    3079           0 :                 writer_print_section_header(w, SECTION_ID_PIXEL_FORMAT_COMPONENT);
    3080           0 :                 print_int("index", i + 1);
    3081           0 :                 print_int("bit_depth", pixdesc->comp[i].depth);
    3082           0 :                 writer_print_section_footer(w);
    3083             :             }
    3084           0 :             writer_print_section_footer(w);
    3085             :         }
    3086           0 :         writer_print_section_footer(w);
    3087             :     }
    3088           0 :     writer_print_section_footer(w);
    3089           0 : }
    3090             : 
    3091           8 : static int opt_format(void *optctx, const char *opt, const char *arg)
    3092             : {
    3093           8 :     iformat = av_find_input_format(arg);
    3094           8 :     if (!iformat) {
    3095           0 :         av_log(NULL, AV_LOG_ERROR, "Unknown input format: %s\n", arg);
    3096           0 :         return AVERROR(EINVAL);
    3097             :     }
    3098           8 :     return 0;
    3099             : }
    3100             : 
    3101         390 : static inline void mark_section_show_entries(SectionID section_id,
    3102             :                                              int show_all_entries, AVDictionary *entries)
    3103             : {
    3104         390 :     struct section *section = &sections[section_id];
    3105             : 
    3106         390 :     section->show_all_entries = show_all_entries;
    3107         390 :     if (show_all_entries) {
    3108             :         SectionID *id;
    3109         600 :         for (id = section->children_ids; *id != -1; id++)
    3110         263 :             mark_section_show_entries(*id, show_all_entries, entries);
    3111             :     } else {
    3112          53 :         av_dict_copy(&section->entries_to_show, entries, 0);
    3113             :     }
    3114         390 : }
    3115             : 
    3116          60 : static int match_section(const char *section_name,
    3117             :                          int show_all_entries, AVDictionary *entries)
    3118             : {
    3119          60 :     int i, ret = 0;
    3120             : 
    3121        2580 :     for (i = 0; i < FF_ARRAY_ELEMS(sections); i++) {
    3122        2520 :         const struct section *section = &sections[i];
    3123        4981 :         if (!strcmp(section_name, section->name) ||
    3124        3405 :             (section->unique_name && !strcmp(section_name, section->unique_name))) {
    3125          76 :             av_log(NULL, AV_LOG_DEBUG,
    3126             :                    "'%s' matches section with unique name '%s'\n", section_name,
    3127          76 :                    (char *)av_x_if_null(section->unique_name, section->name));
    3128          76 :             ret++;
    3129          76 :             mark_section_show_entries(section->id, show_all_entries, entries);
    3130             :         }
    3131             :     }
    3132          60 :     return ret;
    3133             : }
    3134             : 
    3135          30 : static int opt_show_entries(void *optctx, const char *opt, const char *arg)
    3136             : {
    3137          30 :     const char *p = arg;
    3138          30 :     int ret = 0;
    3139             : 
    3140         120 :     while (*p) {
    3141          60 :         AVDictionary *entries = NULL;
    3142          60 :         char *section_name = av_get_token(&p, "=:");
    3143          60 :         int show_all_entries = 0;
    3144             : 
    3145          60 :         if (!section_name) {
    3146           0 :             av_log(NULL, AV_LOG_ERROR,
    3147             :                    "Missing section name for option '%s'\n", opt);
    3148           0 :             return AVERROR(EINVAL);
    3149             :         }
    3150             : 
    3151          60 :         if (*p == '=') {
    3152          40 :             p++;
    3153         167 :             while (*p && *p != ':') {
    3154          87 :                 char *entry = av_get_token(&p, ",:");
    3155          87 :                 if (!entry)
    3156           0 :                     break;
    3157          87 :                 av_log(NULL, AV_LOG_VERBOSE,
    3158             :                        "Adding '%s' to the entries to show in section '%s'\n",
    3159             :                        entry, section_name);
    3160          87 :                 av_dict_set(&entries, entry, "", AV_DICT_DONT_STRDUP_KEY);
    3161          87 :                 if (*p == ',')
    3162          47 :                     p++;
    3163             :             }
    3164             :         } else {
    3165          20 :             show_all_entries = 1;
    3166             :         }
    3167             : 
    3168          60 :         ret = match_section(section_name, show_all_entries, entries);
    3169          60 :         if (ret == 0) {
    3170           0 :             av_log(NULL, AV_LOG_ERROR, "No match for section '%s'\n", section_name);
    3171           0 :             ret = AVERROR(EINVAL);
    3172             :         }
    3173          60 :         av_dict_free(&entries);
    3174          60 :         av_free(section_name);
    3175             : 
    3176          60 :         if (ret <= 0)
    3177           0 :             break;
    3178          60 :         if (*p)
    3179          30 :             p++;
    3180             :     }
    3181             : 
    3182          30 :     return ret;
    3183             : }
    3184             : 
    3185           0 : static int opt_show_format_entry(void *optctx, const char *opt, const char *arg)
    3186             : {
    3187           0 :     char *buf = av_asprintf("format=%s", arg);
    3188             :     int ret;
    3189             : 
    3190           0 :     if (!buf)
    3191           0 :         return AVERROR(ENOMEM);
    3192             : 
    3193           0 :     av_log(NULL, AV_LOG_WARNING,
    3194             :            "Option '%s' is deprecated, use '-show_entries format=%s' instead\n",
    3195             :            opt, arg);
    3196           0 :     ret = opt_show_entries(optctx, opt, buf);
    3197           0 :     av_free(buf);
    3198           0 :     return ret;
    3199             : }
    3200             : 
    3201          52 : static void opt_input_file(void *optctx, const char *arg)
    3202             : {
    3203          52 :     if (input_filename) {
    3204           0 :         av_log(NULL, AV_LOG_ERROR,
    3205             :                 "Argument '%s' provided as input filename, but '%s' was already specified.\n",
    3206             :                 arg, input_filename);
    3207           0 :         exit_program(1);
    3208             :     }
    3209          52 :     if (!strcmp(arg, "-"))
    3210           0 :         arg = "pipe:";
    3211          52 :     input_filename = arg;
    3212          52 : }
    3213             : 
    3214           3 : static int opt_input_file_i(void *optctx, const char *opt, const char *arg)
    3215             : {
    3216           3 :     opt_input_file(optctx, arg);
    3217           3 :     return 0;
    3218             : }
    3219             : 
    3220           0 : void show_help_default(const char *opt, const char *arg)
    3221             : {
    3222           0 :     av_log_set_callback(log_callback_help);
    3223           0 :     show_usage();
    3224           0 :     show_help_options(options, "Main options:", 0, 0, 0);
    3225           0 :     printf("\n");
    3226             : 
    3227           0 :     show_help_children(avformat_get_class(), AV_OPT_FLAG_DECODING_PARAM);
    3228           0 :     show_help_children(avcodec_get_class(), AV_OPT_FLAG_DECODING_PARAM);
    3229           0 : }
    3230             : 
    3231             : /**
    3232             :  * Parse interval specification, according to the format:
    3233             :  * INTERVAL ::= [START|+START_OFFSET][%[END|+END_OFFSET]]
    3234             :  * INTERVALS ::= INTERVAL[,INTERVALS]
    3235             : */
    3236           0 : static int parse_read_interval(const char *interval_spec,
    3237             :                                ReadInterval *interval)
    3238             : {
    3239           0 :     int ret = 0;
    3240           0 :     char *next, *p, *spec = av_strdup(interval_spec);
    3241           0 :     if (!spec)
    3242           0 :         return AVERROR(ENOMEM);
    3243             : 
    3244           0 :     if (!*spec) {
    3245           0 :         av_log(NULL, AV_LOG_ERROR, "Invalid empty interval specification\n");
    3246           0 :         ret = AVERROR(EINVAL);
    3247           0 :         goto end;
    3248             :     }
    3249             : 
    3250           0 :     p = spec;
    3251           0 :     next = strchr(spec, '%');
    3252           0 :     if (next)
    3253           0 :         *next++ = 0;
    3254             : 
    3255             :     /* parse first part */
    3256           0 :     if (*p) {
    3257           0 :         interval->has_start = 1;
    3258             : 
    3259           0 :         if (*p == '+') {
    3260           0 :             interval->start_is_offset = 1;
    3261           0 :             p++;
    3262             :         } else {
    3263           0 :             interval->start_is_offset = 0;
    3264             :         }
    3265             : 
    3266           0 :         ret = av_parse_time(&interval->start, p, 1);
    3267           0 :         if (ret < 0) {
    3268           0 :             av_log(NULL, AV_LOG_ERROR, "Invalid interval start specification '%s'\n", p);
    3269           0 :             goto end;
    3270             :         }
    3271             :     } else {
    3272           0 :         interval->has_start = 0;
    3273             :     }
    3274             : 
    3275             :     /* parse second part */
    3276           0 :     p = next;
    3277           0 :     if (p && *p) {
    3278             :         int64_t us;
    3279           0 :         interval->has_end = 1;
    3280             : 
    3281           0 :         if (*p == '+') {
    3282           0 :             interval->end_is_offset = 1;
    3283           0 :             p++;
    3284             :         } else {
    3285           0 :             interval->end_is_offset = 0;
    3286             :         }
    3287             : 
    3288           0 :         if (interval->end_is_offset && *p == '#') {
    3289             :             long long int lli;
    3290             :             char *tail;
    3291           0 :             interval->duration_frames = 1;
    3292           0 :             p++;
    3293           0 :             lli = strtoll(p, &tail, 10);
    3294           0 :             if (*tail || lli < 0) {
    3295           0 :                 av_log(NULL, AV_LOG_ERROR,
    3296             :                        "Invalid or negative value '%s' for duration number of frames\n", p);
    3297           0 :                 goto end;
    3298             :             }
    3299           0 :             interval->end = lli;
    3300             :         } else {
    3301           0 :             ret = av_parse_time(&us, p, 1);
    3302           0 :             if (ret < 0) {
    3303           0 :                 av_log(NULL, AV_LOG_ERROR, "Invalid interval end/duration specification '%s'\n", p);
    3304           0 :                 goto end;
    3305             :             }
    3306           0 :             interval->end = us;
    3307             :         }
    3308             :     } else {
    3309           0 :         interval->has_end = 0;
    3310             :     }
    3311             : 
    3312           0 : end:
    3313           0 :     av_free(spec);
    3314           0 :     return ret;
    3315             : }
    3316             : 
    3317           0 : static int parse_read_intervals(const char *intervals_spec)
    3318             : {
    3319             :     int ret, n, i;
    3320           0 :     char *p, *spec = av_strdup(intervals_spec);
    3321           0 :     if (!spec)
    3322           0 :         return AVERROR(ENOMEM);
    3323             : 
    3324             :     /* preparse specification, get number of intervals */
    3325           0 :     for (n = 0, p = spec; *p; p++)
    3326           0 :         if (*p == ',')
    3327           0 :             n++;
    3328           0 :     n++;
    3329             : 
    3330           0 :     read_intervals = av_malloc_array(n, sizeof(*read_intervals));
    3331           0 :     if (!read_intervals) {
    3332           0 :         ret = AVERROR(ENOMEM);
    3333           0 :         goto end;
    3334             :     }
    3335           0 :     read_intervals_nb = n;
    3336             : 
    3337             :     /* parse intervals */
    3338           0 :     p = spec;
    3339           0 :     for (i = 0; p; i++) {
    3340             :         char *next;
    3341             : 
    3342           0 :         av_assert0(i < read_intervals_nb);
    3343           0 :         next = strchr(p, ',');
    3344           0 :         if (next)
    3345           0 :             *next++ = 0;
    3346             : 
    3347           0 :         read_intervals[i].id = i;
    3348           0 :         ret = parse_read_interval(p, &read_intervals[i]);
    3349           0 :         if (ret < 0) {
    3350           0 :             av_log(NULL, AV_LOG_ERROR, "Error parsing read interval #%d '%s'\n",
    3351             :                    i, p);
    3352           0 :             goto end;
    3353             :         }
    3354           0 :         av_log(NULL, AV_LOG_VERBOSE, "Parsed log interval ");
    3355           0 :         log_read_interval(&read_intervals[i], NULL, AV_LOG_VERBOSE);
    3356           0 :         p = next;
    3357             :     }
    3358           0 :     av_assert0(i == read_intervals_nb);
    3359             : 
    3360           0 : end:
    3361           0 :     av_free(spec);
    3362           0 :     return ret;
    3363             : }
    3364             : 
    3365           0 : static int opt_read_intervals(void *optctx, const char *opt, const char *arg)
    3366             : {
    3367           0 :     return parse_read_intervals(arg);
    3368             : }
    3369             : 
    3370           0 : static int opt_pretty(void *optctx, const char *opt, const char *arg)
    3371             : {
    3372           0 :     show_value_unit              = 1;
    3373           0 :     use_value_prefix             = 1;
    3374           0 :     use_byte_value_binary_prefix = 1;
    3375           0 :     use_value_sexagesimal_format = 1;
    3376           0 :     return 0;
    3377             : }
    3378             : 
    3379           0 : static void print_section(SectionID id, int level)
    3380             : {
    3381             :     const SectionID *pid;
    3382           0 :     const struct section *section = &sections[id];
    3383           0 :     printf("%c%c%c",
    3384           0 :            section->flags & SECTION_FLAG_IS_WRAPPER           ? 'W' : '.',
    3385           0 :            section->flags & SECTION_FLAG_IS_ARRAY             ? 'A' : '.',
    3386           0 :            section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS  ? 'V' : '.');
    3387           0 :     printf("%*c  %s", level * 4, ' ', section->name);
    3388           0 :     if (section->unique_name)
    3389           0 :         printf("/%s", section->unique_name);
    3390           0 :     printf("\n");
    3391             : 
    3392           0 :     for (pid = section->children_ids; *pid != -1; pid++)
    3393           0 :         print_section(*pid, level+1);
    3394           0 : }
    3395             : 
    3396           0 : static int opt_sections(void *optctx, const char *opt, const char *arg)
    3397             : {
    3398           0 :     printf("Sections:\n"
    3399             :            "W.. = Section is a wrapper (contains other sections, no local entries)\n"
    3400             :            ".A. = Section contains an array of elements of the same type\n"
    3401             :            "..V = Section may contain a variable number of fields with variable keys\n"
    3402             :            "FLAGS NAME/UNIQUE_NAME\n"
    3403             :            "---\n");
    3404           0 :     print_section(SECTION_ID_ROOT, 0);
    3405           0 :     return 0;
    3406             : }
    3407             : 
    3408           0 : static int opt_show_versions(const char *opt, const char *arg)
    3409             : {
    3410           0 :     mark_section_show_entries(SECTION_ID_PROGRAM_VERSION, 1, NULL);
    3411           0 :     mark_section_show_entries(SECTION_ID_LIBRARY_VERSION, 1, NULL);
    3412           0 :     return 0;
    3413             : }
    3414             : 
    3415             : #define DEFINE_OPT_SHOW_SECTION(section, target_section_id)             \
    3416             :     static int opt_show_##section(const char *opt, const char *arg)     \
    3417             :     {                                                                   \
    3418             :         mark_section_show_entries(SECTION_ID_##target_section_id, 1, NULL); \
    3419             :         return 0;                                                       \
    3420             :     }
    3421             : 
    3422           1 : DEFINE_OPT_SHOW_SECTION(chapters,         CHAPTERS)
    3423           0 : DEFINE_OPT_SHOW_SECTION(error,            ERROR)
    3424           7 : DEFINE_OPT_SHOW_SECTION(format,           FORMAT)
    3425          14 : DEFINE_OPT_SHOW_SECTION(frames,           FRAMES)
    3426           0 : DEFINE_OPT_SHOW_SECTION(library_versions, LIBRARY_VERSIONS)
    3427          16 : DEFINE_OPT_SHOW_SECTION(packets,          PACKETS)
    3428           0 : DEFINE_OPT_SHOW_SECTION(pixel_formats,    PIXEL_FORMATS)
    3429           0 : DEFINE_OPT_SHOW_SECTION(program_version,  PROGRAM_VERSION)
    3430          13 : DEFINE_OPT_SHOW_SECTION(streams,          STREAMS)
    3431           0 : DEFINE_OPT_SHOW_SECTION(programs,         PROGRAMS)
    3432             : 
    3433             : static const OptionDef real_options[] = {
    3434             :     CMDUTILS_COMMON_OPTIONS
    3435             :     { "f", HAS_ARG, {.func_arg = opt_format}, "force format", "format" },
    3436             :     { "unit", OPT_BOOL, {&show_value_unit}, "show unit of the displayed values" },
    3437             :     { "prefix", OPT_BOOL, {&use_value_prefix}, "use SI prefixes for the displayed values" },
    3438             :     { "byte_binary_prefix", OPT_BOOL, {&use_byte_value_binary_prefix},
    3439             :       "use binary prefixes for byte units" },
    3440             :     { "sexagesimal", OPT_BOOL,  {&use_value_sexagesimal_format},
    3441             :       "use sexagesimal format HOURS:MM:SS.MICROSECONDS for time units" },
    3442             :     { "pretty", 0, {.func_arg = opt_pretty},
    3443             :       "prettify the format of displayed values, make it more human readable" },
    3444             :     { "print_format", OPT_STRING | HAS_ARG, {(void*)&print_format},
    3445             :       "set the output printing format (available formats are: default, compact, csv, flat, ini, json, xml)", "format" },
    3446             :     { "of", OPT_STRING | HAS_ARG, {(void*)&print_format}, "alias for -print_format", "format" },
    3447             :     { "select_streams", OPT_STRING | HAS_ARG, {(void*)&stream_specifier}, "select the specified streams", "stream_specifier" },
    3448             :     { "sections", OPT_EXIT, {.func_arg = opt_sections}, "print sections structure and section information, and exit" },
    3449             :     { "show_data",    OPT_BOOL, {(void*)&do_show_data}, "show packets data" },
    3450             :     { "show_data_hash", OPT_STRING | HAS_ARG, {(void*)&show_data_hash}, "show packets data hash" },
    3451             :     { "show_error",   0, {(void*)&opt_show_error},  "show probing error" },
    3452             :     { "show_format",  0, {(void*)&opt_show_format}, "show format/container info" },
    3453             :     { "show_frames",  0, {(void*)&opt_show_frames}, "show frames info" },
    3454             :     { "show_format_entry", HAS_ARG, {.func_arg = opt_show_format_entry},
    3455             :       "show a particular entry from the format/container info", "entry" },
    3456             :     { "show_entries", HAS_ARG, {.func_arg = opt_show_entries},
    3457             :       "show a set of specified entries", "entry_list" },
    3458             : #if HAVE_THREADS
    3459             :     { "show_log", OPT_INT|HAS_ARG, {(void*)&do_show_log}, "show log" },
    3460             : #endif
    3461             :     { "show_packets", 0, {(void*)&opt_show_packets}, "show packets info" },
    3462             :     { "show_programs", 0, {(void*)&opt_show_programs}, "show programs info" },
    3463             :     { "show_streams", 0, {(void*)&opt_show_streams}, "show streams info" },
    3464             :     { "show_chapters", 0, {(void*)&opt_show_chapters}, "show chapters info" },
    3465             :     { "count_frames", OPT_BOOL, {(void*)&do_count_frames}, "count the number of frames per stream" },
    3466             :     { "count_packets", OPT_BOOL, {(void*)&do_count_packets}, "count the number of packets per stream" },
    3467             :     { "show_program_version",  0, {(void*)&opt_show_program_version},  "show ffprobe version" },
    3468             :     { "show_library_versions", 0, {(void*)&opt_show_library_versions}, "show library versions" },
    3469             :     { "show_versions",         0, {(void*)&opt_show_versions}, "show program and library versions" },
    3470             :     { "show_pixel_formats", 0, {(void*)&opt_show_pixel_formats}, "show pixel format descriptions" },
    3471             :     { "show_private_data", OPT_BOOL, {(void*)&show_private_data}, "show private data" },
    3472             :     { "private",           OPT_BOOL, {(void*)&show_private_data}, "same as show_private_data" },
    3473             :     { "bitexact", OPT_BOOL, {&do_bitexact}, "force bitexact output" },
    3474             :     { "read_intervals", HAS_ARG, {.func_arg = opt_read_intervals}, "set read intervals", "read_intervals" },
    3475             :     { "default", HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, {.func_arg = opt_default}, "generic catch all option", "" },
    3476             :     { "i", HAS_ARG, {.func_arg = opt_input_file_i}, "read specified file", "input_file"},
    3477             :     { "find_stream_info", OPT_BOOL | OPT_INPUT | OPT_EXPERT, { &find_stream_info },
    3478             :         "read and decode the streams to fill missing information with heuristics" },
    3479             :     { NULL, },
    3480             : };
    3481             : 
    3482        2269 : static inline int check_section_show_entries(int section_id)
    3483             : {
    3484             :     int *id;
    3485        2269 :     struct section *section = &sections[section_id];
    3486        2269 :     if (sections[section_id].show_all_entries || sections[section_id].entries_to_show)
    3487         199 :         return 1;
    3488        3169 :     for (id = section->children_ids; *id != -1; id++)
    3489        1177 :         if (check_section_show_entries(*id))
    3490          78 :             return 1;
    3491        1992 :     return 0;
    3492             : }
    3493             : 
    3494             : #define SET_DO_SHOW(id, varname) do {                                   \
    3495             :         if (check_section_show_entries(SECTION_ID_##id))                \
    3496             :             do_show_##varname = 1;                                      \
    3497             :     } while (0)
    3498             : 
    3499          52 : int main(int argc, char **argv)
    3500             : {
    3501             :     const Writer *w;
    3502             :     WriterContext *wctx;
    3503             :     char *buf;
    3504          52 :     char *w_name = NULL, *w_args = NULL;
    3505             :     int ret, i;
    3506             : 
    3507          52 :     init_dynload();
    3508             : 
    3509             : #if HAVE_THREADS
    3510          52 :     ret = pthread_mutex_init(&log_mutex, NULL);
    3511          52 :     if (ret != 0) {
    3512           0 :         goto end;
    3513             :     }
    3514             : #endif
    3515          52 :     av_log_set_flags(AV_LOG_SKIP_REPEATED);
    3516          52 :     register_exit(ffprobe_cleanup);
    3517             : 
    3518          52 :     options = real_options;
    3519          52 :     parse_loglevel(argc, argv, options);
    3520          52 :     av_register_all();
    3521          52 :     avformat_network_init();
    3522          52 :     init_opts();
    3523             : #if CONFIG_AVDEVICE
    3524          52 :     avdevice_register_all();
    3525             : #endif
    3526             : 
    3527          52 :     show_banner(argc, argv, options);
    3528          52 :     parse_options(NULL, argc, argv, options, opt_input_file);
    3529             : 
    3530          52 :     if (do_show_log)
    3531           0 :         av_log_set_callback(log_callback);
    3532             : 
    3533             :     /* mark things to show, based on -show_entries */
    3534          52 :     SET_DO_SHOW(CHAPTERS, chapters);
    3535          52 :     SET_DO_SHOW(ERROR, error);
    3536          52 :     SET_DO_SHOW(FORMAT, format);
    3537          52 :     SET_DO_SHOW(FRAMES, frames);
    3538          52 :     SET_DO_SHOW(LIBRARY_VERSIONS, library_versions);
    3539          52 :     SET_DO_SHOW(PACKETS, packets);
    3540          52 :     SET_DO_SHOW(PIXEL_FORMATS, pixel_formats);
    3541          52 :     SET_DO_SHOW(PIXEL_FORMAT_FLAGS, pixel_format_flags);
    3542          52 :     SET_DO_SHOW(PIXEL_FORMAT_COMPONENTS, pixel_format_components);
    3543          52 :     SET_DO_SHOW(PROGRAM_VERSION, program_version);
    3544          52 :     SET_DO_SHOW(PROGRAMS, programs);
    3545          52 :     SET_DO_SHOW(STREAMS, streams);
    3546          52 :     SET_DO_SHOW(STREAM_DISPOSITION, stream_disposition);
    3547          52 :     SET_DO_SHOW(PROGRAM_STREAM_DISPOSITION, stream_disposition);
    3548             : 
    3549          52 :     SET_DO_SHOW(CHAPTER_TAGS, chapter_tags);
    3550          52 :     SET_DO_SHOW(FORMAT_TAGS, format_tags);
    3551          52 :     SET_DO_SHOW(FRAME_TAGS, frame_tags);
    3552          52 :     SET_DO_SHOW(PROGRAM_TAGS, program_tags);
    3553          52 :     SET_DO_SHOW(STREAM_TAGS, stream_tags);
    3554          52 :     SET_DO_SHOW(PROGRAM_STREAM_TAGS, stream_tags);
    3555          52 :     SET_DO_SHOW(PACKET_TAGS, packet_tags);
    3556             : 
    3557          52 :     if (do_bitexact && (do_show_program_version || do_show_library_versions)) {
    3558           0 :         av_log(NULL, AV_LOG_ERROR,
    3559             :                "-bitexact and -show_program_version or -show_library_versions "
    3560             :                "options are incompatible\n");
    3561           0 :         ret = AVERROR(EINVAL);
    3562           0 :         goto end;
    3563             :     }
    3564             : 
    3565          52 :     writer_register_all();
    3566             : 
    3567          52 :     if (!print_format)
    3568          15 :         print_format = av_strdup("default");
    3569          52 :     if (!print_format) {
    3570           0 :         ret = AVERROR(ENOMEM);
    3571           0 :         goto end;
    3572             :     }
    3573          52 :     w_name = av_strtok(print_format, "=", &buf);
    3574          52 :     if (!w_name) {
    3575           0 :         av_log(NULL, AV_LOG_ERROR,
    3576             :                "No name specified for the output format\n");
    3577           0 :         ret = AVERROR(EINVAL);
    3578           0 :         goto end;
    3579             :     }
    3580          52 :     w_args = buf;
    3581             : 
    3582          52 :     if (show_data_hash) {
    3583           0 :         if ((ret = av_hash_alloc(&hash, show_data_hash)) < 0) {
    3584           0 :             if (ret == AVERROR(EINVAL)) {
    3585             :                 const char *n;
    3586           0 :                 av_log(NULL, AV_LOG_ERROR,
    3587             :                        "Unknown hash algorithm '%s'\nKnown algorithms:",
    3588             :                        show_data_hash);
    3589           0 :                 for (i = 0; (n = av_hash_names(i)); i++)
    3590           0 :                     av_log(NULL, AV_LOG_ERROR, " %s", n);
    3591           0 :                 av_log(NULL, AV_LOG_ERROR, "\n");
    3592             :             }
    3593           0 :             goto end;
    3594             :         }
    3595             :     }
    3596             : 
    3597          52 :     w = writer_get_by_name(w_name);
    3598          52 :     if (!w) {
    3599           0 :         av_log(NULL, AV_LOG_ERROR, "Unknown output format with name '%s'\n", w_name);
    3600           0 :         ret = AVERROR(EINVAL);
    3601           0 :         goto end;
    3602             :     }
    3603             : 
    3604          52 :     if ((ret = writer_open(&wctx, w, w_args,
    3605             :                            sections, FF_ARRAY_ELEMS(sections))) >= 0) {
    3606          52 :         if (w == &xml_writer)
    3607           1 :             wctx->string_validation_utf8_flags |= AV_UTF8_FLAG_EXCLUDE_XML_INVALID_CONTROL_CODES;
    3608             : 
    3609          52 :         writer_print_section_header(wctx, SECTION_ID_ROOT);
    3610             : 
    3611          52 :         if (do_show_program_version)
    3612           0 :             ffprobe_show_program_version(wctx);
    3613          52 :         if (do_show_library_versions)
    3614           0 :             ffprobe_show_library_versions(wctx);
    3615          52 :         if (do_show_pixel_formats)
    3616           0 :             ffprobe_show_pixel_formats(wctx);
    3617             : 
    3618          52 :         if (!input_filename &&
    3619           0 :             ((do_show_format || do_show_programs || do_show_streams || do_show_chapters || do_show_packets || do_show_error) ||
    3620           0 :              (!do_show_program_version && !do_show_library_versions && !do_show_pixel_formats))) {
    3621           0 :             show_usage();
    3622           0 :             av_log(NULL, AV_LOG_ERROR, "You have to specify one input file.\n");
    3623           0 :             av_log(NULL, AV_LOG_ERROR, "Use -h to get full help or, even better, run 'man %s'.\n", program_name);
    3624           0 :             ret = AVERROR(EINVAL);
    3625          52 :         } else if (input_filename) {
    3626          52 :             ret = probe_file(wctx, input_filename);
    3627          52 :             if (ret < 0 && do_show_error)
    3628           0 :                 show_error(wctx, ret);
    3629             :         }
    3630             : 
    3631          52 :         writer_print_section_footer(wctx);
    3632          52 :         writer_close(&wctx);
    3633             :     }
    3634             : 
    3635          52 : end:
    3636          52 :     av_freep(&print_format);
    3637          52 :     av_freep(&read_intervals);
    3638          52 :     av_hash_freep(&hash);
    3639             : 
    3640          52 :     uninit_opts();
    3641        2236 :     for (i = 0; i < FF_ARRAY_ELEMS(sections); i++)
    3642        2184 :         av_dict_free(&(sections[i].entries_to_show));
    3643             : 
    3644          52 :     avformat_network_deinit();
    3645             : 
    3646          52 :     return ret < 0;
    3647             : }

Generated by: LCOV version 1.13