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

Generated by: LCOV version 1.12