Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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 "version.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/opt.h"
  37. #include "libavutil/pixdesc.h"
  38. #include "libavutil/dict.h"
  39. #include "libavutil/libm.h"
  40. #include "libavutil/parseutils.h"
  41. #include "libavutil/timecode.h"
  42. #include "libavutil/timestamp.h"
  43. #include "libavdevice/avdevice.h"
  44. #include "libswscale/swscale.h"
  45. #include "libswresample/swresample.h"
  46. #include "libpostproc/postprocess.h"
  47. #include "cmdutils.h"
  48.  
  49. const char program_name[] = "ffprobe";
  50. const int program_birth_year = 2007;
  51.  
  52. static int do_bitexact = 0;
  53. static int do_count_frames = 0;
  54. static int do_count_packets = 0;
  55. static int do_read_frames  = 0;
  56. static int do_read_packets = 0;
  57. static int do_show_chapters = 0;
  58. static int do_show_error   = 0;
  59. static int do_show_format  = 0;
  60. static int do_show_frames  = 0;
  61. static int do_show_packets = 0;
  62. static int do_show_programs = 0;
  63. static int do_show_streams = 0;
  64. static int do_show_stream_disposition = 0;
  65. static int do_show_data    = 0;
  66. static int do_show_program_version  = 0;
  67. static int do_show_library_versions = 0;
  68.  
  69. static int show_value_unit              = 0;
  70. static int use_value_prefix             = 0;
  71. static int use_byte_value_binary_prefix = 0;
  72. static int use_value_sexagesimal_format = 0;
  73. static int show_private_data            = 1;
  74.  
  75. static char *print_format;
  76. static char *stream_specifier;
  77.  
  78. typedef struct {
  79.     int id;             ///< identifier
  80.     int64_t start, end; ///< start, end in second/AV_TIME_BASE units
  81.     int has_start, has_end;
  82.     int start_is_offset, end_is_offset;
  83.     int duration_frames;
  84. } ReadInterval;
  85.  
  86. static ReadInterval *read_intervals;
  87. static int read_intervals_nb = 0;
  88.  
  89. /* section structure definition */
  90.  
  91. #define SECTION_MAX_NB_CHILDREN 10
  92.  
  93. struct section {
  94.     int id;             ///< unique id identifying a section
  95.     const char *name;
  96.  
  97. #define SECTION_FLAG_IS_WRAPPER      1 ///< the section only contains other sections, but has no data at its own level
  98. #define SECTION_FLAG_IS_ARRAY        2 ///< the section contains an array of elements of the same type
  99. #define SECTION_FLAG_HAS_VARIABLE_FIELDS 4 ///< the section may contain a variable number of fields with variable keys.
  100.                                            ///  For these sections the element_name field is mandatory.
  101.     int flags;
  102.     int children_ids[SECTION_MAX_NB_CHILDREN+1]; ///< list of children section IDS, terminated by -1
  103.     const char *element_name; ///< name of the contained element, if provided
  104.     const char *unique_name;  ///< unique section name, in case the name is ambiguous
  105.     AVDictionary *entries_to_show;
  106.     int show_all_entries;
  107. };
  108.  
  109. typedef enum {
  110.     SECTION_ID_NONE = -1,
  111.     SECTION_ID_CHAPTER,
  112.     SECTION_ID_CHAPTER_TAGS,
  113.     SECTION_ID_CHAPTERS,
  114.     SECTION_ID_ERROR,
  115.     SECTION_ID_FORMAT,
  116.     SECTION_ID_FORMAT_TAGS,
  117.     SECTION_ID_FRAME,
  118.     SECTION_ID_FRAMES,
  119.     SECTION_ID_FRAME_TAGS,
  120.     SECTION_ID_LIBRARY_VERSION,
  121.     SECTION_ID_LIBRARY_VERSIONS,
  122.     SECTION_ID_PACKET,
  123.     SECTION_ID_PACKETS,
  124.     SECTION_ID_PACKETS_AND_FRAMES,
  125.     SECTION_ID_PROGRAM_STREAM_DISPOSITION,
  126.     SECTION_ID_PROGRAM_STREAM_TAGS,
  127.     SECTION_ID_PROGRAM,
  128.     SECTION_ID_PROGRAM_STREAMS,
  129.     SECTION_ID_PROGRAM_STREAM,
  130.     SECTION_ID_PROGRAM_TAGS,
  131.     SECTION_ID_PROGRAM_VERSION,
  132.     SECTION_ID_PROGRAMS,
  133.     SECTION_ID_ROOT,
  134.     SECTION_ID_STREAM,
  135.     SECTION_ID_STREAM_DISPOSITION,
  136.     SECTION_ID_STREAMS,
  137.     SECTION_ID_STREAM_TAGS,
  138. } SectionID;
  139.  
  140. static struct section sections[] = {
  141.     [SECTION_ID_CHAPTERS] =           { SECTION_ID_CHAPTERS, "chapters", SECTION_FLAG_IS_ARRAY, { SECTION_ID_CHAPTER, -1 } },
  142.     [SECTION_ID_CHAPTER] =            { SECTION_ID_CHAPTER, "chapter", 0, { SECTION_ID_CHAPTER_TAGS, -1 } },
  143.     [SECTION_ID_CHAPTER_TAGS] =       { SECTION_ID_CHAPTER_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "chapter_tags" },
  144.     [SECTION_ID_ERROR] =              { SECTION_ID_ERROR, "error", 0, { -1 } },
  145.     [SECTION_ID_FORMAT] =             { SECTION_ID_FORMAT, "format", 0, { SECTION_ID_FORMAT_TAGS, -1 } },
  146.     [SECTION_ID_FORMAT_TAGS] =        { SECTION_ID_FORMAT_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "format_tags" },
  147.     [SECTION_ID_FRAMES] =             { SECTION_ID_FRAMES, "frames", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME, -1 } },
  148.     [SECTION_ID_FRAME] =              { SECTION_ID_FRAME, "frame", 0, { SECTION_ID_FRAME_TAGS, -1 } },
  149.     [SECTION_ID_FRAME_TAGS] =         { SECTION_ID_FRAME_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "frame_tags" },
  150.     [SECTION_ID_LIBRARY_VERSIONS] =   { SECTION_ID_LIBRARY_VERSIONS, "library_versions", SECTION_FLAG_IS_ARRAY, { SECTION_ID_LIBRARY_VERSION, -1 } },
  151.     [SECTION_ID_LIBRARY_VERSION] =    { SECTION_ID_LIBRARY_VERSION, "library_version", 0, { -1 } },
  152.     [SECTION_ID_PACKETS] =            { SECTION_ID_PACKETS, "packets", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET, -1} },
  153.     [SECTION_ID_PACKETS_AND_FRAMES] = { SECTION_ID_PACKETS_AND_FRAMES, "packets_and_frames", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET, -1} },
  154.     [SECTION_ID_PACKET] =             { SECTION_ID_PACKET, "packet", 0, { -1 } },
  155.     [SECTION_ID_PROGRAM_STREAM_DISPOSITION] = { SECTION_ID_PROGRAM_STREAM_DISPOSITION, "disposition", 0, { -1 }, .unique_name = "program_stream_disposition" },
  156.     [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" },
  157.     [SECTION_ID_PROGRAM] =                    { SECTION_ID_PROGRAM, "program", 0, { SECTION_ID_PROGRAM_TAGS, SECTION_ID_PROGRAM_STREAMS, -1 } },
  158.     [SECTION_ID_PROGRAM_STREAMS] =            { SECTION_ID_PROGRAM_STREAMS, "streams", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PROGRAM_STREAM, -1 }, .unique_name = "program_streams" },
  159.     [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" },
  160.     [SECTION_ID_PROGRAM_TAGS] =               { SECTION_ID_PROGRAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "program_tags" },
  161.     [SECTION_ID_PROGRAM_VERSION] =    { SECTION_ID_PROGRAM_VERSION, "program_version", 0, { -1 } },
  162.     [SECTION_ID_PROGRAMS] =                   { SECTION_ID_PROGRAMS, "programs", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PROGRAM, -1 } },
  163.     [SECTION_ID_ROOT] =               { SECTION_ID_ROOT, "root", SECTION_FLAG_IS_WRAPPER,
  164.                                         { SECTION_ID_CHAPTERS, SECTION_ID_FORMAT, SECTION_ID_FRAMES, SECTION_ID_PROGRAMS, SECTION_ID_STREAMS,
  165.                                           SECTION_ID_PACKETS, SECTION_ID_ERROR, SECTION_ID_PROGRAM_VERSION, SECTION_ID_LIBRARY_VERSIONS, -1} },
  166.     [SECTION_ID_STREAMS] =            { SECTION_ID_STREAMS, "streams", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM, -1 } },
  167.     [SECTION_ID_STREAM] =             { SECTION_ID_STREAM, "stream", 0, { SECTION_ID_STREAM_DISPOSITION, SECTION_ID_STREAM_TAGS, -1 } },
  168.     [SECTION_ID_STREAM_DISPOSITION] = { SECTION_ID_STREAM_DISPOSITION, "disposition", 0, { -1 }, .unique_name = "stream_disposition" },
  169.     [SECTION_ID_STREAM_TAGS] =        { SECTION_ID_STREAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "stream_tags" },
  170. };
  171.  
  172. static const OptionDef *options;
  173.  
  174. /* FFprobe context */
  175. static const char *input_filename;
  176. static AVInputFormat *iformat = NULL;
  177.  
  178. static const char *const binary_unit_prefixes [] = { "", "Ki", "Mi", "Gi", "Ti", "Pi" };
  179. static const char *const decimal_unit_prefixes[] = { "", "K" , "M" , "G" , "T" , "P"  };
  180.  
  181. static const char unit_second_str[]         = "s"    ;
  182. static const char unit_hertz_str[]          = "Hz"   ;
  183. static const char unit_byte_str[]           = "byte" ;
  184. static const char unit_bit_per_second_str[] = "bit/s";
  185.  
  186. static uint64_t *nb_streams_packets;
  187. static uint64_t *nb_streams_frames;
  188. static int *selected_streams;
  189.  
  190. static void ffprobe_cleanup(int ret)
  191. {
  192.     int i;
  193.     for (i = 0; i < FF_ARRAY_ELEMS(sections); i++)
  194.         av_dict_free(&(sections[i].entries_to_show));
  195. }
  196.  
  197. struct unit_value {
  198.     union { double d; long long int i; } val;
  199.     const char *unit;
  200. };
  201.  
  202. static char *value_string(char *buf, int buf_size, struct unit_value uv)
  203. {
  204.     double vald;
  205.     long long int vali;
  206.     int show_float = 0;
  207.  
  208.     if (uv.unit == unit_second_str) {
  209.         vald = uv.val.d;
  210.         show_float = 1;
  211.     } else {
  212.         vald = vali = uv.val.i;
  213.     }
  214.  
  215.     if (uv.unit == unit_second_str && use_value_sexagesimal_format) {
  216.         double secs;
  217.         int hours, mins;
  218.         secs  = vald;
  219.         mins  = (int)secs / 60;
  220.         secs  = secs - mins * 60;
  221.         hours = mins / 60;
  222.         mins %= 60;
  223.         snprintf(buf, buf_size, "%d:%02d:%09.6f", hours, mins, secs);
  224.     } else {
  225.         const char *prefix_string = "";
  226.  
  227.         if (use_value_prefix && vald > 1) {
  228.             long long int index;
  229.  
  230.             if (uv.unit == unit_byte_str && use_byte_value_binary_prefix) {
  231.                 index = (long long int) (log2(vald)) / 10;
  232.                 index = av_clip(index, 0, FF_ARRAY_ELEMS(binary_unit_prefixes) - 1);
  233.                 vald /= exp2(index * 10);
  234.                 prefix_string = binary_unit_prefixes[index];
  235.             } else {
  236.                 index = (long long int) (log10(vald)) / 3;
  237.                 index = av_clip(index, 0, FF_ARRAY_ELEMS(decimal_unit_prefixes) - 1);
  238.                 vald /= pow(10, index * 3);
  239.                 prefix_string = decimal_unit_prefixes[index];
  240.             }
  241.         }
  242.  
  243.         if (show_float || (use_value_prefix && vald != (long long int)vald))
  244.             snprintf(buf, buf_size, "%f", vald);
  245.         else
  246.             snprintf(buf, buf_size, "%lld", vali);
  247.         av_strlcatf(buf, buf_size, "%s%s%s", *prefix_string || show_value_unit ? " " : "",
  248.                  prefix_string, show_value_unit ? uv.unit : "");
  249.     }
  250.  
  251.     return buf;
  252. }
  253.  
  254. /* WRITERS API */
  255.  
  256. typedef struct WriterContext WriterContext;
  257.  
  258. #define WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS 1
  259. #define WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER 2
  260.  
  261. typedef struct Writer {
  262.     const AVClass *priv_class;      ///< private class of the writer, if any
  263.     int priv_size;                  ///< private size for the writer context
  264.     const char *name;
  265.  
  266.     int  (*init)  (WriterContext *wctx);
  267.     void (*uninit)(WriterContext *wctx);
  268.  
  269.     void (*print_section_header)(WriterContext *wctx);
  270.     void (*print_section_footer)(WriterContext *wctx);
  271.     void (*print_integer)       (WriterContext *wctx, const char *, long long int);
  272.     void (*print_rational)      (WriterContext *wctx, AVRational *q, char *sep);
  273.     void (*print_string)        (WriterContext *wctx, const char *, const char *);
  274.     int flags;                  ///< a combination or WRITER_FLAG_*
  275. } Writer;
  276.  
  277. #define SECTION_MAX_NB_LEVELS 10
  278.  
  279. struct WriterContext {
  280.     const AVClass *class;           ///< class of the writer
  281.     const Writer *writer;           ///< the Writer of which this is an instance
  282.     char *name;                     ///< name of this writer instance
  283.     void *priv;                     ///< private data for use by the filter
  284.  
  285.     const struct section *sections; ///< array containing all sections
  286.     int nb_sections;                ///< number of sections
  287.  
  288.     int level;                      ///< current level, starting from 0
  289.  
  290.     /** number of the item printed in the given section, starting from 0 */
  291.     unsigned int nb_item[SECTION_MAX_NB_LEVELS];
  292.  
  293.     /** section per each level */
  294.     const struct section *section[SECTION_MAX_NB_LEVELS];
  295.     AVBPrint section_pbuf[SECTION_MAX_NB_LEVELS]; ///< generic print buffer dedicated to each section,
  296.                                                   ///  used by various writers
  297.  
  298.     unsigned int nb_section_packet; ///< number of the packet section in case we are in "packets_and_frames" section
  299.     unsigned int nb_section_frame;  ///< number of the frame  section in case we are in "packets_and_frames" section
  300.     unsigned int nb_section_packet_frame; ///< nb_section_packet or nb_section_frame according if is_packets_and_frames
  301. };
  302.  
  303. static const char *writer_get_name(void *p)
  304. {
  305.     WriterContext *wctx = p;
  306.     return wctx->writer->name;
  307. }
  308.  
  309. static const AVClass writer_class = {
  310.     "Writer",
  311.     writer_get_name,
  312.     NULL,
  313.     LIBAVUTIL_VERSION_INT,
  314. };
  315.  
  316. static void writer_close(WriterContext **wctx)
  317. {
  318.     int i;
  319.  
  320.     if (!*wctx)
  321.         return;
  322.  
  323.     if ((*wctx)->writer->uninit)
  324.         (*wctx)->writer->uninit(*wctx);
  325.     for (i = 0; i < SECTION_MAX_NB_LEVELS; i++)
  326.         av_bprint_finalize(&(*wctx)->section_pbuf[i], NULL);
  327.     if ((*wctx)->writer->priv_class)
  328.         av_opt_free((*wctx)->priv);
  329.     av_freep(&((*wctx)->priv));
  330.     av_freep(wctx);
  331. }
  332.  
  333. static int writer_open(WriterContext **wctx, const Writer *writer, const char *args,
  334.                        const struct section *sections, int nb_sections)
  335. {
  336.     int i, ret = 0;
  337.  
  338.     if (!(*wctx = av_mallocz(sizeof(WriterContext)))) {
  339.         ret = AVERROR(ENOMEM);
  340.         goto fail;
  341.     }
  342.  
  343.     if (!((*wctx)->priv = av_mallocz(writer->priv_size))) {
  344.         ret = AVERROR(ENOMEM);
  345.         goto fail;
  346.     }
  347.  
  348.     (*wctx)->class = &writer_class;
  349.     (*wctx)->writer = writer;
  350.     (*wctx)->level = -1;
  351.     (*wctx)->sections = sections;
  352.     (*wctx)->nb_sections = nb_sections;
  353.  
  354.     if (writer->priv_class) {
  355.         void *priv_ctx = (*wctx)->priv;
  356.         *((const AVClass **)priv_ctx) = writer->priv_class;
  357.         av_opt_set_defaults(priv_ctx);
  358.  
  359.         if (args &&
  360.             (ret = av_set_options_string(priv_ctx, args, "=", ":")) < 0)
  361.             goto fail;
  362.     }
  363.  
  364.     for (i = 0; i < SECTION_MAX_NB_LEVELS; i++)
  365.         av_bprint_init(&(*wctx)->section_pbuf[i], 1, AV_BPRINT_SIZE_UNLIMITED);
  366.  
  367.     if ((*wctx)->writer->init)
  368.         ret = (*wctx)->writer->init(*wctx);
  369.     if (ret < 0)
  370.         goto fail;
  371.  
  372.     return 0;
  373.  
  374. fail:
  375.     writer_close(wctx);
  376.     return ret;
  377. }
  378.  
  379. static inline void writer_print_section_header(WriterContext *wctx,
  380.                                                int section_id)
  381. {
  382.     int parent_section_id;
  383.     wctx->level++;
  384.     av_assert0(wctx->level < SECTION_MAX_NB_LEVELS);
  385.     parent_section_id = wctx->level ?
  386.         (wctx->section[wctx->level-1])->id : SECTION_ID_NONE;
  387.  
  388.     wctx->nb_item[wctx->level] = 0;
  389.     wctx->section[wctx->level] = &wctx->sections[section_id];
  390.  
  391.     if (section_id == SECTION_ID_PACKETS_AND_FRAMES) {
  392.         wctx->nb_section_packet = wctx->nb_section_frame =
  393.         wctx->nb_section_packet_frame = 0;
  394.     } else if (parent_section_id == SECTION_ID_PACKETS_AND_FRAMES) {
  395.         wctx->nb_section_packet_frame = section_id == SECTION_ID_PACKET ?
  396.             wctx->nb_section_packet : wctx->nb_section_frame;
  397.     }
  398.  
  399.     if (wctx->writer->print_section_header)
  400.         wctx->writer->print_section_header(wctx);
  401. }
  402.  
  403. static inline void writer_print_section_footer(WriterContext *wctx)
  404. {
  405.     int section_id = wctx->section[wctx->level]->id;
  406.     int parent_section_id = wctx->level ?
  407.         wctx->section[wctx->level-1]->id : SECTION_ID_NONE;
  408.  
  409.     if (parent_section_id != SECTION_ID_NONE)
  410.         wctx->nb_item[wctx->level-1]++;
  411.     if (parent_section_id == SECTION_ID_PACKETS_AND_FRAMES) {
  412.         if (section_id == SECTION_ID_PACKET) wctx->nb_section_packet++;
  413.         else                                     wctx->nb_section_frame++;
  414.     }
  415.     if (wctx->writer->print_section_footer)
  416.         wctx->writer->print_section_footer(wctx);
  417.     wctx->level--;
  418. }
  419.  
  420. static inline void writer_print_integer(WriterContext *wctx,
  421.                                         const char *key, long long int val)
  422. {
  423.     const struct section *section = wctx->section[wctx->level];
  424.  
  425.     if (section->show_all_entries || av_dict_get(section->entries_to_show, key, NULL, 0)) {
  426.         wctx->writer->print_integer(wctx, key, val);
  427.         wctx->nb_item[wctx->level]++;
  428.     }
  429. }
  430.  
  431. static inline void writer_print_string(WriterContext *wctx,
  432.                                        const char *key, const char *val, int opt)
  433. {
  434.     const struct section *section = wctx->section[wctx->level];
  435.  
  436.     if (opt && !(wctx->writer->flags & WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS))
  437.         return;
  438.  
  439.     if (section->show_all_entries || av_dict_get(section->entries_to_show, key, NULL, 0)) {
  440.         wctx->writer->print_string(wctx, key, val);
  441.         wctx->nb_item[wctx->level]++;
  442.     }
  443. }
  444.  
  445. static inline void writer_print_rational(WriterContext *wctx,
  446.                                          const char *key, AVRational q, char sep)
  447. {
  448.     AVBPrint buf;
  449.     av_bprint_init(&buf, 0, AV_BPRINT_SIZE_AUTOMATIC);
  450.     av_bprintf(&buf, "%d%c%d", q.num, sep, q.den);
  451.     writer_print_string(wctx, key, buf.str, 0);
  452. }
  453.  
  454. static void writer_print_time(WriterContext *wctx, const char *key,
  455.                               int64_t ts, const AVRational *time_base, int is_duration)
  456. {
  457.     char buf[128];
  458.  
  459.     if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0)) {
  460.         writer_print_string(wctx, key, "N/A", 1);
  461.     } else {
  462.         double d = ts * av_q2d(*time_base);
  463.         struct unit_value uv;
  464.         uv.val.d = d;
  465.         uv.unit = unit_second_str;
  466.         value_string(buf, sizeof(buf), uv);
  467.         writer_print_string(wctx, key, buf, 0);
  468.     }
  469. }
  470.  
  471. static void writer_print_ts(WriterContext *wctx, const char *key, int64_t ts, int is_duration)
  472. {
  473.     if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0)) {
  474.         writer_print_string(wctx, key, "N/A", 1);
  475.     } else {
  476.         writer_print_integer(wctx, key, ts);
  477.     }
  478. }
  479.  
  480. static void writer_print_data(WriterContext *wctx, const char *name,
  481.                               uint8_t *data, int size)
  482. {
  483.     AVBPrint bp;
  484.     int offset = 0, l, i;
  485.  
  486.     av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED);
  487.     av_bprintf(&bp, "\n");
  488.     while (size) {
  489.         av_bprintf(&bp, "%08x: ", offset);
  490.         l = FFMIN(size, 16);
  491.         for (i = 0; i < l; i++) {
  492.             av_bprintf(&bp, "%02x", data[i]);
  493.             if (i & 1)
  494.                 av_bprintf(&bp, " ");
  495.         }
  496.         av_bprint_chars(&bp, ' ', 41 - 2 * i - i / 2);
  497.         for (i = 0; i < l; i++)
  498.             av_bprint_chars(&bp, data[i] - 32U < 95 ? data[i] : '.', 1);
  499.         av_bprintf(&bp, "\n");
  500.         offset += l;
  501.         data   += l;
  502.         size   -= l;
  503.     }
  504.     writer_print_string(wctx, name, bp.str, 0);
  505.     av_bprint_finalize(&bp, NULL);
  506. }
  507.  
  508. #define MAX_REGISTERED_WRITERS_NB 64
  509.  
  510. static const Writer *registered_writers[MAX_REGISTERED_WRITERS_NB + 1];
  511.  
  512. static int writer_register(const Writer *writer)
  513. {
  514.     static int next_registered_writer_idx = 0;
  515.  
  516.     if (next_registered_writer_idx == MAX_REGISTERED_WRITERS_NB)
  517.         return AVERROR(ENOMEM);
  518.  
  519.     registered_writers[next_registered_writer_idx++] = writer;
  520.     return 0;
  521. }
  522.  
  523. static const Writer *writer_get_by_name(const char *name)
  524. {
  525.     int i;
  526.  
  527.     for (i = 0; registered_writers[i]; i++)
  528.         if (!strcmp(registered_writers[i]->name, name))
  529.             return registered_writers[i];
  530.  
  531.     return NULL;
  532. }
  533.  
  534.  
  535. /* WRITERS */
  536.  
  537. #define DEFINE_WRITER_CLASS(name)                   \
  538. static const char *name##_get_name(void *ctx)       \
  539. {                                                   \
  540.     return #name ;                                  \
  541. }                                                   \
  542. static const AVClass name##_class = {               \
  543.     #name,                                          \
  544.     name##_get_name,                                \
  545.     name##_options                                  \
  546. }
  547.  
  548. /* Default output */
  549.  
  550. typedef struct DefaultContext {
  551.     const AVClass *class;
  552.     int nokey;
  553.     int noprint_wrappers;
  554.     int nested_section[SECTION_MAX_NB_LEVELS];
  555. } DefaultContext;
  556.  
  557. #define OFFSET(x) offsetof(DefaultContext, x)
  558.  
  559. static const AVOption default_options[] = {
  560.     { "noprint_wrappers", "do not print headers and footers", OFFSET(noprint_wrappers), AV_OPT_TYPE_INT, {.i64=0}, 0, 1 },
  561.     { "nw",               "do not print headers and footers", OFFSET(noprint_wrappers), AV_OPT_TYPE_INT, {.i64=0}, 0, 1 },
  562.     { "nokey",          "force no key printing",     OFFSET(nokey),          AV_OPT_TYPE_INT, {.i64=0}, 0, 1 },
  563.     { "nk",             "force no key printing",     OFFSET(nokey),          AV_OPT_TYPE_INT, {.i64=0}, 0, 1 },
  564.     {NULL},
  565. };
  566.  
  567. DEFINE_WRITER_CLASS(default);
  568.  
  569. /* lame uppercasing routine, assumes the string is lower case ASCII */
  570. static inline char *upcase_string(char *dst, size_t dst_size, const char *src)
  571. {
  572.     int i;
  573.     for (i = 0; src[i] && i < dst_size-1; i++)
  574.         dst[i] = av_toupper(src[i]);
  575.     dst[i] = 0;
  576.     return dst;
  577. }
  578.  
  579. static void default_print_section_header(WriterContext *wctx)
  580. {
  581.     DefaultContext *def = wctx->priv;
  582.     char buf[32];
  583.     const struct section *section = wctx->section[wctx->level];
  584.     const struct section *parent_section = wctx->level ?
  585.         wctx->section[wctx->level-1] : NULL;
  586.  
  587.     av_bprint_clear(&wctx->section_pbuf[wctx->level]);
  588.     if (parent_section &&
  589.         !(parent_section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))) {
  590.         def->nested_section[wctx->level] = 1;
  591.         av_bprintf(&wctx->section_pbuf[wctx->level], "%s%s:",
  592.                    wctx->section_pbuf[wctx->level-1].str,
  593.                    upcase_string(buf, sizeof(buf),
  594.                                  av_x_if_null(section->element_name, section->name)));
  595.     }
  596.  
  597.     if (def->noprint_wrappers || def->nested_section[wctx->level])
  598.         return;
  599.  
  600.     if (!(section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY)))
  601.         printf("[%s]\n", upcase_string(buf, sizeof(buf), section->name));
  602. }
  603.  
  604. static void default_print_section_footer(WriterContext *wctx)
  605. {
  606.     DefaultContext *def = wctx->priv;
  607.     const struct section *section = wctx->section[wctx->level];
  608.     char buf[32];
  609.  
  610.     if (def->noprint_wrappers || def->nested_section[wctx->level])
  611.         return;
  612.  
  613.     if (!(section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY)))
  614.         printf("[/%s]\n", upcase_string(buf, sizeof(buf), section->name));
  615. }
  616.  
  617. static void default_print_str(WriterContext *wctx, const char *key, const char *value)
  618. {
  619.     DefaultContext *def = wctx->priv;
  620.  
  621.     if (!def->nokey)
  622.         printf("%s%s=", wctx->section_pbuf[wctx->level].str, key);
  623.     printf("%s\n", value);
  624. }
  625.  
  626. static void default_print_int(WriterContext *wctx, const char *key, long long int value)
  627. {
  628.     DefaultContext *def = wctx->priv;
  629.  
  630.     if (!def->nokey)
  631.         printf("%s%s=", wctx->section_pbuf[wctx->level].str, key);
  632.     printf("%lld\n", value);
  633. }
  634.  
  635. static const Writer default_writer = {
  636.     .name                  = "default",
  637.     .priv_size             = sizeof(DefaultContext),
  638.     .print_section_header  = default_print_section_header,
  639.     .print_section_footer  = default_print_section_footer,
  640.     .print_integer         = default_print_int,
  641.     .print_string          = default_print_str,
  642.     .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS,
  643.     .priv_class            = &default_class,
  644. };
  645.  
  646. /* Compact output */
  647.  
  648. /**
  649.  * Apply C-language-like string escaping.
  650.  */
  651. static const char *c_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
  652. {
  653.     const char *p;
  654.  
  655.     for (p = src; *p; p++) {
  656.         switch (*p) {
  657.         case '\b': av_bprintf(dst, "%s", "\\b");  break;
  658.         case '\f': av_bprintf(dst, "%s", "\\f");  break;
  659.         case '\n': av_bprintf(dst, "%s", "\\n");  break;
  660.         case '\r': av_bprintf(dst, "%s", "\\r");  break;
  661.         case '\\': av_bprintf(dst, "%s", "\\\\"); break;
  662.         default:
  663.             if (*p == sep)
  664.                 av_bprint_chars(dst, '\\', 1);
  665.             av_bprint_chars(dst, *p, 1);
  666.         }
  667.     }
  668.     return dst->str;
  669. }
  670.  
  671. /**
  672.  * Quote fields containing special characters, check RFC4180.
  673.  */
  674. static const char *csv_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
  675. {
  676.     char meta_chars[] = { sep, '"', '\n', '\r', '\0' };
  677.     int needs_quoting = !!src[strcspn(src, meta_chars)];
  678.  
  679.     if (needs_quoting)
  680.         av_bprint_chars(dst, '"', 1);
  681.  
  682.     for (; *src; src++) {
  683.         if (*src == '"')
  684.             av_bprint_chars(dst, '"', 1);
  685.         av_bprint_chars(dst, *src, 1);
  686.     }
  687.     if (needs_quoting)
  688.         av_bprint_chars(dst, '"', 1);
  689.     return dst->str;
  690. }
  691.  
  692. static const char *none_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
  693. {
  694.     return src;
  695. }
  696.  
  697. typedef struct CompactContext {
  698.     const AVClass *class;
  699.     char *item_sep_str;
  700.     char item_sep;
  701.     int nokey;
  702.     int print_section;
  703.     char *escape_mode_str;
  704.     const char * (*escape_str)(AVBPrint *dst, const char *src, const char sep, void *log_ctx);
  705.     int nested_section[SECTION_MAX_NB_LEVELS];
  706.     int has_nested_elems[SECTION_MAX_NB_LEVELS];
  707.     int terminate_line[SECTION_MAX_NB_LEVELS];
  708. } CompactContext;
  709.  
  710. #undef OFFSET
  711. #define OFFSET(x) offsetof(CompactContext, x)
  712.  
  713. static const AVOption compact_options[]= {
  714.     {"item_sep", "set item separator",    OFFSET(item_sep_str),    AV_OPT_TYPE_STRING, {.str="|"},  CHAR_MIN, CHAR_MAX },
  715.     {"s",        "set item separator",    OFFSET(item_sep_str),    AV_OPT_TYPE_STRING, {.str="|"},  CHAR_MIN, CHAR_MAX },
  716.     {"nokey",    "force no key printing", OFFSET(nokey),           AV_OPT_TYPE_INT,    {.i64=0},    0,        1        },
  717.     {"nk",       "force no key printing", OFFSET(nokey),           AV_OPT_TYPE_INT,    {.i64=0},    0,        1        },
  718.     {"escape",   "set escape mode",       OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="c"},  CHAR_MIN, CHAR_MAX },
  719.     {"e",        "set escape mode",       OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="c"},  CHAR_MIN, CHAR_MAX },
  720.     {"print_section", "print section name", OFFSET(print_section), AV_OPT_TYPE_INT,    {.i64=1},    0,        1        },
  721.     {"p",             "print section name", OFFSET(print_section), AV_OPT_TYPE_INT,    {.i64=1},    0,        1        },
  722.     {NULL},
  723. };
  724.  
  725. DEFINE_WRITER_CLASS(compact);
  726.  
  727. static av_cold int compact_init(WriterContext *wctx)
  728. {
  729.     CompactContext *compact = wctx->priv;
  730.  
  731.     if (strlen(compact->item_sep_str) != 1) {
  732.         av_log(wctx, AV_LOG_ERROR, "Item separator '%s' specified, but must contain a single character\n",
  733.                compact->item_sep_str);
  734.         return AVERROR(EINVAL);
  735.     }
  736.     compact->item_sep = compact->item_sep_str[0];
  737.  
  738.     if      (!strcmp(compact->escape_mode_str, "none")) compact->escape_str = none_escape_str;
  739.     else if (!strcmp(compact->escape_mode_str, "c"   )) compact->escape_str = c_escape_str;
  740.     else if (!strcmp(compact->escape_mode_str, "csv" )) compact->escape_str = csv_escape_str;
  741.     else {
  742.         av_log(wctx, AV_LOG_ERROR, "Unknown escape mode '%s'\n", compact->escape_mode_str);
  743.         return AVERROR(EINVAL);
  744.     }
  745.  
  746.     return 0;
  747. }
  748.  
  749. static void compact_print_section_header(WriterContext *wctx)
  750. {
  751.     CompactContext *compact = wctx->priv;
  752.     const struct section *section = wctx->section[wctx->level];
  753.     const struct section *parent_section = wctx->level ?
  754.         wctx->section[wctx->level-1] : NULL;
  755.     compact->terminate_line[wctx->level] = 1;
  756.     compact->has_nested_elems[wctx->level] = 0;
  757.  
  758.     av_bprint_clear(&wctx->section_pbuf[wctx->level]);
  759.     if (!(section->flags & SECTION_FLAG_IS_ARRAY) && parent_section &&
  760.         !(parent_section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))) {
  761.         compact->nested_section[wctx->level] = 1;
  762.         compact->has_nested_elems[wctx->level-1] = 1;
  763.         av_bprintf(&wctx->section_pbuf[wctx->level], "%s%s:",
  764.                    wctx->section_pbuf[wctx->level-1].str,
  765.                    (char *)av_x_if_null(section->element_name, section->name));
  766.         wctx->nb_item[wctx->level] = wctx->nb_item[wctx->level-1];
  767.     } else {
  768.         if (parent_section && compact->has_nested_elems[wctx->level-1] &&
  769.             (section->flags & SECTION_FLAG_IS_ARRAY)) {
  770.             compact->terminate_line[wctx->level-1] = 0;
  771.             printf("\n");
  772.         }
  773.         if (compact->print_section &&
  774.             !(section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY)))
  775.             printf("%s%c", section->name, compact->item_sep);
  776.     }
  777. }
  778.  
  779. static void compact_print_section_footer(WriterContext *wctx)
  780. {
  781.     CompactContext *compact = wctx->priv;
  782.  
  783.     if (!compact->nested_section[wctx->level] &&
  784.         compact->terminate_line[wctx->level] &&
  785.         !(wctx->section[wctx->level]->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY)))
  786.         printf("\n");
  787. }
  788.  
  789. static void compact_print_str(WriterContext *wctx, const char *key, const char *value)
  790. {
  791.     CompactContext *compact = wctx->priv;
  792.     AVBPrint buf;
  793.  
  794.     if (wctx->nb_item[wctx->level]) printf("%c", compact->item_sep);
  795.     if (!compact->nokey)
  796.         printf("%s%s=", wctx->section_pbuf[wctx->level].str, key);
  797.     av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
  798.     printf("%s", compact->escape_str(&buf, value, compact->item_sep, wctx));
  799.     av_bprint_finalize(&buf, NULL);
  800. }
  801.  
  802. static void compact_print_int(WriterContext *wctx, const char *key, long long int value)
  803. {
  804.     CompactContext *compact = wctx->priv;
  805.  
  806.     if (wctx->nb_item[wctx->level]) printf("%c", compact->item_sep);
  807.     if (!compact->nokey)
  808.         printf("%s%s=", wctx->section_pbuf[wctx->level].str, key);
  809.     printf("%lld", value);
  810. }
  811.  
  812. static const Writer compact_writer = {
  813.     .name                 = "compact",
  814.     .priv_size            = sizeof(CompactContext),
  815.     .init                 = compact_init,
  816.     .print_section_header = compact_print_section_header,
  817.     .print_section_footer = compact_print_section_footer,
  818.     .print_integer        = compact_print_int,
  819.     .print_string         = compact_print_str,
  820.     .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS,
  821.     .priv_class           = &compact_class,
  822. };
  823.  
  824. /* CSV output */
  825.  
  826. #undef OFFSET
  827. #define OFFSET(x) offsetof(CompactContext, x)
  828.  
  829. static const AVOption csv_options[] = {
  830.     {"item_sep", "set item separator",    OFFSET(item_sep_str),    AV_OPT_TYPE_STRING, {.str=","},  CHAR_MIN, CHAR_MAX },
  831.     {"s",        "set item separator",    OFFSET(item_sep_str),    AV_OPT_TYPE_STRING, {.str=","},  CHAR_MIN, CHAR_MAX },
  832.     {"nokey",    "force no key printing", OFFSET(nokey),           AV_OPT_TYPE_INT,    {.i64=1},    0,        1        },
  833.     {"nk",       "force no key printing", OFFSET(nokey),           AV_OPT_TYPE_INT,    {.i64=1},    0,        1        },
  834.     {"escape",   "set escape mode",       OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="csv"}, CHAR_MIN, CHAR_MAX },
  835.     {"e",        "set escape mode",       OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="csv"}, CHAR_MIN, CHAR_MAX },
  836.     {"print_section", "print section name", OFFSET(print_section), AV_OPT_TYPE_INT,    {.i64=1},    0,        1        },
  837.     {"p",             "print section name", OFFSET(print_section), AV_OPT_TYPE_INT,    {.i64=1},    0,        1        },
  838.     {NULL},
  839. };
  840.  
  841. DEFINE_WRITER_CLASS(csv);
  842.  
  843. static const Writer csv_writer = {
  844.     .name                 = "csv",
  845.     .priv_size            = sizeof(CompactContext),
  846.     .init                 = compact_init,
  847.     .print_section_header = compact_print_section_header,
  848.     .print_section_footer = compact_print_section_footer,
  849.     .print_integer        = compact_print_int,
  850.     .print_string         = compact_print_str,
  851.     .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS,
  852.     .priv_class           = &csv_class,
  853. };
  854.  
  855. /* Flat output */
  856.  
  857. typedef struct FlatContext {
  858.     const AVClass *class;
  859.     const char *sep_str;
  860.     char sep;
  861.     int hierarchical;
  862. } FlatContext;
  863.  
  864. #undef OFFSET
  865. #define OFFSET(x) offsetof(FlatContext, x)
  866.  
  867. static const AVOption flat_options[]= {
  868.     {"sep_char", "set separator",    OFFSET(sep_str),    AV_OPT_TYPE_STRING, {.str="."},  CHAR_MIN, CHAR_MAX },
  869.     {"s",        "set separator",    OFFSET(sep_str),    AV_OPT_TYPE_STRING, {.str="."},  CHAR_MIN, CHAR_MAX },
  870.     {"hierarchical", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_INT, {.i64=1}, 0, 1 },
  871.     {"h",           "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_INT, {.i64=1}, 0, 1 },
  872.     {NULL},
  873. };
  874.  
  875. DEFINE_WRITER_CLASS(flat);
  876.  
  877. static av_cold int flat_init(WriterContext *wctx)
  878. {
  879.     FlatContext *flat = wctx->priv;
  880.  
  881.     if (strlen(flat->sep_str) != 1) {
  882.         av_log(wctx, AV_LOG_ERROR, "Item separator '%s' specified, but must contain a single character\n",
  883.                flat->sep_str);
  884.         return AVERROR(EINVAL);
  885.     }
  886.     flat->sep = flat->sep_str[0];
  887.  
  888.     return 0;
  889. }
  890.  
  891. static const char *flat_escape_key_str(AVBPrint *dst, const char *src, const char sep)
  892. {
  893.     const char *p;
  894.  
  895.     for (p = src; *p; p++) {
  896.         if (!((*p >= '0' && *p <= '9') ||
  897.               (*p >= 'a' && *p <= 'z') ||
  898.               (*p >= 'A' && *p <= 'Z')))
  899.             av_bprint_chars(dst, '_', 1);
  900.         else
  901.             av_bprint_chars(dst, *p, 1);
  902.     }
  903.     return dst->str;
  904. }
  905.  
  906. static const char *flat_escape_value_str(AVBPrint *dst, const char *src)
  907. {
  908.     const char *p;
  909.  
  910.     for (p = src; *p; p++) {
  911.         switch (*p) {
  912.         case '\n': av_bprintf(dst, "%s", "\\n");  break;
  913.         case '\r': av_bprintf(dst, "%s", "\\r");  break;
  914.         case '\\': av_bprintf(dst, "%s", "\\\\"); break;
  915.         case '"':  av_bprintf(dst, "%s", "\\\""); break;
  916.         case '`':  av_bprintf(dst, "%s", "\\`");  break;
  917.         case '$':  av_bprintf(dst, "%s", "\\$");  break;
  918.         default:   av_bprint_chars(dst, *p, 1);   break;
  919.         }
  920.     }
  921.     return dst->str;
  922. }
  923.  
  924. static void flat_print_section_header(WriterContext *wctx)
  925. {
  926.     FlatContext *flat = wctx->priv;
  927.     AVBPrint *buf = &wctx->section_pbuf[wctx->level];
  928.     const struct section *section = wctx->section[wctx->level];
  929.     const struct section *parent_section = wctx->level ?
  930.         wctx->section[wctx->level-1] : NULL;
  931.  
  932.     /* build section header */
  933.     av_bprint_clear(buf);
  934.     if (!parent_section)
  935.         return;
  936.     av_bprintf(buf, "%s", wctx->section_pbuf[wctx->level-1].str);
  937.  
  938.     if (flat->hierarchical ||
  939.         !(section->flags & (SECTION_FLAG_IS_ARRAY|SECTION_FLAG_IS_WRAPPER))) {
  940.         av_bprintf(buf, "%s%s", wctx->section[wctx->level]->name, flat->sep_str);
  941.  
  942.         if (parent_section->flags & SECTION_FLAG_IS_ARRAY) {
  943.             int n = parent_section->id == SECTION_ID_PACKETS_AND_FRAMES ?
  944.                 wctx->nb_section_packet_frame : wctx->nb_item[wctx->level-1];
  945.             av_bprintf(buf, "%d%s", n, flat->sep_str);
  946.         }
  947.     }
  948. }
  949.  
  950. static void flat_print_int(WriterContext *wctx, const char *key, long long int value)
  951. {
  952.     printf("%s%s=%lld\n", wctx->section_pbuf[wctx->level].str, key, value);
  953. }
  954.  
  955. static void flat_print_str(WriterContext *wctx, const char *key, const char *value)
  956. {
  957.     FlatContext *flat = wctx->priv;
  958.     AVBPrint buf;
  959.  
  960.     printf("%s", wctx->section_pbuf[wctx->level].str);
  961.     av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
  962.     printf("%s=", flat_escape_key_str(&buf, key, flat->sep));
  963.     av_bprint_clear(&buf);
  964.     printf("\"%s\"\n", flat_escape_value_str(&buf, value));
  965.     av_bprint_finalize(&buf, NULL);
  966. }
  967.  
  968. static const Writer flat_writer = {
  969.     .name                  = "flat",
  970.     .priv_size             = sizeof(FlatContext),
  971.     .init                  = flat_init,
  972.     .print_section_header  = flat_print_section_header,
  973.     .print_integer         = flat_print_int,
  974.     .print_string          = flat_print_str,
  975.     .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS|WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER,
  976.     .priv_class            = &flat_class,
  977. };
  978.  
  979. /* INI format output */
  980.  
  981. typedef struct {
  982.     const AVClass *class;
  983.     int hierarchical;
  984. } INIContext;
  985.  
  986. #undef OFFSET
  987. #define OFFSET(x) offsetof(INIContext, x)
  988.  
  989. static const AVOption ini_options[] = {
  990.     {"hierarchical", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_INT, {.i64=1}, 0, 1 },
  991.     {"h",           "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_INT, {.i64=1}, 0, 1 },
  992.     {NULL},
  993. };
  994.  
  995. DEFINE_WRITER_CLASS(ini);
  996.  
  997. static char *ini_escape_str(AVBPrint *dst, const char *src)
  998. {
  999.     int i = 0;
  1000.     char c = 0;
  1001.  
  1002.     while (c = src[i++]) {
  1003.         switch (c) {
  1004.         case '\b': av_bprintf(dst, "%s", "\\b"); break;
  1005.         case '\f': av_bprintf(dst, "%s", "\\f"); break;
  1006.         case '\n': av_bprintf(dst, "%s", "\\n"); break;
  1007.         case '\r': av_bprintf(dst, "%s", "\\r"); break;
  1008.         case '\t': av_bprintf(dst, "%s", "\\t"); break;
  1009.         case '\\':
  1010.         case '#' :
  1011.         case '=' :
  1012.         case ':' : av_bprint_chars(dst, '\\', 1);
  1013.         default:
  1014.             if ((unsigned char)c < 32)
  1015.                 av_bprintf(dst, "\\x00%02x", c & 0xff);
  1016.             else
  1017.                 av_bprint_chars(dst, c, 1);
  1018.             break;
  1019.         }
  1020.     }
  1021.     return dst->str;
  1022. }
  1023.  
  1024. static void ini_print_section_header(WriterContext *wctx)
  1025. {
  1026.     INIContext *ini = wctx->priv;
  1027.     AVBPrint *buf = &wctx->section_pbuf[wctx->level];
  1028.     const struct section *section = wctx->section[wctx->level];
  1029.     const struct section *parent_section = wctx->level ?
  1030.         wctx->section[wctx->level-1] : NULL;
  1031.  
  1032.     av_bprint_clear(buf);
  1033.     if (!parent_section) {
  1034.         printf("# ffprobe output\n\n");
  1035.         return;
  1036.     }
  1037.  
  1038.     if (wctx->nb_item[wctx->level-1])
  1039.         printf("\n");
  1040.  
  1041.     av_bprintf(buf, "%s", wctx->section_pbuf[wctx->level-1].str);
  1042.     if (ini->hierarchical ||
  1043.         !(section->flags & (SECTION_FLAG_IS_ARRAY|SECTION_FLAG_IS_WRAPPER))) {
  1044.         av_bprintf(buf, "%s%s", buf->str[0] ? "." : "", wctx->section[wctx->level]->name);
  1045.  
  1046.         if (parent_section->flags & SECTION_FLAG_IS_ARRAY) {
  1047.             int n = parent_section->id == SECTION_ID_PACKETS_AND_FRAMES ?
  1048.                 wctx->nb_section_packet_frame : wctx->nb_item[wctx->level-1];
  1049.             av_bprintf(buf, ".%d", n);
  1050.         }
  1051.     }
  1052.  
  1053.     if (!(section->flags & (SECTION_FLAG_IS_ARRAY|SECTION_FLAG_IS_WRAPPER)))
  1054.         printf("[%s]\n", buf->str);
  1055. }
  1056.  
  1057. static void ini_print_str(WriterContext *wctx, const char *key, const char *value)
  1058. {
  1059.     AVBPrint buf;
  1060.  
  1061.     av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
  1062.     printf("%s=", ini_escape_str(&buf, key));
  1063.     av_bprint_clear(&buf);
  1064.     printf("%s\n", ini_escape_str(&buf, value));
  1065.     av_bprint_finalize(&buf, NULL);
  1066. }
  1067.  
  1068. static void ini_print_int(WriterContext *wctx, const char *key, long long int value)
  1069. {
  1070.     printf("%s=%lld\n", key, value);
  1071. }
  1072.  
  1073. static const Writer ini_writer = {
  1074.     .name                  = "ini",
  1075.     .priv_size             = sizeof(INIContext),
  1076.     .print_section_header  = ini_print_section_header,
  1077.     .print_integer         = ini_print_int,
  1078.     .print_string          = ini_print_str,
  1079.     .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS|WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER,
  1080.     .priv_class            = &ini_class,
  1081. };
  1082.  
  1083. /* JSON output */
  1084.  
  1085. typedef struct {
  1086.     const AVClass *class;
  1087.     int indent_level;
  1088.     int compact;
  1089.     const char *item_sep, *item_start_end;
  1090. } JSONContext;
  1091.  
  1092. #undef OFFSET
  1093. #define OFFSET(x) offsetof(JSONContext, x)
  1094.  
  1095. static const AVOption json_options[]= {
  1096.     { "compact", "enable compact output", OFFSET(compact), AV_OPT_TYPE_INT, {.i64=0}, 0, 1 },
  1097.     { "c",       "enable compact output", OFFSET(compact), AV_OPT_TYPE_INT, {.i64=0}, 0, 1 },
  1098.     { NULL }
  1099. };
  1100.  
  1101. DEFINE_WRITER_CLASS(json);
  1102.  
  1103. static av_cold int json_init(WriterContext *wctx)
  1104. {
  1105.     JSONContext *json = wctx->priv;
  1106.  
  1107.     json->item_sep       = json->compact ? ", " : ",\n";
  1108.     json->item_start_end = json->compact ? " "  : "\n";
  1109.  
  1110.     return 0;
  1111. }
  1112.  
  1113. static const char *json_escape_str(AVBPrint *dst, const char *src, void *log_ctx)
  1114. {
  1115.     static const char json_escape[] = {'"', '\\', '\b', '\f', '\n', '\r', '\t', 0};
  1116.     static const char json_subst[]  = {'"', '\\',  'b',  'f',  'n',  'r',  't', 0};
  1117.     const char *p;
  1118.  
  1119.     for (p = src; *p; p++) {
  1120.         char *s = strchr(json_escape, *p);
  1121.         if (s) {
  1122.             av_bprint_chars(dst, '\\', 1);
  1123.             av_bprint_chars(dst, json_subst[s - json_escape], 1);
  1124.         } else if ((unsigned char)*p < 32) {
  1125.             av_bprintf(dst, "\\u00%02x", *p & 0xff);
  1126.         } else {
  1127.             av_bprint_chars(dst, *p, 1);
  1128.         }
  1129.     }
  1130.     return dst->str;
  1131. }
  1132.  
  1133. #define JSON_INDENT() printf("%*c", json->indent_level * 4, ' ')
  1134.  
  1135. static void json_print_section_header(WriterContext *wctx)
  1136. {
  1137.     JSONContext *json = wctx->priv;
  1138.     AVBPrint buf;
  1139.     const struct section *section = wctx->section[wctx->level];
  1140.     const struct section *parent_section = wctx->level ?
  1141.         wctx->section[wctx->level-1] : NULL;
  1142.  
  1143.     if (wctx->level && wctx->nb_item[wctx->level-1])
  1144.         printf(",\n");
  1145.  
  1146.     if (section->flags & SECTION_FLAG_IS_WRAPPER) {
  1147.         printf("{\n");
  1148.         json->indent_level++;
  1149.     } else {
  1150.         av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
  1151.         json_escape_str(&buf, section->name, wctx);
  1152.         JSON_INDENT();
  1153.  
  1154.         json->indent_level++;
  1155.         if (section->flags & SECTION_FLAG_IS_ARRAY) {
  1156.             printf("\"%s\": [\n", buf.str);
  1157.         } else if (parent_section && !(parent_section->flags & SECTION_FLAG_IS_ARRAY)) {
  1158.             printf("\"%s\": {%s", buf.str, json->item_start_end);
  1159.         } else {
  1160.             printf("{%s", json->item_start_end);
  1161.  
  1162.             /* this is required so the parser can distinguish between packets and frames */
  1163.             if (parent_section && parent_section->id == SECTION_ID_PACKETS_AND_FRAMES) {
  1164.                 if (!json->compact)
  1165.                     JSON_INDENT();
  1166.                 printf("\"type\": \"%s\"%s", section->name, json->item_sep);
  1167.             }
  1168.         }
  1169.         av_bprint_finalize(&buf, NULL);
  1170.     }
  1171. }
  1172.  
  1173. static void json_print_section_footer(WriterContext *wctx)
  1174. {
  1175.     JSONContext *json = wctx->priv;
  1176.     const struct section *section = wctx->section[wctx->level];
  1177.  
  1178.     if (wctx->level == 0) {
  1179.         json->indent_level--;
  1180.         printf("\n}\n");
  1181.     } else if (section->flags & SECTION_FLAG_IS_ARRAY) {
  1182.         printf("\n");
  1183.         json->indent_level--;
  1184.         JSON_INDENT();
  1185.         printf("]");
  1186.     } else {
  1187.         printf("%s", json->item_start_end);
  1188.         json->indent_level--;
  1189.         if (!json->compact)
  1190.             JSON_INDENT();
  1191.         printf("}");
  1192.     }
  1193. }
  1194.  
  1195. static inline void json_print_item_str(WriterContext *wctx,
  1196.                                        const char *key, const char *value)
  1197. {
  1198.     AVBPrint buf;
  1199.  
  1200.     av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
  1201.     printf("\"%s\":", json_escape_str(&buf, key,   wctx));
  1202.     av_bprint_clear(&buf);
  1203.     printf(" \"%s\"", json_escape_str(&buf, value, wctx));
  1204.     av_bprint_finalize(&buf, NULL);
  1205. }
  1206.  
  1207. static void json_print_str(WriterContext *wctx, const char *key, const char *value)
  1208. {
  1209.     JSONContext *json = wctx->priv;
  1210.  
  1211.     if (wctx->nb_item[wctx->level])
  1212.         printf("%s", json->item_sep);
  1213.     if (!json->compact)
  1214.         JSON_INDENT();
  1215.     json_print_item_str(wctx, key, value);
  1216. }
  1217.  
  1218. static void json_print_int(WriterContext *wctx, const char *key, long long int value)
  1219. {
  1220.     JSONContext *json = wctx->priv;
  1221.     AVBPrint buf;
  1222.  
  1223.     if (wctx->nb_item[wctx->level])
  1224.         printf("%s", json->item_sep);
  1225.     if (!json->compact)
  1226.         JSON_INDENT();
  1227.  
  1228.     av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
  1229.     printf("\"%s\": %lld", json_escape_str(&buf, key, wctx), value);
  1230.     av_bprint_finalize(&buf, NULL);
  1231. }
  1232.  
  1233. static const Writer json_writer = {
  1234.     .name                 = "json",
  1235.     .priv_size            = sizeof(JSONContext),
  1236.     .init                 = json_init,
  1237.     .print_section_header = json_print_section_header,
  1238.     .print_section_footer = json_print_section_footer,
  1239.     .print_integer        = json_print_int,
  1240.     .print_string         = json_print_str,
  1241.     .flags = WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER,
  1242.     .priv_class           = &json_class,
  1243. };
  1244.  
  1245. /* XML output */
  1246.  
  1247. typedef struct {
  1248.     const AVClass *class;
  1249.     int within_tag;
  1250.     int indent_level;
  1251.     int fully_qualified;
  1252.     int xsd_strict;
  1253. } XMLContext;
  1254.  
  1255. #undef OFFSET
  1256. #define OFFSET(x) offsetof(XMLContext, x)
  1257.  
  1258. static const AVOption xml_options[] = {
  1259.     {"fully_qualified", "specify if the output should be fully qualified", OFFSET(fully_qualified), AV_OPT_TYPE_INT, {.i64=0},  0, 1 },
  1260.     {"q",               "specify if the output should be fully qualified", OFFSET(fully_qualified), AV_OPT_TYPE_INT, {.i64=0},  0, 1 },
  1261.     {"xsd_strict",      "ensure that the output is XSD compliant",         OFFSET(xsd_strict),      AV_OPT_TYPE_INT, {.i64=0},  0, 1 },
  1262.     {"x",               "ensure that the output is XSD compliant",         OFFSET(xsd_strict),      AV_OPT_TYPE_INT, {.i64=0},  0, 1 },
  1263.     {NULL},
  1264. };
  1265.  
  1266. DEFINE_WRITER_CLASS(xml);
  1267.  
  1268. static av_cold int xml_init(WriterContext *wctx)
  1269. {
  1270.     XMLContext *xml = wctx->priv;
  1271.  
  1272.     if (xml->xsd_strict) {
  1273.         xml->fully_qualified = 1;
  1274. #define CHECK_COMPLIANCE(opt, opt_name)                                 \
  1275.         if (opt) {                                                      \
  1276.             av_log(wctx, AV_LOG_ERROR,                                  \
  1277.                    "XSD-compliant output selected but option '%s' was selected, XML output may be non-compliant.\n" \
  1278.                    "You need to disable such option with '-no%s'\n", opt_name, opt_name); \
  1279.             return AVERROR(EINVAL);                                     \
  1280.         }
  1281.         CHECK_COMPLIANCE(show_private_data, "private");
  1282.         CHECK_COMPLIANCE(show_value_unit,   "unit");
  1283.         CHECK_COMPLIANCE(use_value_prefix,  "prefix");
  1284.  
  1285.         if (do_show_frames && do_show_packets) {
  1286.             av_log(wctx, AV_LOG_ERROR,
  1287.                    "Interleaved frames and packets are not allowed in XSD. "
  1288.                    "Select only one between the -show_frames and the -show_packets options.\n");
  1289.             return AVERROR(EINVAL);
  1290.         }
  1291.     }
  1292.  
  1293.     return 0;
  1294. }
  1295.  
  1296. static const char *xml_escape_str(AVBPrint *dst, const char *src, void *log_ctx)
  1297. {
  1298.     const char *p;
  1299.  
  1300.     for (p = src; *p; p++) {
  1301.         switch (*p) {
  1302.         case '&' : av_bprintf(dst, "%s", "&amp;");  break;
  1303.         case '<' : av_bprintf(dst, "%s", "&lt;");   break;
  1304.         case '>' : av_bprintf(dst, "%s", "&gt;");   break;
  1305.         case '"' : av_bprintf(dst, "%s", "&quot;"); break;
  1306.         case '\'': av_bprintf(dst, "%s", "&apos;"); break;
  1307.         default: av_bprint_chars(dst, *p, 1);
  1308.         }
  1309.     }
  1310.  
  1311.     return dst->str;
  1312. }
  1313.  
  1314. #define XML_INDENT() printf("%*c", xml->indent_level * 4, ' ')
  1315.  
  1316. static void xml_print_section_header(WriterContext *wctx)
  1317. {
  1318.     XMLContext *xml = wctx->priv;
  1319.     const struct section *section = wctx->section[wctx->level];
  1320.     const struct section *parent_section = wctx->level ?
  1321.         wctx->section[wctx->level-1] : NULL;
  1322.  
  1323.     if (wctx->level == 0) {
  1324.         const char *qual = " xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' "
  1325.             "xmlns:ffprobe='http://www.ffmpeg.org/schema/ffprobe' "
  1326.             "xsi:schemaLocation='http://www.ffmpeg.org/schema/ffprobe ffprobe.xsd'";
  1327.  
  1328.         printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
  1329.         printf("<%sffprobe%s>\n",
  1330.                xml->fully_qualified ? "ffprobe:" : "",
  1331.                xml->fully_qualified ? qual : "");
  1332.         return;
  1333.     }
  1334.  
  1335.     if (xml->within_tag) {
  1336.         xml->within_tag = 0;
  1337.         printf(">\n");
  1338.     }
  1339.     if (section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS) {
  1340.         xml->indent_level++;
  1341.     } else {
  1342.         if (parent_section && (parent_section->flags & SECTION_FLAG_IS_WRAPPER) &&
  1343.             wctx->level && wctx->nb_item[wctx->level-1])
  1344.             printf("\n");
  1345.         xml->indent_level++;
  1346.  
  1347.         if (section->flags & SECTION_FLAG_IS_ARRAY) {
  1348.             XML_INDENT(); printf("<%s>\n", section->name);
  1349.         } else {
  1350.             XML_INDENT(); printf("<%s ", section->name);
  1351.             xml->within_tag = 1;
  1352.         }
  1353.     }
  1354. }
  1355.  
  1356. static void xml_print_section_footer(WriterContext *wctx)
  1357. {
  1358.     XMLContext *xml = wctx->priv;
  1359.     const struct section *section = wctx->section[wctx->level];
  1360.  
  1361.     if (wctx->level == 0) {
  1362.         printf("</%sffprobe>\n", xml->fully_qualified ? "ffprobe:" : "");
  1363.     } else if (xml->within_tag) {
  1364.         xml->within_tag = 0;
  1365.         printf("/>\n");
  1366.         xml->indent_level--;
  1367.     } else if (section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS) {
  1368.         xml->indent_level--;
  1369.     } else {
  1370.         XML_INDENT(); printf("</%s>\n", section->name);
  1371.         xml->indent_level--;
  1372.     }
  1373. }
  1374.  
  1375. static void xml_print_str(WriterContext *wctx, const char *key, const char *value)
  1376. {
  1377.     AVBPrint buf;
  1378.     XMLContext *xml = wctx->priv;
  1379.     const struct section *section = wctx->section[wctx->level];
  1380.  
  1381.     av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
  1382.  
  1383.     if (section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS) {
  1384.         XML_INDENT();
  1385.         printf("<%s key=\"%s\"",
  1386.                section->element_name, xml_escape_str(&buf, key, wctx));
  1387.         av_bprint_clear(&buf);
  1388.         printf(" value=\"%s\"/>\n", xml_escape_str(&buf, value, wctx));
  1389.     } else {
  1390.         if (wctx->nb_item[wctx->level])
  1391.             printf(" ");
  1392.         printf("%s=\"%s\"", key, xml_escape_str(&buf, value, wctx));
  1393.     }
  1394.  
  1395.     av_bprint_finalize(&buf, NULL);
  1396. }
  1397.  
  1398. static void xml_print_int(WriterContext *wctx, const char *key, long long int value)
  1399. {
  1400.     if (wctx->nb_item[wctx->level])
  1401.         printf(" ");
  1402.     printf("%s=\"%lld\"", key, value);
  1403. }
  1404.  
  1405. static Writer xml_writer = {
  1406.     .name                 = "xml",
  1407.     .priv_size            = sizeof(XMLContext),
  1408.     .init                 = xml_init,
  1409.     .print_section_header = xml_print_section_header,
  1410.     .print_section_footer = xml_print_section_footer,
  1411.     .print_integer        = xml_print_int,
  1412.     .print_string         = xml_print_str,
  1413.     .flags = WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER,
  1414.     .priv_class           = &xml_class,
  1415. };
  1416.  
  1417. static void writer_register_all(void)
  1418. {
  1419.     static int initialized;
  1420.  
  1421.     if (initialized)
  1422.         return;
  1423.     initialized = 1;
  1424.  
  1425.     writer_register(&default_writer);
  1426.     writer_register(&compact_writer);
  1427.     writer_register(&csv_writer);
  1428.     writer_register(&flat_writer);
  1429.     writer_register(&ini_writer);
  1430.     writer_register(&json_writer);
  1431.     writer_register(&xml_writer);
  1432. }
  1433.  
  1434. #define print_fmt(k, f, ...) do {              \
  1435.     av_bprint_clear(&pbuf);                    \
  1436.     av_bprintf(&pbuf, f, __VA_ARGS__);         \
  1437.     writer_print_string(w, k, pbuf.str, 0);    \
  1438. } while (0)
  1439.  
  1440. #define print_int(k, v)         writer_print_integer(w, k, v)
  1441. #define print_q(k, v, s)        writer_print_rational(w, k, v, s)
  1442. #define print_str(k, v)         writer_print_string(w, k, v, 0)
  1443. #define print_str_opt(k, v)     writer_print_string(w, k, v, 1)
  1444. #define print_time(k, v, tb)    writer_print_time(w, k, v, tb, 0)
  1445. #define print_ts(k, v)          writer_print_ts(w, k, v, 0)
  1446. #define print_duration_time(k, v, tb) writer_print_time(w, k, v, tb, 1)
  1447. #define print_duration_ts(k, v)       writer_print_ts(w, k, v, 1)
  1448. #define print_val(k, v, u) do {                                     \
  1449.     struct unit_value uv;                                           \
  1450.     uv.val.i = v;                                                   \
  1451.     uv.unit = u;                                                    \
  1452.     writer_print_string(w, k, value_string(val_str, sizeof(val_str), uv), 0); \
  1453. } while (0)
  1454.  
  1455. #define print_section_header(s) writer_print_section_header(w, s)
  1456. #define print_section_footer(s) writer_print_section_footer(w, s)
  1457.  
  1458. static inline void show_tags(WriterContext *wctx, AVDictionary *tags, int section_id)
  1459. {
  1460.     AVDictionaryEntry *tag = NULL;
  1461.  
  1462.     if (!tags)
  1463.         return;
  1464.     writer_print_section_header(wctx, section_id);
  1465.     while ((tag = av_dict_get(tags, "", tag, AV_DICT_IGNORE_SUFFIX)))
  1466.         writer_print_string(wctx, tag->key, tag->value, 0);
  1467.     writer_print_section_footer(wctx);
  1468. }
  1469.  
  1470. static void show_packet(WriterContext *w, AVFormatContext *fmt_ctx, AVPacket *pkt, int packet_idx)
  1471. {
  1472.     char val_str[128];
  1473.     AVStream *st = fmt_ctx->streams[pkt->stream_index];
  1474.     AVBPrint pbuf;
  1475.     const char *s;
  1476.  
  1477.     av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
  1478.  
  1479.     writer_print_section_header(w, SECTION_ID_PACKET);
  1480.  
  1481.     s = av_get_media_type_string(st->codec->codec_type);
  1482.     if (s) print_str    ("codec_type", s);
  1483.     else   print_str_opt("codec_type", "unknown");
  1484.     print_int("stream_index",     pkt->stream_index);
  1485.     print_ts  ("pts",             pkt->pts);
  1486.     print_time("pts_time",        pkt->pts, &st->time_base);
  1487.     print_ts  ("dts",             pkt->dts);
  1488.     print_time("dts_time",        pkt->dts, &st->time_base);
  1489.     print_duration_ts("duration",        pkt->duration);
  1490.     print_duration_time("duration_time", pkt->duration, &st->time_base);
  1491.     print_duration_ts("convergence_duration", pkt->convergence_duration);
  1492.     print_duration_time("convergence_duration_time", pkt->convergence_duration, &st->time_base);
  1493.     print_val("size",             pkt->size, unit_byte_str);
  1494.     if (pkt->pos != -1) print_fmt    ("pos", "%"PRId64, pkt->pos);
  1495.     else                print_str_opt("pos", "N/A");
  1496.     print_fmt("flags", "%c",      pkt->flags & AV_PKT_FLAG_KEY ? 'K' : '_');
  1497.     if (do_show_data)
  1498.         writer_print_data(w, "data", pkt->data, pkt->size);
  1499.     writer_print_section_footer(w);
  1500.  
  1501.     av_bprint_finalize(&pbuf, NULL);
  1502.     fflush(stdout);
  1503. }
  1504.  
  1505. static void show_frame(WriterContext *w, AVFrame *frame, AVStream *stream,
  1506.                        AVFormatContext *fmt_ctx)
  1507. {
  1508.     AVBPrint pbuf;
  1509.     const char *s;
  1510.  
  1511.     av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
  1512.  
  1513.     writer_print_section_header(w, SECTION_ID_FRAME);
  1514.  
  1515.     s = av_get_media_type_string(stream->codec->codec_type);
  1516.     if (s) print_str    ("media_type", s);
  1517.     else   print_str_opt("media_type", "unknown");
  1518.     print_int("key_frame",              frame->key_frame);
  1519.     print_ts  ("pkt_pts",               frame->pkt_pts);
  1520.     print_time("pkt_pts_time",          frame->pkt_pts, &stream->time_base);
  1521.     print_ts  ("pkt_dts",               frame->pkt_dts);
  1522.     print_time("pkt_dts_time",          frame->pkt_dts, &stream->time_base);
  1523.     print_duration_ts  ("pkt_duration",      av_frame_get_pkt_duration(frame));
  1524.     print_duration_time("pkt_duration_time", av_frame_get_pkt_duration(frame), &stream->time_base);
  1525.     if (av_frame_get_pkt_pos (frame) != -1) print_fmt    ("pkt_pos", "%"PRId64, av_frame_get_pkt_pos(frame));
  1526.     else                      print_str_opt("pkt_pos", "N/A");
  1527.     if (av_frame_get_pkt_size(frame) != -1) print_fmt    ("pkt_size", "%d", av_frame_get_pkt_size(frame));
  1528.     else                       print_str_opt("pkt_size", "N/A");
  1529.  
  1530.     switch (stream->codec->codec_type) {
  1531.         AVRational sar;
  1532.  
  1533.     case AVMEDIA_TYPE_VIDEO:
  1534.         print_int("width",                  frame->width);
  1535.         print_int("height",                 frame->height);
  1536.         s = av_get_pix_fmt_name(frame->format);
  1537.         if (s) print_str    ("pix_fmt", s);
  1538.         else   print_str_opt("pix_fmt", "unknown");
  1539.         sar = av_guess_sample_aspect_ratio(fmt_ctx, stream, frame);
  1540.         if (sar.num) {
  1541.             print_q("sample_aspect_ratio", sar, ':');
  1542.         } else {
  1543.             print_str_opt("sample_aspect_ratio", "N/A");
  1544.         }
  1545.         print_fmt("pict_type",              "%c", av_get_picture_type_char(frame->pict_type));
  1546.         print_int("coded_picture_number",   frame->coded_picture_number);
  1547.         print_int("display_picture_number", frame->display_picture_number);
  1548.         print_int("interlaced_frame",       frame->interlaced_frame);
  1549.         print_int("top_field_first",        frame->top_field_first);
  1550.         print_int("repeat_pict",            frame->repeat_pict);
  1551.         break;
  1552.  
  1553.     case AVMEDIA_TYPE_AUDIO:
  1554.         s = av_get_sample_fmt_name(frame->format);
  1555.         if (s) print_str    ("sample_fmt", s);
  1556.         else   print_str_opt("sample_fmt", "unknown");
  1557.         print_int("nb_samples",         frame->nb_samples);
  1558.         print_int("channels", av_frame_get_channels(frame));
  1559.         if (av_frame_get_channel_layout(frame)) {
  1560.             av_bprint_clear(&pbuf);
  1561.             av_bprint_channel_layout(&pbuf, av_frame_get_channels(frame),
  1562.                                      av_frame_get_channel_layout(frame));
  1563.             print_str    ("channel_layout", pbuf.str);
  1564.         } else
  1565.             print_str_opt("channel_layout", "unknown");
  1566.         break;
  1567.     }
  1568.     show_tags(w, av_frame_get_metadata(frame), SECTION_ID_FRAME_TAGS);
  1569.  
  1570.     writer_print_section_footer(w);
  1571.  
  1572.     av_bprint_finalize(&pbuf, NULL);
  1573.     fflush(stdout);
  1574. }
  1575.  
  1576. static av_always_inline int process_frame(WriterContext *w,
  1577.                                           AVFormatContext *fmt_ctx,
  1578.                                           AVFrame *frame, AVPacket *pkt)
  1579. {
  1580.     AVCodecContext *dec_ctx = fmt_ctx->streams[pkt->stream_index]->codec;
  1581.     int ret = 0, got_frame = 0;
  1582.  
  1583.     avcodec_get_frame_defaults(frame);
  1584.     if (dec_ctx->codec) {
  1585.         switch (dec_ctx->codec_type) {
  1586.         case AVMEDIA_TYPE_VIDEO:
  1587.             ret = avcodec_decode_video2(dec_ctx, frame, &got_frame, pkt);
  1588.             break;
  1589.  
  1590.         case AVMEDIA_TYPE_AUDIO:
  1591.             ret = avcodec_decode_audio4(dec_ctx, frame, &got_frame, pkt);
  1592.             break;
  1593.         }
  1594.     }
  1595.  
  1596.     if (ret < 0)
  1597.         return ret;
  1598.     ret = FFMIN(ret, pkt->size); /* guard against bogus return values */
  1599.     pkt->data += ret;
  1600.     pkt->size -= ret;
  1601.     if (got_frame) {
  1602.         nb_streams_frames[pkt->stream_index]++;
  1603.         if (do_show_frames)
  1604.             show_frame(w, frame, fmt_ctx->streams[pkt->stream_index], fmt_ctx);
  1605.     }
  1606.     return got_frame;
  1607. }
  1608.  
  1609. static void log_read_interval(const ReadInterval *interval, void *log_ctx, int log_level)
  1610. {
  1611.     av_log(log_ctx, log_level, "id:%d", interval->id);
  1612.  
  1613.     if (interval->has_start) {
  1614.         av_log(log_ctx, log_level, " start:%s%s", interval->start_is_offset ? "+" : "",
  1615.                av_ts2timestr(interval->start, &AV_TIME_BASE_Q));
  1616.     } else {
  1617.         av_log(log_ctx, log_level, " start:N/A");
  1618.     }
  1619.  
  1620.     if (interval->has_end) {
  1621.         av_log(log_ctx, log_level, " end:%s", interval->end_is_offset ? "+" : "");
  1622.         if (interval->duration_frames)
  1623.             av_log(log_ctx, log_level, "#%"PRId64, interval->end);
  1624.         else
  1625.             av_log(log_ctx, log_level, "%s", av_ts2timestr(interval->end, &AV_TIME_BASE_Q));
  1626.     } else {
  1627.         av_log(log_ctx, log_level, " end:N/A");
  1628.     }
  1629.  
  1630.     av_log(log_ctx, log_level, "\n");
  1631. }
  1632.  
  1633. static int read_interval_packets(WriterContext *w, AVFormatContext *fmt_ctx,
  1634.                                  const ReadInterval *interval, int64_t *cur_ts)
  1635. {
  1636.     AVPacket pkt, pkt1;
  1637.     AVFrame frame;
  1638.     int ret = 0, i = 0, frame_count = 0;
  1639.     int64_t start = -INT64_MAX, end = interval->end;
  1640.     int has_start = 0, has_end = interval->has_end && !interval->end_is_offset;
  1641.  
  1642.     av_init_packet(&pkt);
  1643.  
  1644.     av_log(NULL, AV_LOG_VERBOSE, "Processing read interval ");
  1645.     log_read_interval(interval, NULL, AV_LOG_VERBOSE);
  1646.  
  1647.     if (interval->has_start) {
  1648.         int64_t target;
  1649.         if (interval->start_is_offset) {
  1650.             if (*cur_ts == AV_NOPTS_VALUE) {
  1651.                 av_log(NULL, AV_LOG_ERROR,
  1652.                        "Could not seek to relative position since current "
  1653.                        "timestamp is not defined\n");
  1654.                 ret = AVERROR(EINVAL);
  1655.                 goto end;
  1656.             }
  1657.             target = *cur_ts + interval->start;
  1658.         } else {
  1659.             target = interval->start;
  1660.         }
  1661.  
  1662.         av_log(NULL, AV_LOG_VERBOSE, "Seeking to read interval start point %s\n",
  1663.                av_ts2timestr(target, &AV_TIME_BASE_Q));
  1664.         if ((ret = avformat_seek_file(fmt_ctx, -1, -INT64_MAX, target, INT64_MAX, 0)) < 0) {
  1665.             av_log(NULL, AV_LOG_ERROR, "Could not seek to position %"PRId64": %s\n",
  1666.                    interval->start, av_err2str(ret));
  1667.             goto end;
  1668.         }
  1669.     }
  1670.  
  1671.     while (!av_read_frame(fmt_ctx, &pkt)) {
  1672.         if (selected_streams[pkt.stream_index]) {
  1673.             AVRational tb = fmt_ctx->streams[pkt.stream_index]->time_base;
  1674.  
  1675.             if (pkt.pts != AV_NOPTS_VALUE)
  1676.                 *cur_ts = av_rescale_q(pkt.pts, tb, AV_TIME_BASE_Q);
  1677.  
  1678.             if (!has_start && *cur_ts != AV_NOPTS_VALUE) {
  1679.                 start = *cur_ts;
  1680.                 has_start = 1;
  1681.             }
  1682.  
  1683.             if (has_start && !has_end && interval->end_is_offset) {
  1684.                 end = start + interval->end;
  1685.                 has_end = 1;
  1686.             }
  1687.  
  1688.             if (interval->end_is_offset && interval->duration_frames) {
  1689.                 if (frame_count >= interval->end)
  1690.                     break;
  1691.             } else if (has_end && *cur_ts != AV_NOPTS_VALUE && *cur_ts >= end) {
  1692.                 break;
  1693.             }
  1694.  
  1695.             frame_count++;
  1696.             if (do_read_packets) {
  1697.                 if (do_show_packets)
  1698.                     show_packet(w, fmt_ctx, &pkt, i++);
  1699.                 nb_streams_packets[pkt.stream_index]++;
  1700.             }
  1701.             if (do_read_frames) {
  1702.                 pkt1 = pkt;
  1703.                 while (pkt1.size && process_frame(w, fmt_ctx, &frame, &pkt1) > 0);
  1704.             }
  1705.         }
  1706.         av_free_packet(&pkt);
  1707.     }
  1708.     av_init_packet(&pkt);
  1709.     pkt.data = NULL;
  1710.     pkt.size = 0;
  1711.     //Flush remaining frames that are cached in the decoder
  1712.     for (i = 0; i < fmt_ctx->nb_streams; i++) {
  1713.         pkt.stream_index = i;
  1714.         if (do_read_frames)
  1715.             while (process_frame(w, fmt_ctx, &frame, &pkt) > 0);
  1716.     }
  1717.  
  1718. end:
  1719.     if (ret < 0) {
  1720.         av_log(NULL, AV_LOG_ERROR, "Could not read packets in interval ");
  1721.         log_read_interval(interval, NULL, AV_LOG_ERROR);
  1722.     }
  1723.     return ret;
  1724. }
  1725.  
  1726. static void read_packets(WriterContext *w, AVFormatContext *fmt_ctx)
  1727. {
  1728.     int i, ret = 0;
  1729.     int64_t cur_ts = fmt_ctx->start_time;
  1730.  
  1731.     if (read_intervals_nb == 0) {
  1732.         ReadInterval interval = (ReadInterval) { .has_start = 0, .has_end = 0 };
  1733.         ret = read_interval_packets(w, fmt_ctx, &interval, &cur_ts);
  1734.     } else {
  1735.         for (i = 0; i < read_intervals_nb; i++) {
  1736.             ret = read_interval_packets(w, fmt_ctx, &read_intervals[i], &cur_ts);
  1737.             if (ret < 0)
  1738.                 break;
  1739.         }
  1740.     }
  1741. }
  1742.  
  1743. static void show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_idx, int in_program)
  1744. {
  1745.     AVStream *stream = fmt_ctx->streams[stream_idx];
  1746.     AVCodecContext *dec_ctx;
  1747.     const AVCodec *dec;
  1748.     char val_str[128];
  1749.     const char *s;
  1750.     AVRational sar, dar;
  1751.     AVBPrint pbuf;
  1752.  
  1753.     av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
  1754.  
  1755.     writer_print_section_header(w, in_program ? SECTION_ID_PROGRAM_STREAM : SECTION_ID_STREAM);
  1756.  
  1757.     print_int("index", stream->index);
  1758.  
  1759.     if ((dec_ctx = stream->codec)) {
  1760.         const char *profile = NULL;
  1761.         dec = dec_ctx->codec;
  1762.         if (dec) {
  1763.             print_str("codec_name", dec->name);
  1764.             if (!do_bitexact) {
  1765.                 if (dec->long_name) print_str    ("codec_long_name", dec->long_name);
  1766.                 else                print_str_opt("codec_long_name", "unknown");
  1767.             }
  1768.         } else {
  1769.             print_str_opt("codec_name", "unknown");
  1770.             if (!do_bitexact) {
  1771.                 print_str_opt("codec_long_name", "unknown");
  1772.             }
  1773.         }
  1774.  
  1775.         if (dec && (profile = av_get_profile_name(dec, dec_ctx->profile)))
  1776.             print_str("profile", profile);
  1777.         else
  1778.             print_str_opt("profile", "unknown");
  1779.  
  1780.         s = av_get_media_type_string(dec_ctx->codec_type);
  1781.         if (s) print_str    ("codec_type", s);
  1782.         else   print_str_opt("codec_type", "unknown");
  1783.         print_q("codec_time_base", dec_ctx->time_base, '/');
  1784.  
  1785.         /* print AVI/FourCC tag */
  1786.         av_get_codec_tag_string(val_str, sizeof(val_str), dec_ctx->codec_tag);
  1787.         print_str("codec_tag_string",    val_str);
  1788.         print_fmt("codec_tag", "0x%04x", dec_ctx->codec_tag);
  1789.  
  1790.         switch (dec_ctx->codec_type) {
  1791.         case AVMEDIA_TYPE_VIDEO:
  1792.             print_int("width",        dec_ctx->width);
  1793.             print_int("height",       dec_ctx->height);
  1794.             print_int("has_b_frames", dec_ctx->has_b_frames);
  1795.             sar = av_guess_sample_aspect_ratio(fmt_ctx, stream, NULL);
  1796.             if (sar.den) {
  1797.                 print_q("sample_aspect_ratio", sar, ':');
  1798.                 av_reduce(&dar.num, &dar.den,
  1799.                           dec_ctx->width  * sar.num,
  1800.                           dec_ctx->height * sar.den,
  1801.                           1024*1024);
  1802.                 print_q("display_aspect_ratio", dar, ':');
  1803.             } else {
  1804.                 print_str_opt("sample_aspect_ratio", "N/A");
  1805.                 print_str_opt("display_aspect_ratio", "N/A");
  1806.             }
  1807.             s = av_get_pix_fmt_name(dec_ctx->pix_fmt);
  1808.             if (s) print_str    ("pix_fmt", s);
  1809.             else   print_str_opt("pix_fmt", "unknown");
  1810.             print_int("level",   dec_ctx->level);
  1811.             if (dec_ctx->timecode_frame_start >= 0) {
  1812.                 char tcbuf[AV_TIMECODE_STR_SIZE];
  1813.                 av_timecode_make_mpeg_tc_string(tcbuf, dec_ctx->timecode_frame_start);
  1814.                 print_str("timecode", tcbuf);
  1815.             } else {
  1816.                 print_str_opt("timecode", "N/A");
  1817.             }
  1818.             break;
  1819.  
  1820.         case AVMEDIA_TYPE_AUDIO:
  1821.             s = av_get_sample_fmt_name(dec_ctx->sample_fmt);
  1822.             if (s) print_str    ("sample_fmt", s);
  1823.             else   print_str_opt("sample_fmt", "unknown");
  1824.             print_val("sample_rate",     dec_ctx->sample_rate, unit_hertz_str);
  1825.             print_int("channels",        dec_ctx->channels);
  1826.  
  1827.             if (dec_ctx->channel_layout) {
  1828.                 av_bprint_clear(&pbuf);
  1829.                 av_bprint_channel_layout(&pbuf, dec_ctx->channels, dec_ctx->channel_layout);
  1830.                 print_str    ("channel_layout", pbuf.str);
  1831.             } else {
  1832.                 print_str_opt("channel_layout", "unknown");
  1833.             }
  1834.  
  1835.             print_int("bits_per_sample", av_get_bits_per_sample(dec_ctx->codec_id));
  1836.             break;
  1837.  
  1838.         case AVMEDIA_TYPE_SUBTITLE:
  1839.             if (dec_ctx->width)
  1840.                 print_int("width",       dec_ctx->width);
  1841.             else
  1842.                 print_str_opt("width",   "N/A");
  1843.             if (dec_ctx->height)
  1844.                 print_int("height",      dec_ctx->height);
  1845.             else
  1846.                 print_str_opt("height",  "N/A");
  1847.             break;
  1848.         }
  1849.     } else {
  1850.         print_str_opt("codec_type", "unknown");
  1851.     }
  1852.     if (dec_ctx->codec && dec_ctx->codec->priv_class && show_private_data) {
  1853.         const AVOption *opt = NULL;
  1854.         while (opt = av_opt_next(dec_ctx->priv_data,opt)) {
  1855.             uint8_t *str;
  1856.             if (opt->flags) continue;
  1857.             if (av_opt_get(dec_ctx->priv_data, opt->name, 0, &str) >= 0) {
  1858.                 print_str(opt->name, str);
  1859.                 av_free(str);
  1860.             }
  1861.         }
  1862.     }
  1863.  
  1864.     if (fmt_ctx->iformat->flags & AVFMT_SHOW_IDS) print_fmt    ("id", "0x%x", stream->id);
  1865.     else                                          print_str_opt("id", "N/A");
  1866.     print_q("r_frame_rate",   stream->r_frame_rate,   '/');
  1867.     print_q("avg_frame_rate", stream->avg_frame_rate, '/');
  1868.     print_q("time_base",      stream->time_base,      '/');
  1869.     print_ts  ("start_pts",   stream->start_time);
  1870.     print_time("start_time",  stream->start_time, &stream->time_base);
  1871.     print_ts  ("duration_ts", stream->duration);
  1872.     print_time("duration",    stream->duration, &stream->time_base);
  1873.     if (dec_ctx->bit_rate > 0) print_val    ("bit_rate", dec_ctx->bit_rate, unit_bit_per_second_str);
  1874.     else                       print_str_opt("bit_rate", "N/A");
  1875.     if (stream->nb_frames) print_fmt    ("nb_frames", "%"PRId64, stream->nb_frames);
  1876.     else                   print_str_opt("nb_frames", "N/A");
  1877.     if (nb_streams_frames[stream_idx])  print_fmt    ("nb_read_frames", "%"PRIu64, nb_streams_frames[stream_idx]);
  1878.     else                                print_str_opt("nb_read_frames", "N/A");
  1879.     if (nb_streams_packets[stream_idx]) print_fmt    ("nb_read_packets", "%"PRIu64, nb_streams_packets[stream_idx]);
  1880.     else                                print_str_opt("nb_read_packets", "N/A");
  1881.     if (do_show_data)
  1882.         writer_print_data(w, "extradata", dec_ctx->extradata,
  1883.                                           dec_ctx->extradata_size);
  1884.  
  1885.     /* Print disposition information */
  1886. #define PRINT_DISPOSITION(flagname, name) do {                                \
  1887.         print_int(name, !!(stream->disposition & AV_DISPOSITION_##flagname)); \
  1888.     } while (0)
  1889.  
  1890.     if (do_show_stream_disposition) {
  1891.     writer_print_section_header(w, in_program ? SECTION_ID_PROGRAM_STREAM_DISPOSITION : SECTION_ID_STREAM_DISPOSITION);
  1892.     PRINT_DISPOSITION(DEFAULT,          "default");
  1893.     PRINT_DISPOSITION(DUB,              "dub");
  1894.     PRINT_DISPOSITION(ORIGINAL,         "original");
  1895.     PRINT_DISPOSITION(COMMENT,          "comment");
  1896.     PRINT_DISPOSITION(LYRICS,           "lyrics");
  1897.     PRINT_DISPOSITION(KARAOKE,          "karaoke");
  1898.     PRINT_DISPOSITION(FORCED,           "forced");
  1899.     PRINT_DISPOSITION(HEARING_IMPAIRED, "hearing_impaired");
  1900.     PRINT_DISPOSITION(VISUAL_IMPAIRED,  "visual_impaired");
  1901.     PRINT_DISPOSITION(CLEAN_EFFECTS,    "clean_effects");
  1902.     PRINT_DISPOSITION(ATTACHED_PIC,     "attached_pic");
  1903.     writer_print_section_footer(w);
  1904.     }
  1905.  
  1906.     show_tags(w, stream->metadata, in_program ? SECTION_ID_PROGRAM_STREAM_TAGS : SECTION_ID_STREAM_TAGS);
  1907.  
  1908.     writer_print_section_footer(w);
  1909.     av_bprint_finalize(&pbuf, NULL);
  1910.     fflush(stdout);
  1911. }
  1912.  
  1913. static void show_streams(WriterContext *w, AVFormatContext *fmt_ctx)
  1914. {
  1915.     int i;
  1916.     writer_print_section_header(w, SECTION_ID_STREAMS);
  1917.     for (i = 0; i < fmt_ctx->nb_streams; i++)
  1918.         if (selected_streams[i])
  1919.             show_stream(w, fmt_ctx, i, 0);
  1920.     writer_print_section_footer(w);
  1921. }
  1922.  
  1923. static void show_program(WriterContext *w, AVFormatContext *fmt_ctx, AVProgram *program)
  1924. {
  1925.     int i;
  1926.  
  1927.     writer_print_section_header(w, SECTION_ID_PROGRAM);
  1928.     print_int("program_id", program->id);
  1929.     print_int("program_num", program->program_num);
  1930.     print_int("nb_streams", program->nb_stream_indexes);
  1931.     print_int("pmt_pid", program->pmt_pid);
  1932.     print_int("pcr_pid", program->pcr_pid);
  1933.     print_ts("start_pts", program->start_time);
  1934.     print_time("start_time", program->start_time, &AV_TIME_BASE_Q);
  1935.     print_ts("end_pts", program->end_time);
  1936.     print_time("end_time", program->end_time, &AV_TIME_BASE_Q);
  1937.     show_tags(w, program->metadata, SECTION_ID_PROGRAM_TAGS);
  1938.  
  1939.     writer_print_section_header(w, SECTION_ID_PROGRAM_STREAMS);
  1940.     for (i = 0; i < program->nb_stream_indexes; i++) {
  1941.         if (selected_streams[program->stream_index[i]])
  1942.             show_stream(w, fmt_ctx, program->stream_index[i], 1);
  1943.     }
  1944.     writer_print_section_footer(w);
  1945.  
  1946.     writer_print_section_footer(w);
  1947. }
  1948.  
  1949. static void show_programs(WriterContext *w, AVFormatContext *fmt_ctx)
  1950. {
  1951.     int i;
  1952.  
  1953.     writer_print_section_header(w, SECTION_ID_PROGRAMS);
  1954.     for (i = 0; i < fmt_ctx->nb_programs; i++) {
  1955.         AVProgram *program = fmt_ctx->programs[i];
  1956.         if (!program)
  1957.             continue;
  1958.         show_program(w, fmt_ctx, program);
  1959.     }
  1960.     writer_print_section_footer(w);
  1961. }
  1962.  
  1963. static void show_chapters(WriterContext *w, AVFormatContext *fmt_ctx)
  1964. {
  1965.     int i;
  1966.  
  1967.     writer_print_section_header(w, SECTION_ID_CHAPTERS);
  1968.     for (i = 0; i < fmt_ctx->nb_chapters; i++) {
  1969.         AVChapter *chapter = fmt_ctx->chapters[i];
  1970.  
  1971.         writer_print_section_header(w, SECTION_ID_CHAPTER);
  1972.         print_int("id", chapter->id);
  1973.         print_q  ("time_base", chapter->time_base, '/');
  1974.         print_int("start", chapter->start);
  1975.         print_time("start_time", chapter->start, &chapter->time_base);
  1976.         print_int("end", chapter->end);
  1977.         print_time("end_time", chapter->end, &chapter->time_base);
  1978.         show_tags(w, chapter->metadata, SECTION_ID_CHAPTER_TAGS);
  1979.         writer_print_section_footer(w);
  1980.     }
  1981.     writer_print_section_footer(w);
  1982. }
  1983.  
  1984. static void show_format(WriterContext *w, AVFormatContext *fmt_ctx)
  1985. {
  1986.     char val_str[128];
  1987.     int64_t size = fmt_ctx->pb ? avio_size(fmt_ctx->pb) : -1;
  1988.  
  1989.     writer_print_section_header(w, SECTION_ID_FORMAT);
  1990.     print_str("filename",         fmt_ctx->filename);
  1991.     print_int("nb_streams",       fmt_ctx->nb_streams);
  1992.     print_int("nb_programs",      fmt_ctx->nb_programs);
  1993.     print_str("format_name",      fmt_ctx->iformat->name);
  1994.     if (!do_bitexact) {
  1995.         if (fmt_ctx->iformat->long_name) print_str    ("format_long_name", fmt_ctx->iformat->long_name);
  1996.         else                             print_str_opt("format_long_name", "unknown");
  1997.     }
  1998.     print_time("start_time",      fmt_ctx->start_time, &AV_TIME_BASE_Q);
  1999.     print_time("duration",        fmt_ctx->duration,   &AV_TIME_BASE_Q);
  2000.     if (size >= 0) print_val    ("size", size, unit_byte_str);
  2001.     else           print_str_opt("size", "N/A");
  2002.     if (fmt_ctx->bit_rate > 0) print_val    ("bit_rate", fmt_ctx->bit_rate, unit_bit_per_second_str);
  2003.     else                       print_str_opt("bit_rate", "N/A");
  2004.     print_int("probe_score", av_format_get_probe_score(fmt_ctx));
  2005.     show_tags(w, fmt_ctx->metadata, SECTION_ID_FORMAT_TAGS);
  2006.  
  2007.     writer_print_section_footer(w);
  2008.     fflush(stdout);
  2009. }
  2010.  
  2011. static void show_error(WriterContext *w, int err)
  2012. {
  2013.     char errbuf[128];
  2014.     const char *errbuf_ptr = errbuf;
  2015.  
  2016.     if (av_strerror(err, errbuf, sizeof(errbuf)) < 0)
  2017.         errbuf_ptr = strerror(AVUNERROR(err));
  2018.  
  2019.     writer_print_section_header(w, SECTION_ID_ERROR);
  2020.     print_int("code", err);
  2021.     print_str("string", errbuf_ptr);
  2022.     writer_print_section_footer(w);
  2023. }
  2024.  
  2025. static int open_input_file(AVFormatContext **fmt_ctx_ptr, const char *filename)
  2026. {
  2027.     int err, i, orig_nb_streams;
  2028.     AVFormatContext *fmt_ctx = NULL;
  2029.     AVDictionaryEntry *t;
  2030.     AVDictionary **opts;
  2031.  
  2032.     if ((err = avformat_open_input(&fmt_ctx, filename,
  2033.                                    iformat, &format_opts)) < 0) {
  2034.         print_error(filename, err);
  2035.         return err;
  2036.     }
  2037.     if ((t = av_dict_get(format_opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
  2038.         av_log(NULL, AV_LOG_ERROR, "Option %s not found.\n", t->key);
  2039.         return AVERROR_OPTION_NOT_FOUND;
  2040.     }
  2041.  
  2042.     /* fill the streams in the format context */
  2043.     opts = setup_find_stream_info_opts(fmt_ctx, codec_opts);
  2044.     orig_nb_streams = fmt_ctx->nb_streams;
  2045.  
  2046.     if ((err = avformat_find_stream_info(fmt_ctx, opts)) < 0) {
  2047.         print_error(filename, err);
  2048.         return err;
  2049.     }
  2050.     for (i = 0; i < orig_nb_streams; i++)
  2051.         av_dict_free(&opts[i]);
  2052.     av_freep(&opts);
  2053.  
  2054.     av_dump_format(fmt_ctx, 0, filename, 0);
  2055.  
  2056.     /* bind a decoder to each input stream */
  2057.     for (i = 0; i < fmt_ctx->nb_streams; i++) {
  2058.         AVStream *stream = fmt_ctx->streams[i];
  2059.         AVCodec *codec;
  2060.  
  2061.         if (stream->codec->codec_id == AV_CODEC_ID_PROBE) {
  2062.             av_log(NULL, AV_LOG_WARNING,
  2063.                    "Failed to probe codec for input stream %d\n",
  2064.                     stream->index);
  2065.         } else if (!(codec = avcodec_find_decoder(stream->codec->codec_id))) {
  2066.             av_log(NULL, AV_LOG_WARNING,
  2067.                     "Unsupported codec with id %d for input stream %d\n",
  2068.                     stream->codec->codec_id, stream->index);
  2069.         } else {
  2070.             AVDictionary *opts = filter_codec_opts(codec_opts, stream->codec->codec_id,
  2071.                                                    fmt_ctx, stream, codec);
  2072.             if (avcodec_open2(stream->codec, codec, &opts) < 0) {
  2073.                 av_log(NULL, AV_LOG_WARNING, "Could not open codec for input stream %d\n",
  2074.                        stream->index);
  2075.             }
  2076.             if ((t = av_dict_get(opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
  2077.                 av_log(NULL, AV_LOG_ERROR, "Option %s for input stream %d not found\n",
  2078.                        t->key, stream->index);
  2079.                 return AVERROR_OPTION_NOT_FOUND;
  2080.             }
  2081.         }
  2082.     }
  2083.  
  2084.     *fmt_ctx_ptr = fmt_ctx;
  2085.     return 0;
  2086. }
  2087.  
  2088. static void close_input_file(AVFormatContext **ctx_ptr)
  2089. {
  2090.     int i;
  2091.     AVFormatContext *fmt_ctx = *ctx_ptr;
  2092.  
  2093.     /* close decoder for each stream */
  2094.     for (i = 0; i < fmt_ctx->nb_streams; i++)
  2095.         if (fmt_ctx->streams[i]->codec->codec_id != AV_CODEC_ID_NONE)
  2096.             avcodec_close(fmt_ctx->streams[i]->codec);
  2097.  
  2098.     avformat_close_input(ctx_ptr);
  2099. }
  2100.  
  2101. static int probe_file(WriterContext *wctx, const char *filename)
  2102. {
  2103.     AVFormatContext *fmt_ctx;
  2104.     int ret, i;
  2105.     int section_id;
  2106.  
  2107.     do_read_frames = do_show_frames || do_count_frames;
  2108.     do_read_packets = do_show_packets || do_count_packets;
  2109.  
  2110.     ret = open_input_file(&fmt_ctx, filename);
  2111.     if (ret < 0)
  2112.         return ret;
  2113.  
  2114.     nb_streams_frames  = av_calloc(fmt_ctx->nb_streams, sizeof(*nb_streams_frames));
  2115.     nb_streams_packets = av_calloc(fmt_ctx->nb_streams, sizeof(*nb_streams_packets));
  2116.     selected_streams   = av_calloc(fmt_ctx->nb_streams, sizeof(*selected_streams));
  2117.  
  2118.     for (i = 0; i < fmt_ctx->nb_streams; i++) {
  2119.         if (stream_specifier) {
  2120.             ret = avformat_match_stream_specifier(fmt_ctx,
  2121.                                                   fmt_ctx->streams[i],
  2122.                                                   stream_specifier);
  2123.             if (ret < 0)
  2124.                 goto end;
  2125.             else
  2126.                 selected_streams[i] = ret;
  2127.             ret = 0;
  2128.         } else {
  2129.             selected_streams[i] = 1;
  2130.         }
  2131.     }
  2132.  
  2133.     if (do_read_frames || do_read_packets) {
  2134.         if (do_show_frames && do_show_packets &&
  2135.             wctx->writer->flags & WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER)
  2136.             section_id = SECTION_ID_PACKETS_AND_FRAMES;
  2137.         else if (do_show_packets && !do_show_frames)
  2138.             section_id = SECTION_ID_PACKETS;
  2139.         else // (!do_show_packets && do_show_frames)
  2140.             section_id = SECTION_ID_FRAMES;
  2141.         if (do_show_frames || do_show_packets)
  2142.             writer_print_section_header(wctx, section_id);
  2143.         read_packets(wctx, fmt_ctx);
  2144.         if (do_show_frames || do_show_packets)
  2145.             writer_print_section_footer(wctx);
  2146.     }
  2147.     if (do_show_programs)
  2148.         show_programs(wctx, fmt_ctx);
  2149.     if (do_show_streams)
  2150.         show_streams(wctx, fmt_ctx);
  2151.     if (do_show_chapters)
  2152.         show_chapters(wctx, fmt_ctx);
  2153.     if (do_show_format)
  2154.         show_format(wctx, fmt_ctx);
  2155.  
  2156. end:
  2157.     close_input_file(&fmt_ctx);
  2158.     av_freep(&nb_streams_frames);
  2159.     av_freep(&nb_streams_packets);
  2160.     av_freep(&selected_streams);
  2161.  
  2162.     return ret;
  2163. }
  2164.  
  2165. static void show_usage(void)
  2166. {
  2167.     av_log(NULL, AV_LOG_INFO, "Simple multimedia streams analyzer\n");
  2168.     av_log(NULL, AV_LOG_INFO, "usage: %s [OPTIONS] [INPUT_FILE]\n", program_name);
  2169.     av_log(NULL, AV_LOG_INFO, "\n");
  2170. }
  2171.  
  2172. static void ffprobe_show_program_version(WriterContext *w)
  2173. {
  2174.     AVBPrint pbuf;
  2175.     av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
  2176.  
  2177.     writer_print_section_header(w, SECTION_ID_PROGRAM_VERSION);
  2178.     print_str("version", FFMPEG_VERSION);
  2179.     print_fmt("copyright", "Copyright (c) %d-%d the FFmpeg developers",
  2180.               program_birth_year, this_year);
  2181.     print_str("build_date", __DATE__);
  2182.     print_str("build_time", __TIME__);
  2183.     print_str("compiler_ident", CC_IDENT);
  2184.     print_str("configuration", FFMPEG_CONFIGURATION);
  2185.     writer_print_section_footer(w);
  2186.  
  2187.     av_bprint_finalize(&pbuf, NULL);
  2188. }
  2189.  
  2190. #define SHOW_LIB_VERSION(libname, LIBNAME)                              \
  2191.     do {                                                                \
  2192.         if (CONFIG_##LIBNAME) {                                         \
  2193.             unsigned int version = libname##_version();                 \
  2194.             writer_print_section_header(w, SECTION_ID_LIBRARY_VERSION); \
  2195.             print_str("name",    "lib" #libname);                       \
  2196.             print_int("major",   LIB##LIBNAME##_VERSION_MAJOR);         \
  2197.             print_int("minor",   LIB##LIBNAME##_VERSION_MINOR);         \
  2198.             print_int("micro",   LIB##LIBNAME##_VERSION_MICRO);         \
  2199.             print_int("version", version);                              \
  2200.             print_str("ident",   LIB##LIBNAME##_IDENT);                 \
  2201.             writer_print_section_footer(w);                             \
  2202.         }                                                               \
  2203.     } while (0)
  2204.  
  2205. static void ffprobe_show_library_versions(WriterContext *w)
  2206. {
  2207.     writer_print_section_header(w, SECTION_ID_LIBRARY_VERSIONS);
  2208.     SHOW_LIB_VERSION(avutil,     AVUTIL);
  2209.     SHOW_LIB_VERSION(avcodec,    AVCODEC);
  2210.     SHOW_LIB_VERSION(avformat,   AVFORMAT);
  2211.     SHOW_LIB_VERSION(avdevice,   AVDEVICE);
  2212.     SHOW_LIB_VERSION(avfilter,   AVFILTER);
  2213.     SHOW_LIB_VERSION(swscale,    SWSCALE);
  2214.     SHOW_LIB_VERSION(swresample, SWRESAMPLE);
  2215.     SHOW_LIB_VERSION(postproc,   POSTPROC);
  2216.     writer_print_section_footer(w);
  2217. }
  2218.  
  2219. static int opt_format(void *optctx, const char *opt, const char *arg)
  2220. {
  2221.     iformat = av_find_input_format(arg);
  2222.     if (!iformat) {
  2223.         av_log(NULL, AV_LOG_ERROR, "Unknown input format: %s\n", arg);
  2224.         return AVERROR(EINVAL);
  2225.     }
  2226.     return 0;
  2227. }
  2228.  
  2229. static inline void mark_section_show_entries(SectionID section_id,
  2230.                                              int show_all_entries, AVDictionary *entries)
  2231. {
  2232.     struct section *section = &sections[section_id];
  2233.  
  2234.     section->show_all_entries = show_all_entries;
  2235.     if (show_all_entries) {
  2236.         SectionID *id;
  2237.         for (id = section->children_ids; *id != -1; id++)
  2238.             mark_section_show_entries(*id, show_all_entries, entries);
  2239.     } else {
  2240.         av_dict_copy(&section->entries_to_show, entries, 0);
  2241.     }
  2242. }
  2243.  
  2244. static int match_section(const char *section_name,
  2245.                          int show_all_entries, AVDictionary *entries)
  2246. {
  2247.     int i, ret = 0;
  2248.  
  2249.     for (i = 0; i < FF_ARRAY_ELEMS(sections); i++) {
  2250.         const struct section *section = &sections[i];
  2251.         if (!strcmp(section_name, section->name) ||
  2252.             (section->unique_name && !strcmp(section_name, section->unique_name))) {
  2253.             av_log(NULL, AV_LOG_DEBUG,
  2254.                    "'%s' matches section with unique name '%s'\n", section_name,
  2255.                    (char *)av_x_if_null(section->unique_name, section->name));
  2256.             ret++;
  2257.             mark_section_show_entries(section->id, show_all_entries, entries);
  2258.         }
  2259.     }
  2260.     return ret;
  2261. }
  2262.  
  2263. static int opt_show_entries(void *optctx, const char *opt, const char *arg)
  2264. {
  2265.     const char *p = arg;
  2266.     int ret = 0;
  2267.  
  2268.     while (*p) {
  2269.         AVDictionary *entries = NULL;
  2270.         char *section_name = av_get_token(&p, "=:");
  2271.         int show_all_entries = 0;
  2272.  
  2273.         if (!section_name) {
  2274.             av_log(NULL, AV_LOG_ERROR,
  2275.                    "Missing section name for option '%s'\n", opt);
  2276.             return AVERROR(EINVAL);
  2277.         }
  2278.  
  2279.         if (*p == '=') {
  2280.             p++;
  2281.             while (*p && *p != ':') {
  2282.                 char *entry = av_get_token(&p, ",:");
  2283.                 if (!entry)
  2284.                     break;
  2285.                 av_log(NULL, AV_LOG_VERBOSE,
  2286.                        "Adding '%s' to the entries to show in section '%s'\n",
  2287.                        entry, section_name);
  2288.                 av_dict_set(&entries, entry, "", AV_DICT_DONT_STRDUP_KEY);
  2289.                 if (*p == ',')
  2290.                     p++;
  2291.             }
  2292.         } else {
  2293.             show_all_entries = 1;
  2294.         }
  2295.  
  2296.         ret = match_section(section_name, show_all_entries, entries);
  2297.         if (ret == 0) {
  2298.             av_log(NULL, AV_LOG_ERROR, "No match for section '%s'\n", section_name);
  2299.             ret = AVERROR(EINVAL);
  2300.         }
  2301.         av_dict_free(&entries);
  2302.         av_free(section_name);
  2303.  
  2304.         if (ret <= 0)
  2305.             break;
  2306.         if (*p)
  2307.             p++;
  2308.     }
  2309.  
  2310.     return ret;
  2311. }
  2312.  
  2313. static int opt_show_format_entry(void *optctx, const char *opt, const char *arg)
  2314. {
  2315.     char *buf = av_asprintf("format=%s", arg);
  2316.     int ret;
  2317.  
  2318.     av_log(NULL, AV_LOG_WARNING,
  2319.            "Option '%s' is deprecated, use '-show_entries format=%s' instead\n",
  2320.            opt, arg);
  2321.     ret = opt_show_entries(optctx, opt, buf);
  2322.     av_free(buf);
  2323.     return ret;
  2324. }
  2325.  
  2326. static void opt_input_file(void *optctx, const char *arg)
  2327. {
  2328.     if (input_filename) {
  2329.         av_log(NULL, AV_LOG_ERROR,
  2330.                 "Argument '%s' provided as input filename, but '%s' was already specified.\n",
  2331.                 arg, input_filename);
  2332.         exit_program(1);
  2333.     }
  2334.     if (!strcmp(arg, "-"))
  2335.         arg = "pipe:";
  2336.     input_filename = arg;
  2337. }
  2338.  
  2339. static int opt_input_file_i(void *optctx, const char *opt, const char *arg)
  2340. {
  2341.     opt_input_file(optctx, arg);
  2342.     return 0;
  2343. }
  2344.  
  2345. void show_help_default(const char *opt, const char *arg)
  2346. {
  2347.     av_log_set_callback(log_callback_help);
  2348.     show_usage();
  2349.     show_help_options(options, "Main options:", 0, 0, 0);
  2350.     printf("\n");
  2351.  
  2352.     show_help_children(avformat_get_class(), AV_OPT_FLAG_DECODING_PARAM);
  2353. }
  2354.  
  2355. /**
  2356.  * Parse interval specification, according to the format:
  2357.  * INTERVAL ::= [START|+START_OFFSET][%[END|+END_OFFSET]]
  2358.  * INTERVALS ::= INTERVAL[,INTERVALS]
  2359. */
  2360. static int parse_read_interval(const char *interval_spec,
  2361.                                ReadInterval *interval)
  2362. {
  2363.     int ret = 0;
  2364.     char *next, *p, *spec = av_strdup(interval_spec);
  2365.     if (!spec)
  2366.         return AVERROR(ENOMEM);
  2367.  
  2368.     if (!*spec) {
  2369.         av_log(NULL, AV_LOG_ERROR, "Invalid empty interval specification\n");
  2370.         ret = AVERROR(EINVAL);
  2371.         goto end;
  2372.     }
  2373.  
  2374.     p = spec;
  2375.     next = strchr(spec, '%');
  2376.     if (next)
  2377.         *next++ = 0;
  2378.  
  2379.     /* parse first part */
  2380.     if (*p) {
  2381.         interval->has_start = 1;
  2382.  
  2383.         if (*p == '+') {
  2384.             interval->start_is_offset = 1;
  2385.             p++;
  2386.         } else {
  2387.             interval->start_is_offset = 0;
  2388.         }
  2389.  
  2390.         ret = av_parse_time(&interval->start, p, 1);
  2391.         if (ret < 0) {
  2392.             av_log(NULL, AV_LOG_ERROR, "Invalid interval start specification '%s'\n", p);
  2393.             goto end;
  2394.         }
  2395.     } else {
  2396.         interval->has_start = 0;
  2397.     }
  2398.  
  2399.     /* parse second part */
  2400.     p = next;
  2401.     if (p && *p) {
  2402.         int64_t us;
  2403.         interval->has_end = 1;
  2404.  
  2405.         if (*p == '+') {
  2406.             interval->end_is_offset = 1;
  2407.             p++;
  2408.         } else {
  2409.             interval->end_is_offset = 0;
  2410.         }
  2411.  
  2412.         if (interval->end_is_offset && *p == '#') {
  2413.             long long int lli;
  2414.             char *tail;
  2415.             interval->duration_frames = 1;
  2416.             p++;
  2417.             lli = strtoll(p, &tail, 10);
  2418.             if (*tail || lli < 0) {
  2419.                 av_log(NULL, AV_LOG_ERROR,
  2420.                        "Invalid or negative value '%s' for duration number of frames\n", p);
  2421.                 goto end;
  2422.             }
  2423.             interval->end = lli;
  2424.         } else {
  2425.             ret = av_parse_time(&us, p, 1);
  2426.             if (ret < 0) {
  2427.                 av_log(NULL, AV_LOG_ERROR, "Invalid interval end/duration specification '%s'\n", p);
  2428.                 goto end;
  2429.             }
  2430.             interval->end = us;
  2431.         }
  2432.     } else {
  2433.         interval->has_end = 0;
  2434.     }
  2435.  
  2436. end:
  2437.     av_free(spec);
  2438.     return ret;
  2439. }
  2440.  
  2441. static int parse_read_intervals(const char *intervals_spec)
  2442. {
  2443.     int ret, n, i;
  2444.     char *p, *spec = av_strdup(intervals_spec);
  2445.     if (!spec)
  2446.         return AVERROR(ENOMEM);
  2447.  
  2448.     /* preparse specification, get number of intervals */
  2449.     for (n = 0, p = spec; *p; p++)
  2450.         if (*p == ',')
  2451.             n++;
  2452.     n++;
  2453.  
  2454.     read_intervals = av_malloc(n * sizeof(*read_intervals));
  2455.     if (!read_intervals) {
  2456.         ret = AVERROR(ENOMEM);
  2457.         goto end;
  2458.     }
  2459.     read_intervals_nb = n;
  2460.  
  2461.     /* parse intervals */
  2462.     p = spec;
  2463.     for (i = 0; p; i++) {
  2464.         char *next;
  2465.  
  2466.         av_assert0(i < read_intervals_nb);
  2467.         next = strchr(p, ',');
  2468.         if (next)
  2469.             *next++ = 0;
  2470.  
  2471.         read_intervals[i].id = i;
  2472.         ret = parse_read_interval(p, &read_intervals[i]);
  2473.         if (ret < 0) {
  2474.             av_log(NULL, AV_LOG_ERROR, "Error parsing read interval #%d '%s'\n",
  2475.                    i, p);
  2476.             goto end;
  2477.         }
  2478.         av_log(NULL, AV_LOG_VERBOSE, "Parsed log interval ");
  2479.         log_read_interval(&read_intervals[i], NULL, AV_LOG_VERBOSE);
  2480.         p = next;
  2481.     }
  2482.     av_assert0(i == read_intervals_nb);
  2483.  
  2484. end:
  2485.     av_free(spec);
  2486.     return ret;
  2487. }
  2488.  
  2489. static int opt_read_intervals(void *optctx, const char *opt, const char *arg)
  2490. {
  2491.     return parse_read_intervals(arg);
  2492. }
  2493.  
  2494. static int opt_pretty(void *optctx, const char *opt, const char *arg)
  2495. {
  2496.     show_value_unit              = 1;
  2497.     use_value_prefix             = 1;
  2498.     use_byte_value_binary_prefix = 1;
  2499.     use_value_sexagesimal_format = 1;
  2500.     return 0;
  2501. }
  2502.  
  2503. static void print_section(SectionID id, int level)
  2504. {
  2505.     const SectionID *pid;
  2506.     const struct section *section = &sections[id];
  2507.     printf("%c%c%c",
  2508.            section->flags & SECTION_FLAG_IS_WRAPPER           ? 'W' : '.',
  2509.            section->flags & SECTION_FLAG_IS_ARRAY             ? 'A' : '.',
  2510.            section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS  ? 'V' : '.');
  2511.     printf("%*c  %s", level * 4, ' ', section->name);
  2512.     if (section->unique_name)
  2513.         printf("/%s", section->unique_name);
  2514.     printf("\n");
  2515.  
  2516.     for (pid = section->children_ids; *pid != -1; pid++)
  2517.         print_section(*pid, level+1);
  2518. }
  2519.  
  2520. static int opt_sections(void *optctx, const char *opt, const char *arg)
  2521. {
  2522.     printf("Sections:\n"
  2523.            "W.. = Section is a wrapper (contains other sections, no local entries)\n"
  2524.            ".A. = Section contains an array of elements of the same type\n"
  2525.            "..V = Section may contain a variable number of fields with variable keys\n"
  2526.            "FLAGS NAME/UNIQUE_NAME\n"
  2527.            "---\n");
  2528.     print_section(SECTION_ID_ROOT, 0);
  2529.     return 0;
  2530. }
  2531.  
  2532. static int opt_show_versions(const char *opt, const char *arg)
  2533. {
  2534.     mark_section_show_entries(SECTION_ID_PROGRAM_VERSION, 1, NULL);
  2535.     mark_section_show_entries(SECTION_ID_LIBRARY_VERSION, 1, NULL);
  2536.     return 0;
  2537. }
  2538.  
  2539. #define DEFINE_OPT_SHOW_SECTION(section, target_section_id)             \
  2540.     static int opt_show_##section(const char *opt, const char *arg)     \
  2541.     {                                                                   \
  2542.         mark_section_show_entries(SECTION_ID_##target_section_id, 1, NULL); \
  2543.         return 0;                                                       \
  2544.     }
  2545.  
  2546. DEFINE_OPT_SHOW_SECTION(chapters,         CHAPTERS);
  2547. DEFINE_OPT_SHOW_SECTION(error,            ERROR);
  2548. DEFINE_OPT_SHOW_SECTION(format,           FORMAT);
  2549. DEFINE_OPT_SHOW_SECTION(frames,           FRAMES);
  2550. DEFINE_OPT_SHOW_SECTION(library_versions, LIBRARY_VERSIONS);
  2551. DEFINE_OPT_SHOW_SECTION(packets,          PACKETS);
  2552. DEFINE_OPT_SHOW_SECTION(program_version,  PROGRAM_VERSION);
  2553. DEFINE_OPT_SHOW_SECTION(streams,          STREAMS);
  2554. DEFINE_OPT_SHOW_SECTION(programs,         PROGRAMS);
  2555.  
  2556. static const OptionDef real_options[] = {
  2557. #include "cmdutils_common_opts.h"
  2558.     { "f", HAS_ARG, {.func_arg = opt_format}, "force format", "format" },
  2559.     { "unit", OPT_BOOL, {&show_value_unit}, "show unit of the displayed values" },
  2560.     { "prefix", OPT_BOOL, {&use_value_prefix}, "use SI prefixes for the displayed values" },
  2561.     { "byte_binary_prefix", OPT_BOOL, {&use_byte_value_binary_prefix},
  2562.       "use binary prefixes for byte units" },
  2563.     { "sexagesimal", OPT_BOOL,  {&use_value_sexagesimal_format},
  2564.       "use sexagesimal format HOURS:MM:SS.MICROSECONDS for time units" },
  2565.     { "pretty", 0, {.func_arg = opt_pretty},
  2566.       "prettify the format of displayed values, make it more human readable" },
  2567.     { "print_format", OPT_STRING | HAS_ARG, {(void*)&print_format},
  2568.       "set the output printing format (available formats are: default, compact, csv, flat, ini, json, xml)", "format" },
  2569.     { "of", OPT_STRING | HAS_ARG, {(void*)&print_format}, "alias for -print_format", "format" },
  2570.     { "select_streams", OPT_STRING | HAS_ARG, {(void*)&stream_specifier}, "select the specified streams", "stream_specifier" },
  2571.     { "sections", OPT_EXIT, {.func_arg = opt_sections}, "print sections structure and section information, and exit" },
  2572.     { "show_data",    OPT_BOOL, {(void*)&do_show_data}, "show packets data" },
  2573.     { "show_error",   0, {(void*)&opt_show_error},  "show probing error" },
  2574.     { "show_format",  0, {(void*)&opt_show_format}, "show format/container info" },
  2575.     { "show_frames",  0, {(void*)&opt_show_frames}, "show frames info" },
  2576.     { "show_format_entry", HAS_ARG, {.func_arg = opt_show_format_entry},
  2577.       "show a particular entry from the format/container info", "entry" },
  2578.     { "show_entries", HAS_ARG, {.func_arg = opt_show_entries},
  2579.       "show a set of specified entries", "entry_list" },
  2580.     { "show_packets", 0, {(void*)&opt_show_packets}, "show packets info" },
  2581.     { "show_programs", 0, {(void*)&opt_show_programs}, "show programs info" },
  2582.     { "show_streams", 0, {(void*)&opt_show_streams}, "show streams info" },
  2583.     { "show_chapters", 0, {(void*)&opt_show_chapters}, "show chapters info" },
  2584.     { "count_frames", OPT_BOOL, {(void*)&do_count_frames}, "count the number of frames per stream" },
  2585.     { "count_packets", OPT_BOOL, {(void*)&do_count_packets}, "count the number of packets per stream" },
  2586.     { "show_program_version",  0, {(void*)&opt_show_program_version},  "show ffprobe version" },
  2587.     { "show_library_versions", 0, {(void*)&opt_show_library_versions}, "show library versions" },
  2588.     { "show_versions",         0, {(void*)&opt_show_versions}, "show program and library versions" },
  2589.     { "show_private_data", OPT_BOOL, {(void*)&show_private_data}, "show private data" },
  2590.     { "private",           OPT_BOOL, {(void*)&show_private_data}, "same as show_private_data" },
  2591.     { "bitexact", OPT_BOOL, {&do_bitexact}, "force bitexact output" },
  2592.     { "read_intervals", HAS_ARG, {.func_arg = opt_read_intervals}, "set read intervals", "read_intervals" },
  2593.     { "default", HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, {.func_arg = opt_default}, "generic catch all option", "" },
  2594.     { "i", HAS_ARG, {.func_arg = opt_input_file_i}, "read specified file", "input_file"},
  2595.     { NULL, },
  2596. };
  2597.  
  2598. static inline int check_section_show_entries(int section_id)
  2599. {
  2600.     int *id;
  2601.     struct section *section = &sections[section_id];
  2602.     if (sections[section_id].show_all_entries || sections[section_id].entries_to_show)
  2603.         return 1;
  2604.     for (id = section->children_ids; *id != -1; id++)
  2605.         if (check_section_show_entries(*id))
  2606.             return 1;
  2607.     return 0;
  2608. }
  2609.  
  2610. #define SET_DO_SHOW(id, varname) do {                                   \
  2611.         if (check_section_show_entries(SECTION_ID_##id))                \
  2612.             do_show_##varname = 1;                                      \
  2613.     } while (0)
  2614.  
  2615. int main(int argc, char **argv)
  2616. {
  2617.     const Writer *w;
  2618.     WriterContext *wctx;
  2619.     char *buf;
  2620.     char *w_name = NULL, *w_args = NULL;
  2621.     int ret, i;
  2622.  
  2623.     av_log_set_flags(AV_LOG_SKIP_REPEATED);
  2624.     register_exit(ffprobe_cleanup);
  2625.  
  2626.     options = real_options;
  2627.     parse_loglevel(argc, argv, options);
  2628.     av_register_all();
  2629.     avformat_network_init();
  2630.     init_opts();
  2631. #if CONFIG_AVDEVICE
  2632.     avdevice_register_all();
  2633. #endif
  2634.  
  2635.     show_banner(argc, argv, options);
  2636.     parse_options(NULL, argc, argv, options, opt_input_file);
  2637.  
  2638.     /* mark things to show, based on -show_entries */
  2639.     SET_DO_SHOW(CHAPTERS, chapters);
  2640.     SET_DO_SHOW(ERROR, error);
  2641.     SET_DO_SHOW(FORMAT, format);
  2642.     SET_DO_SHOW(FRAMES, frames);
  2643.     SET_DO_SHOW(LIBRARY_VERSIONS, library_versions);
  2644.     SET_DO_SHOW(PACKETS, packets);
  2645.     SET_DO_SHOW(PROGRAM_VERSION, program_version);
  2646.     SET_DO_SHOW(PROGRAMS, programs);
  2647.     SET_DO_SHOW(STREAMS, streams);
  2648.     SET_DO_SHOW(STREAM_DISPOSITION, stream_disposition);
  2649.     SET_DO_SHOW(PROGRAM_STREAM_DISPOSITION, stream_disposition);
  2650.  
  2651.     if (do_bitexact && (do_show_program_version || do_show_library_versions)) {
  2652.         av_log(NULL, AV_LOG_ERROR,
  2653.                "-bitexact and -show_program_version or -show_library_versions "
  2654.                "options are incompatible\n");
  2655.         ret = AVERROR(EINVAL);
  2656.         goto end;
  2657.     }
  2658.  
  2659.     writer_register_all();
  2660.  
  2661.     if (!print_format)
  2662.         print_format = av_strdup("default");
  2663.     if (!print_format) {
  2664.         ret = AVERROR(ENOMEM);
  2665.         goto end;
  2666.     }
  2667.     w_name = av_strtok(print_format, "=", &buf);
  2668.     w_args = buf;
  2669.  
  2670.     w = writer_get_by_name(w_name);
  2671.     if (!w) {
  2672.         av_log(NULL, AV_LOG_ERROR, "Unknown output format with name '%s'\n", w_name);
  2673.         ret = AVERROR(EINVAL);
  2674.         goto end;
  2675.     }
  2676.  
  2677.     if ((ret = writer_open(&wctx, w, w_args,
  2678.                            sections, FF_ARRAY_ELEMS(sections))) >= 0) {
  2679.         writer_print_section_header(wctx, SECTION_ID_ROOT);
  2680.  
  2681.         if (do_show_program_version)
  2682.             ffprobe_show_program_version(wctx);
  2683.         if (do_show_library_versions)
  2684.             ffprobe_show_library_versions(wctx);
  2685.  
  2686.         if (!input_filename &&
  2687.             ((do_show_format || do_show_programs || do_show_streams || do_show_chapters || do_show_packets || do_show_error) ||
  2688.              (!do_show_program_version && !do_show_library_versions))) {
  2689.             show_usage();
  2690.             av_log(NULL, AV_LOG_ERROR, "You have to specify one input file.\n");
  2691.             av_log(NULL, AV_LOG_ERROR, "Use -h to get full help or, even better, run 'man %s'.\n", program_name);
  2692.             ret = AVERROR(EINVAL);
  2693.         } else if (input_filename) {
  2694.             ret = probe_file(wctx, input_filename);
  2695.             if (ret < 0 && do_show_error)
  2696.                 show_error(wctx, ret);
  2697.         }
  2698.  
  2699.         writer_print_section_footer(wctx);
  2700.         writer_close(&wctx);
  2701.     }
  2702.  
  2703. end:
  2704.     av_freep(&print_format);
  2705.     av_freep(&read_intervals);
  2706.  
  2707.     uninit_opts();
  2708.     for (i = 0; i < FF_ARRAY_ELEMS(sections); i++)
  2709.         av_dict_free(&(sections[i].entries_to_show));
  2710.  
  2711.     avformat_network_deinit();
  2712.  
  2713.     return ret < 0;
  2714. }
  2715.