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

Generated by: LCOV version 1.13