FFmpeg
ffprobe.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2007-2010 Stefano Sabatini
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 /**
22  * @file
23  * simple media prober based on the FFmpeg libraries
24  */
25 
26 #include "config.h"
27 #include "libavutil/ffversion.h"
28 
29 #include <string.h>
30 #include <math.h>
31 
32 #include "libavformat/avformat.h"
33 #include "libavformat/version.h"
34 #include "libavcodec/avcodec.h"
35 #include "libavcodec/version.h"
37 #include "libavutil/avassert.h"
38 #include "libavutil/avstring.h"
39 #include "libavutil/bprint.h"
41 #include "libavutil/display.h"
42 #include "libavutil/hash.h"
46 #include "libavutil/dovi_meta.h"
47 #include "libavutil/opt.h"
48 #include "libavutil/pixdesc.h"
49 #include "libavutil/spherical.h"
50 #include "libavutil/stereo3d.h"
51 #include "libavutil/dict.h"
52 #include "libavutil/intreadwrite.h"
53 #include "libavutil/libm.h"
54 #include "libavutil/parseutils.h"
55 #include "libavutil/timecode.h"
56 #include "libavutil/timestamp.h"
57 #include "libavdevice/avdevice.h"
58 #include "libavdevice/version.h"
59 #include "libswscale/swscale.h"
60 #include "libswscale/version.h"
62 #include "libswresample/version.h"
64 #include "libpostproc/version.h"
65 #include "libavfilter/version.h"
66 #include "cmdutils.h"
67 #include "opt_common.h"
68 
69 #include "libavutil/thread.h"
70 
71 #if !HAVE_THREADS
72 # ifdef pthread_mutex_lock
73 # undef pthread_mutex_lock
74 # endif
75 # define pthread_mutex_lock(a) do{}while(0)
76 # ifdef pthread_mutex_unlock
77 # undef pthread_mutex_unlock
78 # endif
79 # define pthread_mutex_unlock(a) do{}while(0)
80 #endif
81 
82 // attached as opaque_ref to packets/frames
83 typedef struct FrameData {
84  int64_t pkt_pos;
85  int pkt_size;
86 } FrameData;
87 
88 typedef struct InputStream {
89  AVStream *st;
90 
92 } InputStream;
93 
94 typedef struct InputFile {
96 
98  int nb_streams;
99 } InputFile;
100 
101 const char program_name[] = "ffprobe";
102 const int program_birth_year = 2007;
103 
104 static int do_bitexact = 0;
105 static int do_count_frames = 0;
106 static int do_count_packets = 0;
107 static int do_read_frames = 0;
108 static int do_read_packets = 0;
109 static int do_show_chapters = 0;
110 static int do_show_error = 0;
111 static int do_show_format = 0;
112 static int do_show_frames = 0;
113 static int do_show_packets = 0;
114 static int do_show_programs = 0;
115 static int do_show_streams = 0;
117 static int do_show_data = 0;
118 static int do_show_program_version = 0;
120 static int do_show_pixel_formats = 0;
123 static int do_show_log = 0;
124 
125 static int do_show_chapter_tags = 0;
126 static int do_show_format_tags = 0;
127 static int do_show_frame_tags = 0;
128 static int do_show_program_tags = 0;
129 static int do_show_stream_tags = 0;
130 static int do_show_packet_tags = 0;
131 
132 static int show_value_unit = 0;
133 static int use_value_prefix = 0;
136 static int show_private_data = 1;
137 
138 #define SHOW_OPTIONAL_FIELDS_AUTO -1
139 #define SHOW_OPTIONAL_FIELDS_NEVER 0
140 #define SHOW_OPTIONAL_FIELDS_ALWAYS 1
142 
143 static char *print_format;
144 static char *stream_specifier;
145 static char *show_data_hash;
146 
147 typedef struct ReadInterval {
148  int id; ///< identifier
149  int64_t start, end; ///< start, end in second/AV_TIME_BASE units
153 } ReadInterval;
154 
156 static int read_intervals_nb = 0;
157 
158 static int find_stream_info = 1;
159 
160 /* section structure definition */
161 
162 #define SECTION_MAX_NB_CHILDREN 10
163 
164 typedef enum {
214 } SectionID;
215 
216 struct section {
217  int id; ///< unique id identifying a section
218  const char *name;
219 
220 #define SECTION_FLAG_IS_WRAPPER 1 ///< the section only contains other sections, but has no data at its own level
221 #define SECTION_FLAG_IS_ARRAY 2 ///< the section contains an array of elements of the same type
222 #define SECTION_FLAG_HAS_VARIABLE_FIELDS 4 ///< the section may contain a variable number of fields with variable keys.
223  /// For these sections the element_name field is mandatory.
224  int flags;
225  const SectionID children_ids[SECTION_MAX_NB_CHILDREN+1]; ///< list of children section IDS, terminated by -1
226  const char *element_name; ///< name of the contained element, if provided
227  const char *unique_name; ///< unique section name, in case the name is ambiguous
230 };
231 
232 static struct section sections[] = {
234  [SECTION_ID_CHAPTER] = { SECTION_ID_CHAPTER, "chapter", 0, { SECTION_ID_CHAPTER_TAGS, -1 } },
235  [SECTION_ID_CHAPTER_TAGS] = { SECTION_ID_CHAPTER_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "chapter_tags" },
236  [SECTION_ID_ERROR] = { SECTION_ID_ERROR, "error", 0, { -1 } },
237  [SECTION_ID_FORMAT] = { SECTION_ID_FORMAT, "format", 0, { SECTION_ID_FORMAT_TAGS, -1 } },
238  [SECTION_ID_FORMAT_TAGS] = { SECTION_ID_FORMAT_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "format_tags" },
241  [SECTION_ID_FRAME_TAGS] = { SECTION_ID_FRAME_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "frame_tags" },
242  [SECTION_ID_FRAME_SIDE_DATA_LIST] ={ SECTION_ID_FRAME_SIDE_DATA_LIST, "side_data_list", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_SIDE_DATA, -1 }, .element_name = "side_data", .unique_name = "frame_side_data_list" },
251  [SECTION_ID_FRAME_LOG] = { SECTION_ID_FRAME_LOG, "log", 0, { -1 }, },
253  [SECTION_ID_LIBRARY_VERSION] = { SECTION_ID_LIBRARY_VERSION, "library_version", 0, { -1 } },
257  [SECTION_ID_PACKET_TAGS] = { SECTION_ID_PACKET_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "packet_tags" },
258  [SECTION_ID_PACKET_SIDE_DATA_LIST] ={ SECTION_ID_PACKET_SIDE_DATA_LIST, "side_data_list", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET_SIDE_DATA, -1 }, .element_name = "side_data", .unique_name = "packet_side_data_list" },
259  [SECTION_ID_PACKET_SIDE_DATA] = { SECTION_ID_PACKET_SIDE_DATA, "side_data", 0, { -1 }, .unique_name = "packet_side_data" },
262  [SECTION_ID_PIXEL_FORMAT_FLAGS] = { SECTION_ID_PIXEL_FORMAT_FLAGS, "flags", 0, { -1 }, .unique_name = "pixel_format_flags" },
263  [SECTION_ID_PIXEL_FORMAT_COMPONENTS] = { SECTION_ID_PIXEL_FORMAT_COMPONENTS, "components", SECTION_FLAG_IS_ARRAY, {SECTION_ID_PIXEL_FORMAT_COMPONENT, -1 }, .unique_name = "pixel_format_components" },
265  [SECTION_ID_PROGRAM_STREAM_DISPOSITION] = { SECTION_ID_PROGRAM_STREAM_DISPOSITION, "disposition", 0, { -1 }, .unique_name = "program_stream_disposition" },
266  [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" },
268  [SECTION_ID_PROGRAM_STREAMS] = { SECTION_ID_PROGRAM_STREAMS, "streams", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PROGRAM_STREAM, -1 }, .unique_name = "program_streams" },
270  [SECTION_ID_PROGRAM_TAGS] = { SECTION_ID_PROGRAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "program_tags" },
271  [SECTION_ID_PROGRAM_VERSION] = { SECTION_ID_PROGRAM_VERSION, "program_version", 0, { -1 } },
279  [SECTION_ID_STREAM_DISPOSITION] = { SECTION_ID_STREAM_DISPOSITION, "disposition", 0, { -1 }, .unique_name = "stream_disposition" },
280  [SECTION_ID_STREAM_TAGS] = { SECTION_ID_STREAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "stream_tags" },
281  [SECTION_ID_STREAM_SIDE_DATA_LIST] ={ SECTION_ID_STREAM_SIDE_DATA_LIST, "side_data_list", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_SIDE_DATA, -1 }, .element_name = "side_data", .unique_name = "stream_side_data_list" },
282  [SECTION_ID_STREAM_SIDE_DATA] = { SECTION_ID_STREAM_SIDE_DATA, "side_data", 0, { -1 }, .unique_name = "stream_side_data" },
283  [SECTION_ID_SUBTITLE] = { SECTION_ID_SUBTITLE, "subtitle", 0, { -1 } },
284 };
285 
286 static const OptionDef *options;
287 
288 /* FFprobe context */
289 static const char *input_filename;
290 static const char *print_input_filename;
291 static const AVInputFormat *iformat = NULL;
292 static const char *output_filename = NULL;
293 
294 static struct AVHashContext *hash;
295 
296 static const struct {
297  double bin_val;
298  double dec_val;
299  const char *bin_str;
300  const char *dec_str;
301 } si_prefixes[] = {
302  { 1.0, 1.0, "", "" },
303  { 1.024e3, 1e3, "Ki", "K" },
304  { 1.048576e6, 1e6, "Mi", "M" },
305  { 1.073741824e9, 1e9, "Gi", "G" },
306  { 1.099511627776e12, 1e12, "Ti", "T" },
307  { 1.125899906842624e15, 1e15, "Pi", "P" },
308 };
309 
310 static const char unit_second_str[] = "s" ;
311 static const char unit_hertz_str[] = "Hz" ;
312 static const char unit_byte_str[] = "byte" ;
313 static const char unit_bit_per_second_str[] = "bit/s";
314 
315 static int nb_streams;
316 static uint64_t *nb_streams_packets;
317 static uint64_t *nb_streams_frames;
318 static int *selected_streams;
319 
320 #if HAVE_THREADS
321 pthread_mutex_t log_mutex;
322 #endif
323 typedef struct LogBuffer {
326  char *log_message;
328  char *parent_name;
330 }LogBuffer;
331 
333 static int log_buffer_size;
334 
335 static void log_callback(void *ptr, int level, const char *fmt, va_list vl)
336 {
337  AVClass* avc = ptr ? *(AVClass **) ptr : NULL;
338  va_list vl2;
339  char line[1024];
340  static int print_prefix = 1;
341  void *new_log_buffer;
342 
343  va_copy(vl2, vl);
344  av_log_default_callback(ptr, level, fmt, vl);
345  av_log_format_line(ptr, level, fmt, vl2, line, sizeof(line), &print_prefix);
346  va_end(vl2);
347 
348 #if HAVE_THREADS
349  pthread_mutex_lock(&log_mutex);
350 
351  new_log_buffer = av_realloc_array(log_buffer, log_buffer_size + 1, sizeof(*log_buffer));
352  if (new_log_buffer) {
353  char *msg;
354  int i;
355 
356  log_buffer = new_log_buffer;
357  memset(&log_buffer[log_buffer_size], 0, sizeof(log_buffer[log_buffer_size]));
359  if (avc) {
362  }
365  for (i=strlen(msg) - 1; i>=0 && msg[i] == '\n'; i--) {
366  msg[i] = 0;
367  }
368  if (avc && avc->parent_log_context_offset) {
369  AVClass** parent = *(AVClass ***) (((uint8_t *) ptr) +
371  if (parent && *parent) {
372  log_buffer[log_buffer_size].parent_name = av_strdup((*parent)->item_name(parent));
374  (*parent)->get_category ? (*parent)->get_category(parent) :(*parent)->category;
375  }
376  }
377  log_buffer_size ++;
378  }
379 
380  pthread_mutex_unlock(&log_mutex);
381 #endif
382 }
383 
384 struct unit_value {
385  union { double d; long long int i; } val;
386  const char *unit;
387 };
388 
389 static char *value_string(char *buf, int buf_size, struct unit_value uv)
390 {
391  double vald;
392  long long int vali;
393  int show_float = 0;
394 
395  if (uv.unit == unit_second_str) {
396  vald = uv.val.d;
397  show_float = 1;
398  } else {
399  vald = vali = uv.val.i;
400  }
401 
403  double secs;
404  int hours, mins;
405  secs = vald;
406  mins = (int)secs / 60;
407  secs = secs - mins * 60;
408  hours = mins / 60;
409  mins %= 60;
410  snprintf(buf, buf_size, "%d:%02d:%09.6f", hours, mins, secs);
411  } else {
412  const char *prefix_string = "";
413 
414  if (use_value_prefix && vald > 1) {
415  long long int index;
416 
418  index = (long long int) (log2(vald)) / 10;
420  vald /= si_prefixes[index].bin_val;
421  prefix_string = si_prefixes[index].bin_str;
422  } else {
423  index = (long long int) (log10(vald)) / 3;
425  vald /= si_prefixes[index].dec_val;
426  prefix_string = si_prefixes[index].dec_str;
427  }
428  vali = vald;
429  }
430 
431  if (show_float || (use_value_prefix && vald != (long long int)vald))
432  snprintf(buf, buf_size, "%f", vald);
433  else
434  snprintf(buf, buf_size, "%lld", vali);
435  av_strlcatf(buf, buf_size, "%s%s%s", *prefix_string || show_value_unit ? " " : "",
436  prefix_string, show_value_unit ? uv.unit : "");
437  }
438 
439  return buf;
440 }
441 
442 /* WRITERS API */
443 
444 typedef struct WriterContext WriterContext;
445 
446 #define WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS 1
447 #define WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER 2
448 
449 typedef enum {
455 
456 typedef struct Writer {
457  const AVClass *priv_class; ///< private class of the writer, if any
458  int priv_size; ///< private size for the writer context
459  const char *name;
460 
461  int (*init) (WriterContext *wctx);
462  void (*uninit)(WriterContext *wctx);
463 
466  void (*print_integer) (WriterContext *wctx, const char *, long long int);
467  void (*print_rational) (WriterContext *wctx, AVRational *q, char *sep);
468  void (*print_string) (WriterContext *wctx, const char *, const char *);
469  int flags; ///< a combination or WRITER_FLAG_*
470 } Writer;
471 
472 #define SECTION_MAX_NB_LEVELS 10
473 
475  const AVClass *class; ///< class of the writer
476  const Writer *writer; ///< the Writer of which this is an instance
477  AVIOContext *avio; ///< the I/O context used to write
478 
479  void (* writer_w8)(WriterContext *wctx, int b);
480  void (* writer_put_str)(WriterContext *wctx, const char *str);
481  void (* writer_printf)(WriterContext *wctx, const char *fmt, ...);
482 
483  char *name; ///< name of this writer instance
484  void *priv; ///< private data for use by the filter
485 
486  const struct section *sections; ///< array containing all sections
487  int nb_sections; ///< number of sections
488 
489  int level; ///< current level, starting from 0
490 
491  /** number of the item printed in the given section, starting from 0 */
493 
494  /** section per each level */
496  AVBPrint section_pbuf[SECTION_MAX_NB_LEVELS]; ///< generic print buffer dedicated to each section,
497  /// used by various writers
498 
499  unsigned int nb_section_packet; ///< number of the packet section in case we are in "packets_and_frames" section
500  unsigned int nb_section_frame; ///< number of the frame section in case we are in "packets_and_frames" section
501  unsigned int nb_section_packet_frame; ///< nb_section_packet or nb_section_frame according if is_packets_and_frames
502 
506 };
507 
508 static const char *writer_get_name(void *p)
509 {
510  WriterContext *wctx = p;
511  return wctx->writer->name;
512 }
513 
514 #define OFFSET(x) offsetof(WriterContext, x)
515 
516 static const AVOption writer_options[] = {
517  { "string_validation", "set string validation mode",
518  OFFSET(string_validation), AV_OPT_TYPE_INT, {.i64=WRITER_STRING_VALIDATION_REPLACE}, 0, WRITER_STRING_VALIDATION_NB-1, .unit = "sv" },
519  { "sv", "set string validation mode",
520  OFFSET(string_validation), AV_OPT_TYPE_INT, {.i64=WRITER_STRING_VALIDATION_REPLACE}, 0, WRITER_STRING_VALIDATION_NB-1, .unit = "sv" },
521  { "ignore", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = WRITER_STRING_VALIDATION_IGNORE}, .unit = "sv" },
522  { "replace", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = WRITER_STRING_VALIDATION_REPLACE}, .unit = "sv" },
523  { "fail", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = WRITER_STRING_VALIDATION_FAIL}, .unit = "sv" },
524  { "string_validation_replacement", "set string validation replacement string", OFFSET(string_validation_replacement), AV_OPT_TYPE_STRING, {.str=""}},
525  { "svr", "set string validation replacement string", OFFSET(string_validation_replacement), AV_OPT_TYPE_STRING, {.str="\xEF\xBF\xBD"}},
526  { NULL }
527 };
528 
529 static void *writer_child_next(void *obj, void *prev)
530 {
531  WriterContext *ctx = obj;
532  if (!prev && ctx->writer && ctx->writer->priv_class && ctx->priv)
533  return ctx->priv;
534  return NULL;
535 }
536 
537 static const AVClass writer_class = {
538  .class_name = "Writer",
539  .item_name = writer_get_name,
540  .option = writer_options,
541  .version = LIBAVUTIL_VERSION_INT,
542  .child_next = writer_child_next,
543 };
544 
545 static int writer_close(WriterContext **wctx)
546 {
547  int i;
548  int ret = 0;
549 
550  if (!*wctx)
551  return -1;
552 
553  if ((*wctx)->writer->uninit)
554  (*wctx)->writer->uninit(*wctx);
555  for (i = 0; i < SECTION_MAX_NB_LEVELS; i++)
556  av_bprint_finalize(&(*wctx)->section_pbuf[i], NULL);
557  if ((*wctx)->writer->priv_class)
558  av_opt_free((*wctx)->priv);
559  av_freep(&((*wctx)->priv));
560  av_opt_free(*wctx);
561  if ((*wctx)->avio) {
562  avio_flush((*wctx)->avio);
563  ret = avio_close((*wctx)->avio);
564  }
565  av_freep(wctx);
566  return ret;
567 }
568 
569 static void bprint_bytes(AVBPrint *bp, const uint8_t *ubuf, size_t ubuf_size)
570 {
571  int i;
572  av_bprintf(bp, "0X");
573  for (i = 0; i < ubuf_size; i++)
574  av_bprintf(bp, "%02X", ubuf[i]);
575 }
576 
577 static inline void writer_w8_avio(WriterContext *wctx, int b)
578 {
579  avio_w8(wctx->avio, b);
580 }
581 
582 static inline void writer_put_str_avio(WriterContext *wctx, const char *str)
583 {
584  avio_write(wctx->avio, str, strlen(str));
585 }
586 
587 static inline void writer_printf_avio(WriterContext *wctx, const char *fmt, ...)
588 {
589  va_list ap;
590 
591  va_start(ap, fmt);
592  avio_vprintf(wctx->avio, fmt, ap);
593  va_end(ap);
594 }
595 
596 static inline void writer_w8_printf(WriterContext *wctx, int b)
597 {
598  printf("%c", b);
599 }
600 
601 static inline void writer_put_str_printf(WriterContext *wctx, const char *str)
602 {
603  printf("%s", str);
604 }
605 
606 static inline void writer_printf_printf(WriterContext *wctx, const char *fmt, ...)
607 {
608  va_list ap;
609 
610  va_start(ap, fmt);
611  vprintf(fmt, ap);
612  va_end(ap);
613 }
614 
615 static int writer_open(WriterContext **wctx, const Writer *writer, const char *args,
616  const struct section *sections, int nb_sections, const char *output)
617 {
618  int i, ret = 0;
619 
620  if (!(*wctx = av_mallocz(sizeof(WriterContext)))) {
621  ret = AVERROR(ENOMEM);
622  goto fail;
623  }
624 
625  if (!((*wctx)->priv = av_mallocz(writer->priv_size))) {
626  ret = AVERROR(ENOMEM);
627  goto fail;
628  }
629 
630  (*wctx)->class = &writer_class;
631  (*wctx)->writer = writer;
632  (*wctx)->level = -1;
633  (*wctx)->sections = sections;
634  (*wctx)->nb_sections = nb_sections;
635 
636  av_opt_set_defaults(*wctx);
637 
638  if (writer->priv_class) {
639  void *priv_ctx = (*wctx)->priv;
640  *((const AVClass **)priv_ctx) = writer->priv_class;
641  av_opt_set_defaults(priv_ctx);
642  }
643 
644  /* convert options to dictionary */
645  if (args) {
647  const AVDictionaryEntry *opt = NULL;
648 
649  if ((ret = av_dict_parse_string(&opts, args, "=", ":", 0)) < 0) {
650  av_log(*wctx, AV_LOG_ERROR, "Failed to parse option string '%s' provided to writer context\n", args);
651  av_dict_free(&opts);
652  goto fail;
653  }
654 
655  while ((opt = av_dict_iterate(opts, opt))) {
656  if ((ret = av_opt_set(*wctx, opt->key, opt->value, AV_OPT_SEARCH_CHILDREN)) < 0) {
657  av_log(*wctx, AV_LOG_ERROR, "Failed to set option '%s' with value '%s' provided to writer context\n",
658  opt->key, opt->value);
659  av_dict_free(&opts);
660  goto fail;
661  }
662  }
663 
664  av_dict_free(&opts);
665  }
666 
667  /* validate replace string */
668  {
669  const uint8_t *p = (*wctx)->string_validation_replacement;
670  const uint8_t *endp = p + strlen(p);
671  while (*p) {
672  const uint8_t *p0 = p;
673  int32_t code;
674  ret = av_utf8_decode(&code, &p, endp, (*wctx)->string_validation_utf8_flags);
675  if (ret < 0) {
676  AVBPrint bp;
678  bprint_bytes(&bp, p0, p-p0),
679  av_log(wctx, AV_LOG_ERROR,
680  "Invalid UTF8 sequence %s found in string validation replace '%s'\n",
681  bp.str, (*wctx)->string_validation_replacement);
682  return ret;
683  }
684  }
685  }
686 
687  if (!output_filename) {
688  (*wctx)->writer_w8 = writer_w8_printf;
689  (*wctx)->writer_put_str = writer_put_str_printf;
690  (*wctx)->writer_printf = writer_printf_printf;
691  } else {
692  if ((ret = avio_open(&(*wctx)->avio, output, AVIO_FLAG_WRITE)) < 0) {
693  av_log(*wctx, AV_LOG_ERROR,
694  "Failed to open output '%s' with error: %s\n", output, av_err2str(ret));
695  goto fail;
696  }
697  (*wctx)->writer_w8 = writer_w8_avio;
698  (*wctx)->writer_put_str = writer_put_str_avio;
699  (*wctx)->writer_printf = writer_printf_avio;
700  }
701 
702  for (i = 0; i < SECTION_MAX_NB_LEVELS; i++)
703  av_bprint_init(&(*wctx)->section_pbuf[i], 1, AV_BPRINT_SIZE_UNLIMITED);
704 
705  if ((*wctx)->writer->init)
706  ret = (*wctx)->writer->init(*wctx);
707  if (ret < 0)
708  goto fail;
709 
710  return 0;
711 
712 fail:
713  writer_close(wctx);
714  return ret;
715 }
716 
718  int section_id)
719 {
720  int parent_section_id;
721  wctx->level++;
723  parent_section_id = wctx->level ?
724  (wctx->section[wctx->level-1])->id : SECTION_ID_NONE;
725 
726  wctx->nb_item[wctx->level] = 0;
727  wctx->section[wctx->level] = &wctx->sections[section_id];
728 
729  if (section_id == SECTION_ID_PACKETS_AND_FRAMES) {
730  wctx->nb_section_packet = wctx->nb_section_frame =
731  wctx->nb_section_packet_frame = 0;
732  } else if (parent_section_id == SECTION_ID_PACKETS_AND_FRAMES) {
733  wctx->nb_section_packet_frame = section_id == SECTION_ID_PACKET ?
734  wctx->nb_section_packet : wctx->nb_section_frame;
735  }
736 
737  if (wctx->writer->print_section_header)
738  wctx->writer->print_section_header(wctx);
739 }
740 
742 {
743  int section_id = wctx->section[wctx->level]->id;
744  int parent_section_id = wctx->level ?
745  wctx->section[wctx->level-1]->id : SECTION_ID_NONE;
746 
747  if (parent_section_id != SECTION_ID_NONE)
748  wctx->nb_item[wctx->level-1]++;
749  if (parent_section_id == SECTION_ID_PACKETS_AND_FRAMES) {
750  if (section_id == SECTION_ID_PACKET) wctx->nb_section_packet++;
751  else wctx->nb_section_frame++;
752  }
753  if (wctx->writer->print_section_footer)
754  wctx->writer->print_section_footer(wctx);
755  wctx->level--;
756 }
757 
758 static inline void writer_print_integer(WriterContext *wctx,
759  const char *key, long long int val)
760 {
761  const struct section *section = wctx->section[wctx->level];
762 
764  wctx->writer->print_integer(wctx, key, val);
765  wctx->nb_item[wctx->level]++;
766  }
767 }
768 
769 static inline int validate_string(WriterContext *wctx, char **dstp, const char *src)
770 {
771  const uint8_t *p, *endp;
772  AVBPrint dstbuf;
773  int invalid_chars_nb = 0, ret = 0;
774 
776 
777  endp = src + strlen(src);
778  for (p = (uint8_t *)src; *p;) {
779  uint32_t code;
780  int invalid = 0;
781  const uint8_t *p0 = p;
782 
783  if (av_utf8_decode(&code, &p, endp, wctx->string_validation_utf8_flags) < 0) {
784  AVBPrint bp;
786  bprint_bytes(&bp, p0, p-p0);
787  av_log(wctx, AV_LOG_DEBUG,
788  "Invalid UTF-8 sequence %s found in string '%s'\n", bp.str, src);
789  invalid = 1;
790  }
791 
792  if (invalid) {
793  invalid_chars_nb++;
794 
795  switch (wctx->string_validation) {
797  av_log(wctx, AV_LOG_ERROR,
798  "Invalid UTF-8 sequence found in string '%s'\n", src);
800  goto end;
801  break;
802 
804  av_bprintf(&dstbuf, "%s", wctx->string_validation_replacement);
805  break;
806  }
807  }
808 
809  if (!invalid || wctx->string_validation == WRITER_STRING_VALIDATION_IGNORE)
810  av_bprint_append_data(&dstbuf, p0, p-p0);
811  }
812 
813  if (invalid_chars_nb && wctx->string_validation == WRITER_STRING_VALIDATION_REPLACE) {
814  av_log(wctx, AV_LOG_WARNING,
815  "%d invalid UTF-8 sequence(s) found in string '%s', replaced with '%s'\n",
816  invalid_chars_nb, src, wctx->string_validation_replacement);
817  }
818 
819 end:
820  av_bprint_finalize(&dstbuf, dstp);
821  return ret;
822 }
823 
824 #define PRINT_STRING_OPT 1
825 #define PRINT_STRING_VALIDATE 2
826 
827 static inline int writer_print_string(WriterContext *wctx,
828  const char *key, const char *val, int flags)
829 {
830  const struct section *section = wctx->section[wctx->level];
831  int ret = 0;
832 
835  && (flags & PRINT_STRING_OPT)
837  return 0;
838 
841  char *key1 = NULL, *val1 = NULL;
842  ret = validate_string(wctx, &key1, key);
843  if (ret < 0) goto end;
844  ret = validate_string(wctx, &val1, val);
845  if (ret < 0) goto end;
846  wctx->writer->print_string(wctx, key1, val1);
847  end:
848  if (ret < 0) {
849  av_log(wctx, AV_LOG_ERROR,
850  "Invalid key=value string combination %s=%s in section %s\n",
852  }
853  av_free(key1);
854  av_free(val1);
855  } else {
856  wctx->writer->print_string(wctx, key, val);
857  }
858 
859  wctx->nb_item[wctx->level]++;
860  }
861 
862  return ret;
863 }
864 
865 static inline void writer_print_rational(WriterContext *wctx,
866  const char *key, AVRational q, char sep)
867 {
868  AVBPrint buf;
870  av_bprintf(&buf, "%d%c%d", q.num, sep, q.den);
871  writer_print_string(wctx, key, buf.str, 0);
872 }
873 
874 static void writer_print_time(WriterContext *wctx, const char *key,
875  int64_t ts, const AVRational *time_base, int is_duration)
876 {
877  char buf[128];
878 
879  if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0)) {
881  } else {
882  double d = ts * av_q2d(*time_base);
883  struct unit_value uv;
884  uv.val.d = d;
885  uv.unit = unit_second_str;
886  value_string(buf, sizeof(buf), uv);
887  writer_print_string(wctx, key, buf, 0);
888  }
889 }
890 
891 static void writer_print_ts(WriterContext *wctx, const char *key, int64_t ts, int is_duration)
892 {
893  if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0)) {
895  } else {
896  writer_print_integer(wctx, key, ts);
897  }
898 }
899 
900 static void writer_print_data(WriterContext *wctx, const char *name,
901  const uint8_t *data, int size)
902 {
903  AVBPrint bp;
904  int offset = 0, l, i;
905 
907  av_bprintf(&bp, "\n");
908  while (size) {
909  av_bprintf(&bp, "%08x: ", offset);
910  l = FFMIN(size, 16);
911  for (i = 0; i < l; i++) {
912  av_bprintf(&bp, "%02x", data[i]);
913  if (i & 1)
914  av_bprintf(&bp, " ");
915  }
916  av_bprint_chars(&bp, ' ', 41 - 2 * i - i / 2);
917  for (i = 0; i < l; i++)
918  av_bprint_chars(&bp, data[i] - 32U < 95 ? data[i] : '.', 1);
919  av_bprintf(&bp, "\n");
920  offset += l;
921  data += l;
922  size -= l;
923  }
924  writer_print_string(wctx, name, bp.str, 0);
925  av_bprint_finalize(&bp, NULL);
926 }
927 
928 static void writer_print_data_hash(WriterContext *wctx, const char *name,
929  const uint8_t *data, int size)
930 {
931  char *p, buf[AV_HASH_MAX_SIZE * 2 + 64] = { 0 };
932 
933  if (!hash)
934  return;
937  snprintf(buf, sizeof(buf), "%s:", av_hash_get_name(hash));
938  p = buf + strlen(buf);
939  av_hash_final_hex(hash, p, buf + sizeof(buf) - p);
940  writer_print_string(wctx, name, buf, 0);
941 }
942 
943 static void writer_print_integers(WriterContext *wctx, const char *name,
944  uint8_t *data, int size, const char *format,
945  int columns, int bytes, int offset_add)
946 {
947  AVBPrint bp;
948  int offset = 0, l, i;
949 
951  av_bprintf(&bp, "\n");
952  while (size) {
953  av_bprintf(&bp, "%08x: ", offset);
954  l = FFMIN(size, columns);
955  for (i = 0; i < l; i++) {
956  if (bytes == 1) av_bprintf(&bp, format, *data);
957  else if (bytes == 2) av_bprintf(&bp, format, AV_RN16(data));
958  else if (bytes == 4) av_bprintf(&bp, format, AV_RN32(data));
959  data += bytes;
960  size --;
961  }
962  av_bprintf(&bp, "\n");
963  offset += offset_add;
964  }
965  writer_print_string(wctx, name, bp.str, 0);
966  av_bprint_finalize(&bp, NULL);
967 }
968 
969 #define writer_w8(wctx_, b_) (wctx_)->writer_w8(wctx_, b_)
970 #define writer_put_str(wctx_, str_) (wctx_)->writer_put_str(wctx_, str_)
971 #define writer_printf(wctx_, fmt_, ...) (wctx_)->writer_printf(wctx_, fmt_, __VA_ARGS__)
972 
973 #define MAX_REGISTERED_WRITERS_NB 64
974 
976 
977 static int writer_register(const Writer *writer)
978 {
979  static int next_registered_writer_idx = 0;
980 
981  if (next_registered_writer_idx == MAX_REGISTERED_WRITERS_NB)
982  return AVERROR(ENOMEM);
983 
984  registered_writers[next_registered_writer_idx++] = writer;
985  return 0;
986 }
987 
988 static const Writer *writer_get_by_name(const char *name)
989 {
990  int i;
991 
992  for (i = 0; registered_writers[i]; i++)
993  if (!strcmp(registered_writers[i]->name, name))
994  return registered_writers[i];
995 
996  return NULL;
997 }
998 
999 
1000 /* WRITERS */
1001 
1002 #define DEFINE_WRITER_CLASS(name) \
1003 static const char *name##_get_name(void *ctx) \
1004 { \
1005  return #name ; \
1006 } \
1007 static const AVClass name##_class = { \
1008  .class_name = #name, \
1009  .item_name = name##_get_name, \
1010  .option = name##_options \
1011 }
1012 
1013 /* Default output */
1014 
1015 typedef struct DefaultContext {
1016  const AVClass *class;
1017  int nokey;
1020 } DefaultContext;
1021 
1022 #undef OFFSET
1023 #define OFFSET(x) offsetof(DefaultContext, x)
1024 
1025 static const AVOption default_options[] = {
1026  { "noprint_wrappers", "do not print headers and footers", OFFSET(noprint_wrappers), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
1027  { "nw", "do not print headers and footers", OFFSET(noprint_wrappers), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
1028  { "nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
1029  { "nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
1030  {NULL},
1031 };
1032 
1033 DEFINE_WRITER_CLASS(default);
1034 
1035 /* lame uppercasing routine, assumes the string is lower case ASCII */
1036 static inline char *upcase_string(char *dst, size_t dst_size, const char *src)
1037 {
1038  int i;
1039  for (i = 0; src[i] && i < dst_size-1; i++)
1040  dst[i] = av_toupper(src[i]);
1041  dst[i] = 0;
1042  return dst;
1043 }
1044 
1046 {
1047  DefaultContext *def = wctx->priv;
1048  char buf[32];
1049  const struct section *section = wctx->section[wctx->level];
1050  const struct section *parent_section = wctx->level ?
1051  wctx->section[wctx->level-1] : NULL;
1052 
1053  av_bprint_clear(&wctx->section_pbuf[wctx->level]);
1054  if (parent_section &&
1055  !(parent_section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))) {
1056  def->nested_section[wctx->level] = 1;
1057  av_bprintf(&wctx->section_pbuf[wctx->level], "%s%s:",
1058  wctx->section_pbuf[wctx->level-1].str,
1059  upcase_string(buf, sizeof(buf),
1061  }
1062 
1063  if (def->noprint_wrappers || def->nested_section[wctx->level])
1064  return;
1065 
1067  writer_printf(wctx, "[%s]\n", upcase_string(buf, sizeof(buf), section->name));
1068 }
1069 
1071 {
1072  DefaultContext *def = wctx->priv;
1073  const struct section *section = wctx->section[wctx->level];
1074  char buf[32];
1075 
1076  if (def->noprint_wrappers || def->nested_section[wctx->level])
1077  return;
1078 
1080  writer_printf(wctx, "[/%s]\n", upcase_string(buf, sizeof(buf), section->name));
1081 }
1082 
1083 static void default_print_str(WriterContext *wctx, const char *key, const char *value)
1084 {
1085  DefaultContext *def = wctx->priv;
1086 
1087  if (!def->nokey)
1088  writer_printf(wctx, "%s%s=", wctx->section_pbuf[wctx->level].str, key);
1089  writer_printf(wctx, "%s\n", value);
1090 }
1091 
1092 static void default_print_int(WriterContext *wctx, const char *key, long long int value)
1093 {
1094  DefaultContext *def = wctx->priv;
1095 
1096  if (!def->nokey)
1097  writer_printf(wctx, "%s%s=", wctx->section_pbuf[wctx->level].str, key);
1098  writer_printf(wctx, "%lld\n", value);
1099 }
1100 
1101 static const Writer default_writer = {
1102  .name = "default",
1103  .priv_size = sizeof(DefaultContext),
1106  .print_integer = default_print_int,
1107  .print_string = default_print_str,
1109  .priv_class = &default_class,
1110 };
1111 
1112 /* Compact output */
1113 
1114 /**
1115  * Apply C-language-like string escaping.
1116  */
1117 static const char *c_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
1118 {
1119  const char *p;
1120 
1121  for (p = src; *p; p++) {
1122  switch (*p) {
1123  case '\b': av_bprintf(dst, "%s", "\\b"); break;
1124  case '\f': av_bprintf(dst, "%s", "\\f"); break;
1125  case '\n': av_bprintf(dst, "%s", "\\n"); break;
1126  case '\r': av_bprintf(dst, "%s", "\\r"); break;
1127  case '\\': av_bprintf(dst, "%s", "\\\\"); break;
1128  default:
1129  if (*p == sep)
1130  av_bprint_chars(dst, '\\', 1);
1131  av_bprint_chars(dst, *p, 1);
1132  }
1133  }
1134  return dst->str;
1135 }
1136 
1137 /**
1138  * Quote fields containing special characters, check RFC4180.
1139  */
1140 static const char *csv_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
1141 {
1142  char meta_chars[] = { sep, '"', '\n', '\r', '\0' };
1143  int needs_quoting = !!src[strcspn(src, meta_chars)];
1144 
1145  if (needs_quoting)
1146  av_bprint_chars(dst, '"', 1);
1147 
1148  for (; *src; src++) {
1149  if (*src == '"')
1150  av_bprint_chars(dst, '"', 1);
1151  av_bprint_chars(dst, *src, 1);
1152  }
1153  if (needs_quoting)
1154  av_bprint_chars(dst, '"', 1);
1155  return dst->str;
1156 }
1157 
1158 static const char *none_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
1159 {
1160  return src;
1161 }
1162 
1163 typedef struct CompactContext {
1164  const AVClass *class;
1166  char item_sep;
1167  int nokey;
1170  const char * (*escape_str)(AVBPrint *dst, const char *src, const char sep, void *log_ctx);
1174 } CompactContext;
1175 
1176 #undef OFFSET
1177 #define OFFSET(x) offsetof(CompactContext, x)
1178 
1179 static const AVOption compact_options[]= {
1180  {"item_sep", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str="|"}, 0, 0 },
1181  {"s", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str="|"}, 0, 0 },
1182  {"nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
1183  {"nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
1184  {"escape", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="c"}, 0, 0 },
1185  {"e", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="c"}, 0, 0 },
1186  {"print_section", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
1187  {"p", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
1188  {NULL},
1189 };
1190 
1191 DEFINE_WRITER_CLASS(compact);
1192 
1194 {
1195  CompactContext *compact = wctx->priv;
1196 
1197  if (strlen(compact->item_sep_str) != 1) {
1198  av_log(wctx, AV_LOG_ERROR, "Item separator '%s' specified, but must contain a single character\n",
1199  compact->item_sep_str);
1200  return AVERROR(EINVAL);
1201  }
1202  compact->item_sep = compact->item_sep_str[0];
1203 
1204  if (!strcmp(compact->escape_mode_str, "none")) compact->escape_str = none_escape_str;
1205  else if (!strcmp(compact->escape_mode_str, "c" )) compact->escape_str = c_escape_str;
1206  else if (!strcmp(compact->escape_mode_str, "csv" )) compact->escape_str = csv_escape_str;
1207  else {
1208  av_log(wctx, AV_LOG_ERROR, "Unknown escape mode '%s'\n", compact->escape_mode_str);
1209  return AVERROR(EINVAL);
1210  }
1211 
1212  return 0;
1213 }
1214 
1216 {
1217  CompactContext *compact = wctx->priv;
1218  const struct section *section = wctx->section[wctx->level];
1219  const struct section *parent_section = wctx->level ?
1220  wctx->section[wctx->level-1] : NULL;
1221  compact->terminate_line[wctx->level] = 1;
1222  compact->has_nested_elems[wctx->level] = 0;
1223 
1224  av_bprint_clear(&wctx->section_pbuf[wctx->level]);
1225  if (!(section->flags & SECTION_FLAG_IS_ARRAY) && parent_section &&
1226  !(parent_section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))) {
1227  compact->nested_section[wctx->level] = 1;
1228  compact->has_nested_elems[wctx->level-1] = 1;
1229  av_bprintf(&wctx->section_pbuf[wctx->level], "%s%s:",
1230  wctx->section_pbuf[wctx->level-1].str,
1232  wctx->nb_item[wctx->level] = wctx->nb_item[wctx->level-1];
1233  } else {
1234  if (parent_section && compact->has_nested_elems[wctx->level-1] &&
1236  compact->terminate_line[wctx->level-1] = 0;
1237  }
1238  if (parent_section && !(parent_section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY)) &&
1239  wctx->level && wctx->nb_item[wctx->level-1])
1240  writer_w8(wctx, compact->item_sep);
1241  if (compact->print_section &&
1243  writer_printf(wctx, "%s%c", section->name, compact->item_sep);
1244  }
1245 }
1246 
1248 {
1249  CompactContext *compact = wctx->priv;
1250 
1251  if (!compact->nested_section[wctx->level] &&
1252  compact->terminate_line[wctx->level] &&
1254  writer_w8(wctx, '\n');
1255 }
1256 
1257 static void compact_print_str(WriterContext *wctx, const char *key, const char *value)
1258 {
1259  CompactContext *compact = wctx->priv;
1260  AVBPrint buf;
1261 
1262  if (wctx->nb_item[wctx->level]) writer_w8(wctx, compact->item_sep);
1263  if (!compact->nokey)
1264  writer_printf(wctx, "%s%s=", wctx->section_pbuf[wctx->level].str, key);
1266  writer_put_str(wctx, compact->escape_str(&buf, value, compact->item_sep, wctx));
1267  av_bprint_finalize(&buf, NULL);
1268 }
1269 
1270 static void compact_print_int(WriterContext *wctx, const char *key, long long int value)
1271 {
1272  CompactContext *compact = wctx->priv;
1273 
1274  if (wctx->nb_item[wctx->level]) writer_w8(wctx, compact->item_sep);
1275  if (!compact->nokey)
1276  writer_printf(wctx, "%s%s=", wctx->section_pbuf[wctx->level].str, key);
1277  writer_printf(wctx, "%lld", value);
1278 }
1279 
1280 static const Writer compact_writer = {
1281  .name = "compact",
1282  .priv_size = sizeof(CompactContext),
1283  .init = compact_init,
1286  .print_integer = compact_print_int,
1287  .print_string = compact_print_str,
1289  .priv_class = &compact_class,
1290 };
1291 
1292 /* CSV output */
1293 
1294 #undef OFFSET
1295 #define OFFSET(x) offsetof(CompactContext, x)
1296 
1297 static const AVOption csv_options[] = {
1298  {"item_sep", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str=","}, 0, 0 },
1299  {"s", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str=","}, 0, 0 },
1300  {"nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
1301  {"nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
1302  {"escape", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="csv"}, 0, 0 },
1303  {"e", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="csv"}, 0, 0 },
1304  {"print_section", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
1305  {"p", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
1306  {NULL},
1307 };
1308 
1309 DEFINE_WRITER_CLASS(csv);
1310 
1311 static const Writer csv_writer = {
1312  .name = "csv",
1313  .priv_size = sizeof(CompactContext),
1314  .init = compact_init,
1317  .print_integer = compact_print_int,
1318  .print_string = compact_print_str,
1320  .priv_class = &csv_class,
1321 };
1322 
1323 /* Flat output */
1324 
1325 typedef struct FlatContext {
1326  const AVClass *class;
1327  const char *sep_str;
1328  char sep;
1330 } FlatContext;
1331 
1332 #undef OFFSET
1333 #define OFFSET(x) offsetof(FlatContext, x)
1334 
1335 static const AVOption flat_options[]= {
1336  {"sep_char", "set separator", OFFSET(sep_str), AV_OPT_TYPE_STRING, {.str="."}, 0, 0 },
1337  {"s", "set separator", OFFSET(sep_str), AV_OPT_TYPE_STRING, {.str="."}, 0, 0 },
1338  {"hierarchical", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
1339  {"h", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
1340  {NULL},
1341 };
1342 
1344 
1346 {
1347  FlatContext *flat = wctx->priv;
1348 
1349  if (strlen(flat->sep_str) != 1) {
1350  av_log(wctx, AV_LOG_ERROR, "Item separator '%s' specified, but must contain a single character\n",
1351  flat->sep_str);
1352  return AVERROR(EINVAL);
1353  }
1354  flat->sep = flat->sep_str[0];
1355 
1356  return 0;
1357 }
1358 
1359 static const char *flat_escape_key_str(AVBPrint *dst, const char *src, const char sep)
1360 {
1361  const char *p;
1362 
1363  for (p = src; *p; p++) {
1364  if (!((*p >= '0' && *p <= '9') ||
1365  (*p >= 'a' && *p <= 'z') ||
1366  (*p >= 'A' && *p <= 'Z')))
1367  av_bprint_chars(dst, '_', 1);
1368  else
1369  av_bprint_chars(dst, *p, 1);
1370  }
1371  return dst->str;
1372 }
1373 
1374 static const char *flat_escape_value_str(AVBPrint *dst, const char *src)
1375 {
1376  const char *p;
1377 
1378  for (p = src; *p; p++) {
1379  switch (*p) {
1380  case '\n': av_bprintf(dst, "%s", "\\n"); break;
1381  case '\r': av_bprintf(dst, "%s", "\\r"); break;
1382  case '\\': av_bprintf(dst, "%s", "\\\\"); break;
1383  case '"': av_bprintf(dst, "%s", "\\\""); break;
1384  case '`': av_bprintf(dst, "%s", "\\`"); break;
1385  case '$': av_bprintf(dst, "%s", "\\$"); break;
1386  default: av_bprint_chars(dst, *p, 1); break;
1387  }
1388  }
1389  return dst->str;
1390 }
1391 
1393 {
1394  FlatContext *flat = wctx->priv;
1395  AVBPrint *buf = &wctx->section_pbuf[wctx->level];
1396  const struct section *section = wctx->section[wctx->level];
1397  const struct section *parent_section = wctx->level ?
1398  wctx->section[wctx->level-1] : NULL;
1399 
1400  /* build section header */
1401  av_bprint_clear(buf);
1402  if (!parent_section)
1403  return;
1404  av_bprintf(buf, "%s", wctx->section_pbuf[wctx->level-1].str);
1405 
1406  if (flat->hierarchical ||
1408  av_bprintf(buf, "%s%s", wctx->section[wctx->level]->name, flat->sep_str);
1409 
1410  if (parent_section->flags & SECTION_FLAG_IS_ARRAY) {
1411  int n = parent_section->id == SECTION_ID_PACKETS_AND_FRAMES ?
1412  wctx->nb_section_packet_frame : wctx->nb_item[wctx->level-1];
1413  av_bprintf(buf, "%d%s", n, flat->sep_str);
1414  }
1415  }
1416 }
1417 
1418 static void flat_print_int(WriterContext *wctx, const char *key, long long int value)
1419 {
1420  writer_printf(wctx, "%s%s=%lld\n", wctx->section_pbuf[wctx->level].str, key, value);
1421 }
1422 
1423 static void flat_print_str(WriterContext *wctx, const char *key, const char *value)
1424 {
1425  FlatContext *flat = wctx->priv;
1426  AVBPrint buf;
1427 
1428  writer_put_str(wctx, wctx->section_pbuf[wctx->level].str);
1430  writer_printf(wctx, "%s=", flat_escape_key_str(&buf, key, flat->sep));
1431  av_bprint_clear(&buf);
1432  writer_printf(wctx, "\"%s\"\n", flat_escape_value_str(&buf, value));
1433  av_bprint_finalize(&buf, NULL);
1434 }
1435 
1436 static const Writer flat_writer = {
1437  .name = "flat",
1438  .priv_size = sizeof(FlatContext),
1439  .init = flat_init,
1441  .print_integer = flat_print_int,
1442  .print_string = flat_print_str,
1444  .priv_class = &flat_class,
1445 };
1446 
1447 /* INI format output */
1448 
1449 typedef struct INIContext {
1450  const AVClass *class;
1452 } INIContext;
1453 
1454 #undef OFFSET
1455 #define OFFSET(x) offsetof(INIContext, x)
1456 
1457 static const AVOption ini_options[] = {
1458  {"hierarchical", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
1459  {"h", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
1460  {NULL},
1461 };
1462 
1463 DEFINE_WRITER_CLASS(ini);
1464 
1465 static char *ini_escape_str(AVBPrint *dst, const char *src)
1466 {
1467  int i = 0;
1468  char c = 0;
1469 
1470  while (c = src[i++]) {
1471  switch (c) {
1472  case '\b': av_bprintf(dst, "%s", "\\b"); break;
1473  case '\f': av_bprintf(dst, "%s", "\\f"); break;
1474  case '\n': av_bprintf(dst, "%s", "\\n"); break;
1475  case '\r': av_bprintf(dst, "%s", "\\r"); break;
1476  case '\t': av_bprintf(dst, "%s", "\\t"); break;
1477  case '\\':
1478  case '#' :
1479  case '=' :
1480  case ':' : av_bprint_chars(dst, '\\', 1);
1481  default:
1482  if ((unsigned char)c < 32)
1483  av_bprintf(dst, "\\x00%02x", c & 0xff);
1484  else
1485  av_bprint_chars(dst, c, 1);
1486  break;
1487  }
1488  }
1489  return dst->str;
1490 }
1491 
1493 {
1494  INIContext *ini = wctx->priv;
1495  AVBPrint *buf = &wctx->section_pbuf[wctx->level];
1496  const struct section *section = wctx->section[wctx->level];
1497  const struct section *parent_section = wctx->level ?
1498  wctx->section[wctx->level-1] : NULL;
1499 
1500  av_bprint_clear(buf);
1501  if (!parent_section) {
1502  writer_put_str(wctx, "# ffprobe output\n\n");
1503  return;
1504  }
1505 
1506  if (wctx->nb_item[wctx->level-1])
1507  writer_w8(wctx, '\n');
1508 
1509  av_bprintf(buf, "%s", wctx->section_pbuf[wctx->level-1].str);
1510  if (ini->hierarchical ||
1512  av_bprintf(buf, "%s%s", buf->str[0] ? "." : "", wctx->section[wctx->level]->name);
1513 
1514  if (parent_section->flags & SECTION_FLAG_IS_ARRAY) {
1515  int n = parent_section->id == SECTION_ID_PACKETS_AND_FRAMES ?
1516  wctx->nb_section_packet_frame : wctx->nb_item[wctx->level-1];
1517  av_bprintf(buf, ".%d", n);
1518  }
1519  }
1520 
1522  writer_printf(wctx, "[%s]\n", buf->str);
1523 }
1524 
1525 static void ini_print_str(WriterContext *wctx, const char *key, const char *value)
1526 {
1527  AVBPrint buf;
1528 
1530  writer_printf(wctx, "%s=", ini_escape_str(&buf, key));
1531  av_bprint_clear(&buf);
1532  writer_printf(wctx, "%s\n", ini_escape_str(&buf, value));
1533  av_bprint_finalize(&buf, NULL);
1534 }
1535 
1536 static void ini_print_int(WriterContext *wctx, const char *key, long long int value)
1537 {
1538  writer_printf(wctx, "%s=%lld\n", key, value);
1539 }
1540 
1541 static const Writer ini_writer = {
1542  .name = "ini",
1543  .priv_size = sizeof(INIContext),
1545  .print_integer = ini_print_int,
1546  .print_string = ini_print_str,
1548  .priv_class = &ini_class,
1549 };
1550 
1551 /* JSON output */
1552 
1553 typedef struct JSONContext {
1554  const AVClass *class;
1556  int compact;
1557  const char *item_sep, *item_start_end;
1558 } JSONContext;
1559 
1560 #undef OFFSET
1561 #define OFFSET(x) offsetof(JSONContext, x)
1562 
1563 static const AVOption json_options[]= {
1564  { "compact", "enable compact output", OFFSET(compact), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
1565  { "c", "enable compact output", OFFSET(compact), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
1566  { NULL }
1567 };
1568 
1569 DEFINE_WRITER_CLASS(json);
1570 
1572 {
1573  JSONContext *json = wctx->priv;
1574 
1575  json->item_sep = json->compact ? ", " : ",\n";
1576  json->item_start_end = json->compact ? " " : "\n";
1577 
1578  return 0;
1579 }
1580 
1581 static const char *json_escape_str(AVBPrint *dst, const char *src, void *log_ctx)
1582 {
1583  static const char json_escape[] = {'"', '\\', '\b', '\f', '\n', '\r', '\t', 0};
1584  static const char json_subst[] = {'"', '\\', 'b', 'f', 'n', 'r', 't', 0};
1585  const char *p;
1586 
1587  for (p = src; *p; p++) {
1588  char *s = strchr(json_escape, *p);
1589  if (s) {
1590  av_bprint_chars(dst, '\\', 1);
1591  av_bprint_chars(dst, json_subst[s - json_escape], 1);
1592  } else if ((unsigned char)*p < 32) {
1593  av_bprintf(dst, "\\u00%02x", *p & 0xff);
1594  } else {
1595  av_bprint_chars(dst, *p, 1);
1596  }
1597  }
1598  return dst->str;
1599 }
1600 
1601 #define JSON_INDENT() writer_printf(wctx, "%*c", json->indent_level * 4, ' ')
1602 
1604 {
1605  JSONContext *json = wctx->priv;
1606  AVBPrint buf;
1607  const struct section *section = wctx->section[wctx->level];
1608  const struct section *parent_section = wctx->level ?
1609  wctx->section[wctx->level-1] : NULL;
1610 
1611  if (wctx->level && wctx->nb_item[wctx->level-1])
1612  writer_put_str(wctx, ",\n");
1613 
1615  writer_put_str(wctx, "{\n");
1616  json->indent_level++;
1617  } else {
1619  json_escape_str(&buf, section->name, wctx);
1620  JSON_INDENT();
1621 
1622  json->indent_level++;
1624  writer_printf(wctx, "\"%s\": [\n", buf.str);
1625  } else if (parent_section && !(parent_section->flags & SECTION_FLAG_IS_ARRAY)) {
1626  writer_printf(wctx, "\"%s\": {%s", buf.str, json->item_start_end);
1627  } else {
1628  writer_printf(wctx, "{%s", json->item_start_end);
1629 
1630  /* this is required so the parser can distinguish between packets and frames */
1631  if (parent_section && parent_section->id == SECTION_ID_PACKETS_AND_FRAMES) {
1632  if (!json->compact)
1633  JSON_INDENT();
1634  writer_printf(wctx, "\"type\": \"%s\"", section->name);
1635  wctx->nb_item[wctx->level]++;
1636  }
1637  }
1638  av_bprint_finalize(&buf, NULL);
1639  }
1640 }
1641 
1643 {
1644  JSONContext *json = wctx->priv;
1645  const struct section *section = wctx->section[wctx->level];
1646 
1647  if (wctx->level == 0) {
1648  json->indent_level--;
1649  writer_put_str(wctx, "\n}\n");
1650  } else if (section->flags & SECTION_FLAG_IS_ARRAY) {
1651  writer_w8(wctx, '\n');
1652  json->indent_level--;
1653  JSON_INDENT();
1654  writer_w8(wctx, ']');
1655  } else {
1656  writer_put_str(wctx, json->item_start_end);
1657  json->indent_level--;
1658  if (!json->compact)
1659  JSON_INDENT();
1660  writer_w8(wctx, '}');
1661  }
1662 }
1663 
1664 static inline void json_print_item_str(WriterContext *wctx,
1665  const char *key, const char *value)
1666 {
1667  AVBPrint buf;
1668 
1670  writer_printf(wctx, "\"%s\":", json_escape_str(&buf, key, wctx));
1671  av_bprint_clear(&buf);
1672  writer_printf(wctx, " \"%s\"", json_escape_str(&buf, value, wctx));
1673  av_bprint_finalize(&buf, NULL);
1674 }
1675 
1676 static void json_print_str(WriterContext *wctx, const char *key, const char *value)
1677 {
1678  JSONContext *json = wctx->priv;
1679  const struct section *parent_section = wctx->level ?
1680  wctx->section[wctx->level-1] : NULL;
1681 
1682  if (wctx->nb_item[wctx->level] || (parent_section && parent_section->id == SECTION_ID_PACKETS_AND_FRAMES))
1683  writer_put_str(wctx, json->item_sep);
1684  if (!json->compact)
1685  JSON_INDENT();
1686  json_print_item_str(wctx, key, value);
1687 }
1688 
1689 static void json_print_int(WriterContext *wctx, const char *key, long long int value)
1690 {
1691  JSONContext *json = wctx->priv;
1692  const struct section *parent_section = wctx->level ?
1693  wctx->section[wctx->level-1] : NULL;
1694  AVBPrint buf;
1695 
1696  if (wctx->nb_item[wctx->level] || (parent_section && parent_section->id == SECTION_ID_PACKETS_AND_FRAMES))
1697  writer_put_str(wctx, json->item_sep);
1698  if (!json->compact)
1699  JSON_INDENT();
1700 
1702  writer_printf(wctx, "\"%s\": %lld", json_escape_str(&buf, key, wctx), value);
1703  av_bprint_finalize(&buf, NULL);
1704 }
1705 
1706 static const Writer json_writer = {
1707  .name = "json",
1708  .priv_size = sizeof(JSONContext),
1709  .init = json_init,
1712  .print_integer = json_print_int,
1713  .print_string = json_print_str,
1715  .priv_class = &json_class,
1716 };
1717 
1718 /* XML output */
1719 
1720 typedef struct XMLContext {
1721  const AVClass *class;
1726 } XMLContext;
1727 
1728 #undef OFFSET
1729 #define OFFSET(x) offsetof(XMLContext, x)
1730 
1731 static const AVOption xml_options[] = {
1732  {"fully_qualified", "specify if the output should be fully qualified", OFFSET(fully_qualified), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
1733  {"q", "specify if the output should be fully qualified", OFFSET(fully_qualified), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
1734  {"xsd_strict", "ensure that the output is XSD compliant", OFFSET(xsd_strict), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
1735  {"x", "ensure that the output is XSD compliant", OFFSET(xsd_strict), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
1736  {NULL},
1737 };
1738 
1739 DEFINE_WRITER_CLASS(xml);
1740 
1741 static av_cold int xml_init(WriterContext *wctx)
1742 {
1743  XMLContext *xml = wctx->priv;
1744 
1745  if (xml->xsd_strict) {
1746  xml->fully_qualified = 1;
1747 #define CHECK_COMPLIANCE(opt, opt_name) \
1748  if (opt) { \
1749  av_log(wctx, AV_LOG_ERROR, \
1750  "XSD-compliant output selected but option '%s' was selected, XML output may be non-compliant.\n" \
1751  "You need to disable such option with '-no%s'\n", opt_name, opt_name); \
1752  return AVERROR(EINVAL); \
1753  }
1754  CHECK_COMPLIANCE(show_private_data, "private");
1757  }
1758 
1759  return 0;
1760 }
1761 
1762 #define XML_INDENT() writer_printf(wctx, "%*c", xml->indent_level * 4, ' ')
1763 
1765 {
1766  XMLContext *xml = wctx->priv;
1767  const struct section *section = wctx->section[wctx->level];
1768  const struct section *parent_section = wctx->level ?
1769  wctx->section[wctx->level-1] : NULL;
1770 
1771  if (wctx->level == 0) {
1772  const char *qual = " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
1773  "xmlns:ffprobe=\"http://www.ffmpeg.org/schema/ffprobe\" "
1774  "xsi:schemaLocation=\"http://www.ffmpeg.org/schema/ffprobe ffprobe.xsd\"";
1775 
1776  writer_put_str(wctx, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1777  writer_printf(wctx, "<%sffprobe%s>\n",
1778  xml->fully_qualified ? "ffprobe:" : "",
1779  xml->fully_qualified ? qual : "");
1780  return;
1781  }
1782 
1783  if (xml->within_tag) {
1784  xml->within_tag = 0;
1785  writer_put_str(wctx, ">\n");
1786  }
1788  xml->indent_level++;
1789  } else {
1790  if (parent_section && (parent_section->flags & SECTION_FLAG_IS_WRAPPER) &&
1791  wctx->level && wctx->nb_item[wctx->level-1])
1792  writer_w8(wctx, '\n');
1793  xml->indent_level++;
1794 
1796  XML_INDENT(); writer_printf(wctx, "<%s>\n", section->name);
1797  } else {
1798  XML_INDENT(); writer_printf(wctx, "<%s ", section->name);
1799  xml->within_tag = 1;
1800  }
1801  }
1802 }
1803 
1805 {
1806  XMLContext *xml = wctx->priv;
1807  const struct section *section = wctx->section[wctx->level];
1808 
1809  if (wctx->level == 0) {
1810  writer_printf(wctx, "</%sffprobe>\n", xml->fully_qualified ? "ffprobe:" : "");
1811  } else if (xml->within_tag) {
1812  xml->within_tag = 0;
1813  writer_put_str(wctx, "/>\n");
1814  xml->indent_level--;
1816  xml->indent_level--;
1817  } else {
1818  XML_INDENT(); writer_printf(wctx, "</%s>\n", section->name);
1819  xml->indent_level--;
1820  }
1821 }
1822 
1823 static void xml_print_str(WriterContext *wctx, const char *key, const char *value)
1824 {
1825  AVBPrint buf;
1826  XMLContext *xml = wctx->priv;
1827  const struct section *section = wctx->section[wctx->level];
1828 
1830 
1832  XML_INDENT();
1833  av_bprint_escape(&buf, key, NULL,
1835  writer_printf(wctx, "<%s key=\"%s\"",
1836  section->element_name, buf.str);
1837  av_bprint_clear(&buf);
1838 
1839  av_bprint_escape(&buf, value, NULL,
1841  writer_printf(wctx, " value=\"%s\"/>\n", buf.str);
1842  } else {
1843  if (wctx->nb_item[wctx->level])
1844  writer_w8(wctx, ' ');
1845 
1846  av_bprint_escape(&buf, value, NULL,
1848  writer_printf(wctx, "%s=\"%s\"", key, buf.str);
1849  }
1850 
1851  av_bprint_finalize(&buf, NULL);
1852 }
1853 
1854 static void xml_print_int(WriterContext *wctx, const char *key, long long int value)
1855 {
1856  if (wctx->nb_item[wctx->level])
1857  writer_w8(wctx, ' ');
1858  writer_printf(wctx, "%s=\"%lld\"", key, value);
1859 }
1860 
1861 static Writer xml_writer = {
1862  .name = "xml",
1863  .priv_size = sizeof(XMLContext),
1864  .init = xml_init,
1867  .print_integer = xml_print_int,
1868  .print_string = xml_print_str,
1870  .priv_class = &xml_class,
1871 };
1872 
1873 static void writer_register_all(void)
1874 {
1875  static int initialized;
1876 
1877  if (initialized)
1878  return;
1879  initialized = 1;
1880 
1888 }
1889 
1890 #define print_fmt(k, f, ...) do { \
1891  av_bprint_clear(&pbuf); \
1892  av_bprintf(&pbuf, f, __VA_ARGS__); \
1893  writer_print_string(w, k, pbuf.str, 0); \
1894 } while (0)
1895 
1896 #define print_list_fmt(k, f, n, m, ...) do { \
1897  av_bprint_clear(&pbuf); \
1898  for (int idx = 0; idx < n; idx++) { \
1899  for (int idx2 = 0; idx2 < m; idx2++) { \
1900  if (idx > 0 || idx2 > 0) \
1901  av_bprint_chars(&pbuf, ' ', 1); \
1902  av_bprintf(&pbuf, f, __VA_ARGS__); \
1903  } \
1904  } \
1905  writer_print_string(w, k, pbuf.str, 0); \
1906 } while (0)
1907 
1908 #define print_int(k, v) writer_print_integer(w, k, v)
1909 #define print_q(k, v, s) writer_print_rational(w, k, v, s)
1910 #define print_str(k, v) writer_print_string(w, k, v, 0)
1911 #define print_str_opt(k, v) writer_print_string(w, k, v, PRINT_STRING_OPT)
1912 #define print_str_validate(k, v) writer_print_string(w, k, v, PRINT_STRING_VALIDATE)
1913 #define print_time(k, v, tb) writer_print_time(w, k, v, tb, 0)
1914 #define print_ts(k, v) writer_print_ts(w, k, v, 0)
1915 #define print_duration_time(k, v, tb) writer_print_time(w, k, v, tb, 1)
1916 #define print_duration_ts(k, v) writer_print_ts(w, k, v, 1)
1917 #define print_val(k, v, u) do { \
1918  struct unit_value uv; \
1919  uv.val.i = v; \
1920  uv.unit = u; \
1921  writer_print_string(w, k, value_string(val_str, sizeof(val_str), uv), 0); \
1922 } while (0)
1923 
1924 #define print_section_header(s) writer_print_section_header(w, s)
1925 #define print_section_footer(s) writer_print_section_footer(w, s)
1926 
1927 #define REALLOCZ_ARRAY_STREAM(ptr, cur_n, new_n) \
1928 { \
1929  ret = av_reallocp_array(&(ptr), (new_n), sizeof(*(ptr))); \
1930  if (ret < 0) \
1931  goto end; \
1932  memset( (ptr) + (cur_n), 0, ((new_n) - (cur_n)) * sizeof(*(ptr)) ); \
1933 }
1934 
1935 static inline int show_tags(WriterContext *w, AVDictionary *tags, int section_id)
1936 {
1937  const AVDictionaryEntry *tag = NULL;
1938  int ret = 0;
1939 
1940  if (!tags)
1941  return 0;
1942  writer_print_section_header(w, section_id);
1943 
1944  while ((tag = av_dict_iterate(tags, tag))) {
1945  if ((ret = print_str_validate(tag->key, tag->value)) < 0)
1946  break;
1947  }
1949 
1950  return ret;
1951 }
1952 
1954 {
1955  if (!dovi)
1956  return;
1957 
1958  {
1959  const AVDOVIRpuDataHeader *hdr = av_dovi_get_header(dovi);
1960  const AVDOVIDataMapping *mapping = av_dovi_get_mapping(dovi);
1962  AVBPrint pbuf;
1963 
1965 
1966  // header
1967  print_int("rpu_type", hdr->rpu_type);
1968  print_int("rpu_format", hdr->rpu_format);
1969  print_int("vdr_rpu_profile", hdr->vdr_rpu_profile);
1970  print_int("vdr_rpu_level", hdr->vdr_rpu_level);
1971  print_int("chroma_resampling_explicit_filter_flag",
1973  print_int("coef_data_type", hdr->coef_data_type);
1974  print_int("coef_log2_denom", hdr->coef_log2_denom);
1975  print_int("vdr_rpu_normalized_idc", hdr->vdr_rpu_normalized_idc);
1976  print_int("bl_video_full_range_flag", hdr->bl_video_full_range_flag);
1977  print_int("bl_bit_depth", hdr->bl_bit_depth);
1978  print_int("el_bit_depth", hdr->el_bit_depth);
1979  print_int("vdr_bit_depth", hdr->vdr_bit_depth);
1980  print_int("spatial_resampling_filter_flag",
1982  print_int("el_spatial_resampling_filter_flag",
1984  print_int("disable_residual_flag", hdr->disable_residual_flag);
1985 
1986  // data mapping values
1987  print_int("vdr_rpu_id", mapping->vdr_rpu_id);
1988  print_int("mapping_color_space", mapping->mapping_color_space);
1989  print_int("mapping_chroma_format_idc",
1990  mapping->mapping_chroma_format_idc);
1991 
1992  print_int("nlq_method_idc", mapping->nlq_method_idc);
1993  switch (mapping->nlq_method_idc) {
1994  case AV_DOVI_NLQ_NONE:
1995  print_str("nlq_method_idc_name", "none");
1996  break;
1997  case AV_DOVI_NLQ_LINEAR_DZ:
1998  print_str("nlq_method_idc_name", "linear_dz");
1999  break;
2000  default:
2001  print_str("nlq_method_idc_name", "unknown");
2002  break;
2003  }
2004 
2005  print_int("num_x_partitions", mapping->num_x_partitions);
2006  print_int("num_y_partitions", mapping->num_y_partitions);
2007 
2009 
2010  for (int c = 0; c < 3; c++) {
2011  const AVDOVIReshapingCurve *curve = &mapping->curves[c];
2013 
2014  print_list_fmt("pivots", "%"PRIu16, curve->num_pivots, 1, curve->pivots[idx]);
2015 
2017  for (int i = 0; i < curve->num_pivots - 1; i++) {
2018 
2020  print_int("mapping_idc", curve->mapping_idc[i]);
2021  switch (curve->mapping_idc[i]) {
2023  print_str("mapping_idc_name", "polynomial");
2024  print_int("poly_order", curve->poly_order[i]);
2025  print_list_fmt("poly_coef", "%"PRIi64,
2026  curve->poly_order[i] + 1, 1,
2027  curve->poly_coef[i][idx]);
2028  break;
2029  case AV_DOVI_MAPPING_MMR:
2030  print_str("mapping_idc_name", "mmr");
2031  print_int("mmr_order", curve->mmr_order[i]);
2032  print_int("mmr_constant", curve->mmr_constant[i]);
2033  print_list_fmt("mmr_coef", "%"PRIi64,
2034  curve->mmr_order[i], 7,
2035  curve->mmr_coef[i][idx][idx2]);
2036  break;
2037  default:
2038  print_str("mapping_idc_name", "unknown");
2039  break;
2040  }
2041 
2042  // SECTION_ID_FRAME_SIDE_DATA_PIECE
2044  }
2045 
2046  // SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST
2048 
2049  if (mapping->nlq_method_idc != AV_DOVI_NLQ_NONE) {
2050  const AVDOVINLQParams *nlq = &mapping->nlq[c];
2051  print_int("nlq_offset", nlq->nlq_offset);
2052  print_int("vdr_in_max", nlq->vdr_in_max);
2053 
2054  switch (mapping->nlq_method_idc) {
2055  case AV_DOVI_NLQ_LINEAR_DZ:
2056  print_int("linear_deadzone_slope", nlq->linear_deadzone_slope);
2057  print_int("linear_deadzone_threshold", nlq->linear_deadzone_threshold);
2058  break;
2059  }
2060  }
2061 
2062  // SECTION_ID_FRAME_SIDE_DATA_COMPONENT
2064  }
2065 
2066  // SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST
2068 
2069  // color metadata
2070  print_int("dm_metadata_id", color->dm_metadata_id);
2071  print_int("scene_refresh_flag", color->scene_refresh_flag);
2072  print_list_fmt("ycc_to_rgb_matrix", "%d/%d",
2073  FF_ARRAY_ELEMS(color->ycc_to_rgb_matrix), 1,
2074  color->ycc_to_rgb_matrix[idx].num,
2075  color->ycc_to_rgb_matrix[idx].den);
2076  print_list_fmt("ycc_to_rgb_offset", "%d/%d",
2077  FF_ARRAY_ELEMS(color->ycc_to_rgb_offset), 1,
2078  color->ycc_to_rgb_offset[idx].num,
2079  color->ycc_to_rgb_offset[idx].den);
2080  print_list_fmt("rgb_to_lms_matrix", "%d/%d",
2081  FF_ARRAY_ELEMS(color->rgb_to_lms_matrix), 1,
2082  color->rgb_to_lms_matrix[idx].num,
2083  color->rgb_to_lms_matrix[idx].den);
2084  print_int("signal_eotf", color->signal_eotf);
2085  print_int("signal_eotf_param0", color->signal_eotf_param0);
2086  print_int("signal_eotf_param1", color->signal_eotf_param1);
2087  print_int("signal_eotf_param2", color->signal_eotf_param2);
2088  print_int("signal_bit_depth", color->signal_bit_depth);
2089  print_int("signal_color_space", color->signal_color_space);
2090  print_int("signal_chroma_format", color->signal_chroma_format);
2091  print_int("signal_full_range_flag", color->signal_full_range_flag);
2092  print_int("source_min_pq", color->source_min_pq);
2093  print_int("source_max_pq", color->source_max_pq);
2094  print_int("source_diagonal", color->source_diagonal);
2095 
2096  av_bprint_finalize(&pbuf, NULL);
2097  }
2098 }
2099 
2101 {
2102  if (!metadata)
2103  return;
2104  print_int("application version", metadata->application_version);
2105  print_int("num_windows", metadata->num_windows);
2106  for (int n = 1; n < metadata->num_windows; n++) {
2107  const AVHDRPlusColorTransformParams *params = &metadata->params[n];
2108  print_q("window_upper_left_corner_x",
2109  params->window_upper_left_corner_x,'/');
2110  print_q("window_upper_left_corner_y",
2111  params->window_upper_left_corner_y,'/');
2112  print_q("window_lower_right_corner_x",
2113  params->window_lower_right_corner_x,'/');
2114  print_q("window_lower_right_corner_y",
2115  params->window_lower_right_corner_y,'/');
2116  print_q("window_upper_left_corner_x",
2117  params->window_upper_left_corner_x,'/');
2118  print_q("window_upper_left_corner_y",
2119  params->window_upper_left_corner_y,'/');
2120  print_int("center_of_ellipse_x",
2121  params->center_of_ellipse_x ) ;
2122  print_int("center_of_ellipse_y",
2123  params->center_of_ellipse_y );
2124  print_int("rotation_angle",
2125  params->rotation_angle);
2126  print_int("semimajor_axis_internal_ellipse",
2128  print_int("semimajor_axis_external_ellipse",
2130  print_int("semiminor_axis_external_ellipse",
2132  print_int("overlap_process_option",
2133  params->overlap_process_option);
2134  }
2135  print_q("targeted_system_display_maximum_luminance",
2138  print_int("num_rows_targeted_system_display_actual_peak_luminance",
2140  print_int("num_cols_targeted_system_display_actual_peak_luminance",
2142  for (int i = 0; i < metadata->num_rows_targeted_system_display_actual_peak_luminance; i++) {
2143  for (int j = 0; j < metadata->num_cols_targeted_system_display_actual_peak_luminance; j++) {
2144  print_q("targeted_system_display_actual_peak_luminance",
2146  }
2147  }
2148  }
2149  for (int n = 0; n < metadata->num_windows; n++) {
2150  const AVHDRPlusColorTransformParams *params = &metadata->params[n];
2151  for (int i = 0; i < 3; i++) {
2152  print_q("maxscl",params->maxscl[i],'/');
2153  }
2154  print_q("average_maxrgb",
2155  params->average_maxrgb,'/');
2156  print_int("num_distribution_maxrgb_percentiles",
2158  for (int i = 0; i < params->num_distribution_maxrgb_percentiles; i++) {
2159  print_int("distribution_maxrgb_percentage",
2160  params->distribution_maxrgb[i].percentage);
2161  print_q("distribution_maxrgb_percentile",
2162  params->distribution_maxrgb[i].percentile,'/');
2163  }
2164  print_q("fraction_bright_pixels",
2165  params->fraction_bright_pixels,'/');
2166  }
2168  print_int("num_rows_mastering_display_actual_peak_luminance",
2170  print_int("num_cols_mastering_display_actual_peak_luminance",
2172  for (int i = 0; i < metadata->num_rows_mastering_display_actual_peak_luminance; i++) {
2173  for (int j = 0; j < metadata->num_cols_mastering_display_actual_peak_luminance; j++) {
2174  print_q("mastering_display_actual_peak_luminance",
2175  metadata->mastering_display_actual_peak_luminance[i][j],'/');
2176  }
2177  }
2178  }
2179 
2180  for (int n = 0; n < metadata->num_windows; n++) {
2181  const AVHDRPlusColorTransformParams *params = &metadata->params[n];
2182  if (params->tone_mapping_flag) {
2183  print_q("knee_point_x", params->knee_point_x,'/');
2184  print_q("knee_point_y", params->knee_point_y,'/');
2185  print_int("num_bezier_curve_anchors",
2186  params->num_bezier_curve_anchors );
2187  for (int i = 0; i < params->num_bezier_curve_anchors; i++) {
2188  print_q("bezier_curve_anchors",
2189  params->bezier_curve_anchors[i],'/');
2190  }
2191  }
2192  if (params->color_saturation_mapping_flag) {
2193  print_q("color_saturation_weight",
2194  params->color_saturation_weight,'/');
2195  }
2196  }
2197 }
2198 
2200 {
2201  if (!metadata)
2202  return;
2203  print_int("system_start_code", metadata->system_start_code);
2204  print_int("num_windows", metadata->num_windows);
2205 
2206  for (int n = 0; n < metadata->num_windows; n++) {
2207  const AVHDRVividColorTransformParams *params = &metadata->params[n];
2208 
2209  print_q("minimum_maxrgb", params->minimum_maxrgb, '/');
2210  print_q("average_maxrgb", params->average_maxrgb, '/');
2211  print_q("variance_maxrgb", params->variance_maxrgb, '/');
2212  print_q("maximum_maxrgb", params->maximum_maxrgb, '/');
2213  }
2214 
2215  for (int n = 0; n < metadata->num_windows; n++) {
2216  const AVHDRVividColorTransformParams *params = &metadata->params[n];
2217 
2218  print_int("tone_mapping_mode_flag", params->tone_mapping_mode_flag);
2219  if (params->tone_mapping_mode_flag) {
2220  print_int("tone_mapping_param_num", params->tone_mapping_param_num);
2221  for (int i = 0; i < params->tone_mapping_param_num; i++) {
2222  const AVHDRVividColorToneMappingParams *tm_params = &params->tm_params[i];
2223 
2224  print_q("targeted_system_display_maximum_luminance",
2226  print_int("base_enable_flag", tm_params->base_enable_flag);
2227  if (tm_params->base_enable_flag) {
2228  print_q("base_param_m_p", tm_params->base_param_m_p, '/');
2229  print_q("base_param_m_m", tm_params->base_param_m_m, '/');
2230  print_q("base_param_m_a", tm_params->base_param_m_a, '/');
2231  print_q("base_param_m_b", tm_params->base_param_m_b, '/');
2232  print_q("base_param_m_n", tm_params->base_param_m_n, '/');
2233 
2234  print_int("base_param_k1", tm_params->base_param_k1);
2235  print_int("base_param_k2", tm_params->base_param_k2);
2236  print_int("base_param_k3", tm_params->base_param_k3);
2237  print_int("base_param_Delta_enable_mode",
2238  tm_params->base_param_Delta_enable_mode);
2239  print_q("base_param_Delta", tm_params->base_param_Delta, '/');
2240  }
2241  print_int("3Spline_enable_flag", tm_params->three_Spline_enable_flag);
2242  if (tm_params->three_Spline_enable_flag) {
2243  print_int("3Spline_num", tm_params->three_Spline_num);
2244 
2245  for (int j = 0; j < tm_params->three_Spline_num; j++) {
2246  const AVHDRVivid3SplineParams *three_spline = &tm_params->three_spline[j];
2247  print_int("3Spline_TH_mode", three_spline->th_mode);
2248  if (three_spline->th_mode == 0 || three_spline->th_mode == 2)
2249  print_q("3Spline_TH_enable_MB", three_spline->th_enable_mb, '/');
2250  print_q("3Spline_TH_enable", three_spline->th_enable, '/');
2251  print_q("3Spline_TH_Delta1", three_spline->th_delta1, '/');
2252  print_q("3Spline_TH_Delta2", three_spline->th_delta2, '/');
2253  print_q("3Spline_enable_Strength", three_spline->enable_strength, '/');
2254  }
2255  }
2256  }
2257  }
2258 
2259  print_int("color_saturation_mapping_flag", params->color_saturation_mapping_flag);
2260  if (params->color_saturation_mapping_flag) {
2261  print_int("color_saturation_num", params->color_saturation_num);
2262  for (int i = 0; i < params->color_saturation_num; i++) {
2263  print_q("color_saturation_gain", params->color_saturation_gain[i], '/');
2264  }
2265  }
2266  }
2267 }
2268 
2270  const AVAmbientViewingEnvironment *env)
2271 {
2272  if (!env)
2273  return;
2274 
2275  print_q("ambient_illuminance", env->ambient_illuminance, '/');
2276  print_q("ambient_light_x", env->ambient_light_x, '/');
2277  print_q("ambient_light_y", env->ambient_light_y, '/');
2278 }
2279 
2281  AVCodecParameters *par,
2282  const AVPacketSideData *side_data,
2283  int nb_side_data,
2284  SectionID id_data_list,
2285  SectionID id_data)
2286 {
2287  int i;
2288 
2289  writer_print_section_header(w, id_data_list);
2290  for (i = 0; i < nb_side_data; i++) {
2291  const AVPacketSideData *sd = &side_data[i];
2292  const char *name = av_packet_side_data_name(sd->type);
2293 
2294  writer_print_section_header(w, id_data);
2295  print_str("side_data_type", name ? name : "unknown");
2296  if (sd->type == AV_PKT_DATA_DISPLAYMATRIX && sd->size >= 9*4) {
2297  double rotation = av_display_rotation_get((int32_t *)sd->data);
2298  if (isnan(rotation))
2299  rotation = 0;
2300  writer_print_integers(w, "displaymatrix", sd->data, 9, " %11d", 3, 4, 1);
2301  print_int("rotation", rotation);
2302  } else if (sd->type == AV_PKT_DATA_STEREO3D) {
2303  const AVStereo3D *stereo = (AVStereo3D *)sd->data;
2304  print_str("type", av_stereo3d_type_name(stereo->type));
2305  print_int("inverted", !!(stereo->flags & AV_STEREO3D_FLAG_INVERT));
2306  } else if (sd->type == AV_PKT_DATA_SPHERICAL) {
2307  const AVSphericalMapping *spherical = (AVSphericalMapping *)sd->data;
2308  print_str("projection", av_spherical_projection_name(spherical->projection));
2309  if (spherical->projection == AV_SPHERICAL_CUBEMAP) {
2310  print_int("padding", spherical->padding);
2311  } else if (spherical->projection == AV_SPHERICAL_EQUIRECTANGULAR_TILE) {
2312  size_t l, t, r, b;
2313  av_spherical_tile_bounds(spherical, par->width, par->height,
2314  &l, &t, &r, &b);
2315  print_int("bound_left", l);
2316  print_int("bound_top", t);
2317  print_int("bound_right", r);
2318  print_int("bound_bottom", b);
2319  }
2320 
2321  print_int("yaw", (double) spherical->yaw / (1 << 16));
2322  print_int("pitch", (double) spherical->pitch / (1 << 16));
2323  print_int("roll", (double) spherical->roll / (1 << 16));
2324  } else if (sd->type == AV_PKT_DATA_SKIP_SAMPLES && sd->size == 10) {
2325  print_int("skip_samples", AV_RL32(sd->data));
2326  print_int("discard_padding", AV_RL32(sd->data + 4));
2327  print_int("skip_reason", AV_RL8(sd->data + 8));
2328  print_int("discard_reason", AV_RL8(sd->data + 9));
2329  } else if (sd->type == AV_PKT_DATA_MASTERING_DISPLAY_METADATA) {
2331 
2332  if (metadata->has_primaries) {
2333  print_q("red_x", metadata->display_primaries[0][0], '/');
2334  print_q("red_y", metadata->display_primaries[0][1], '/');
2335  print_q("green_x", metadata->display_primaries[1][0], '/');
2336  print_q("green_y", metadata->display_primaries[1][1], '/');
2337  print_q("blue_x", metadata->display_primaries[2][0], '/');
2338  print_q("blue_y", metadata->display_primaries[2][1], '/');
2339 
2340  print_q("white_point_x", metadata->white_point[0], '/');
2341  print_q("white_point_y", metadata->white_point[1], '/');
2342  }
2343 
2344  if (metadata->has_luminance) {
2345  print_q("min_luminance", metadata->min_luminance, '/');
2346  print_q("max_luminance", metadata->max_luminance, '/');
2347  }
2348  } else if (sd->type == AV_PKT_DATA_CONTENT_LIGHT_LEVEL) {
2350  print_int("max_content", metadata->MaxCLL);
2351  print_int("max_average", metadata->MaxFALL);
2352  } else if (sd->type == AV_PKT_DATA_DYNAMIC_HDR10_PLUS) {
2353  AVDynamicHDRPlus *metadata = (AVDynamicHDRPlus *)sd->data;
2354  print_dynamic_hdr10_plus(w, metadata);
2355  } else if (sd->type == AV_PKT_DATA_DOVI_CONF) {
2357  print_int("dv_version_major", dovi->dv_version_major);
2358  print_int("dv_version_minor", dovi->dv_version_minor);
2359  print_int("dv_profile", dovi->dv_profile);
2360  print_int("dv_level", dovi->dv_level);
2361  print_int("rpu_present_flag", dovi->rpu_present_flag);
2362  print_int("el_present_flag", dovi->el_present_flag);
2363  print_int("bl_present_flag", dovi->bl_present_flag);
2364  print_int("dv_bl_signal_compatibility_id", dovi->dv_bl_signal_compatibility_id);
2365  } else if (sd->type == AV_PKT_DATA_AUDIO_SERVICE_TYPE) {
2366  enum AVAudioServiceType *t = (enum AVAudioServiceType *)sd->data;
2367  print_int("service_type", *t);
2368  } else if (sd->type == AV_PKT_DATA_MPEGTS_STREAM_ID) {
2369  print_int("id", *sd->data);
2370  } else if (sd->type == AV_PKT_DATA_CPB_PROPERTIES) {
2371  const AVCPBProperties *prop = (AVCPBProperties *)sd->data;
2372  print_int("max_bitrate", prop->max_bitrate);
2373  print_int("min_bitrate", prop->min_bitrate);
2374  print_int("avg_bitrate", prop->avg_bitrate);
2375  print_int("buffer_size", prop->buffer_size);
2376  print_int("vbv_delay", prop->vbv_delay);
2377  } else if (sd->type == AV_PKT_DATA_WEBVTT_IDENTIFIER ||
2379  if (do_show_data)
2380  writer_print_data(w, "data", sd->data, sd->size);
2381  writer_print_data_hash(w, "data_hash", sd->data, sd->size);
2382  } else if (sd->type == AV_PKT_DATA_AFD && sd->size > 0) {
2383  print_int("active_format", *sd->data);
2384  }
2386  }
2388 }
2389 
2390 static void print_private_data(WriterContext *w, void *priv_data)
2391 {
2392  const AVOption *opt = NULL;
2393  while (opt = av_opt_next(priv_data, opt)) {
2394  uint8_t *str;
2395  if (!(opt->flags & AV_OPT_FLAG_EXPORT)) continue;
2396  if (av_opt_get(priv_data, opt->name, 0, &str) >= 0) {
2397  print_str(opt->name, str);
2398  av_free(str);
2399  }
2400  }
2401 }
2402 
2404 {
2405  const char *val = av_color_range_name(color_range);
2407  print_str_opt("color_range", "unknown");
2408  } else {
2409  print_str("color_range", val);
2410  }
2411 }
2412 
2413 static void print_color_space(WriterContext *w, enum AVColorSpace color_space)
2414 {
2415  const char *val = av_color_space_name(color_space);
2416  if (!val || color_space == AVCOL_SPC_UNSPECIFIED) {
2417  print_str_opt("color_space", "unknown");
2418  } else {
2419  print_str("color_space", val);
2420  }
2421 }
2422 
2424 {
2427  print_str_opt("color_primaries", "unknown");
2428  } else {
2429  print_str("color_primaries", val);
2430  }
2431 }
2432 
2434 {
2435  const char *val = av_color_transfer_name(color_trc);
2436  if (!val || color_trc == AVCOL_TRC_UNSPECIFIED) {
2437  print_str_opt("color_transfer", "unknown");
2438  } else {
2439  print_str("color_transfer", val);
2440  }
2441 }
2442 
2443 static void print_chroma_location(WriterContext *w, enum AVChromaLocation chroma_location)
2444 {
2445  const char *val = av_chroma_location_name(chroma_location);
2446  if (!val || chroma_location == AVCHROMA_LOC_UNSPECIFIED) {
2447  print_str_opt("chroma_location", "unspecified");
2448  } else {
2449  print_str("chroma_location", val);
2450  }
2451 }
2452 
2453 static void clear_log(int need_lock)
2454 {
2455  int i;
2456 
2457  if (need_lock)
2458  pthread_mutex_lock(&log_mutex);
2459  for (i=0; i<log_buffer_size; i++) {
2460  av_freep(&log_buffer[i].context_name);
2461  av_freep(&log_buffer[i].parent_name);
2462  av_freep(&log_buffer[i].log_message);
2463  }
2464  log_buffer_size = 0;
2465  if(need_lock)
2466  pthread_mutex_unlock(&log_mutex);
2467 }
2468 
2469 static int show_log(WriterContext *w, int section_ids, int section_id, int log_level)
2470 {
2471  int i;
2472  pthread_mutex_lock(&log_mutex);
2473  if (!log_buffer_size) {
2474  pthread_mutex_unlock(&log_mutex);
2475  return 0;
2476  }
2477  writer_print_section_header(w, section_ids);
2478 
2479  for (i=0; i<log_buffer_size; i++) {
2480  if (log_buffer[i].log_level <= log_level) {
2481  writer_print_section_header(w, section_id);
2482  print_str("context", log_buffer[i].context_name);
2483  print_int("level", log_buffer[i].log_level);
2484  print_int("category", log_buffer[i].category);
2485  if (log_buffer[i].parent_name) {
2486  print_str("parent_context", log_buffer[i].parent_name);
2487  print_int("parent_category", log_buffer[i].parent_category);
2488  } else {
2489  print_str_opt("parent_context", "N/A");
2490  print_str_opt("parent_category", "N/A");
2491  }
2492  print_str("message", log_buffer[i].log_message);
2494  }
2495  }
2496  clear_log(0);
2497  pthread_mutex_unlock(&log_mutex);
2498 
2500 
2501  return 0;
2502 }
2503 
2504 static void show_packet(WriterContext *w, InputFile *ifile, AVPacket *pkt, int packet_idx)
2505 {
2506  char val_str[128];
2507  AVStream *st = ifile->streams[pkt->stream_index].st;
2508  AVBPrint pbuf;
2509  const char *s;
2510 
2512 
2514 
2516  if (s) print_str ("codec_type", s);
2517  else print_str_opt("codec_type", "unknown");
2518  print_int("stream_index", pkt->stream_index);
2519  print_ts ("pts", pkt->pts);
2520  print_time("pts_time", pkt->pts, &st->time_base);
2521  print_ts ("dts", pkt->dts);
2522  print_time("dts_time", pkt->dts, &st->time_base);
2523  print_duration_ts("duration", pkt->duration);
2524  print_duration_time("duration_time", pkt->duration, &st->time_base);
2525  print_val("size", pkt->size, unit_byte_str);
2526  if (pkt->pos != -1) print_fmt ("pos", "%"PRId64, pkt->pos);
2527  else print_str_opt("pos", "N/A");
2528  print_fmt("flags", "%c%c%c", pkt->flags & AV_PKT_FLAG_KEY ? 'K' : '_',
2529  pkt->flags & AV_PKT_FLAG_DISCARD ? 'D' : '_',
2530  pkt->flags & AV_PKT_FLAG_CORRUPT ? 'C' : '_');
2531  if (do_show_data)
2532  writer_print_data(w, "data", pkt->data, pkt->size);
2533  writer_print_data_hash(w, "data_hash", pkt->data, pkt->size);
2534 
2535  if (pkt->side_data_elems) {
2536  size_t size;
2537  const uint8_t *side_metadata;
2538 
2540  if (side_metadata && size && do_show_packet_tags) {
2541  AVDictionary *dict = NULL;
2542  if (av_packet_unpack_dictionary(side_metadata, size, &dict) >= 0)
2544  av_dict_free(&dict);
2545  }
2546 
2550  }
2551 
2553 
2554  av_bprint_finalize(&pbuf, NULL);
2555  fflush(stdout);
2556 }
2557 
2558 static void show_subtitle(WriterContext *w, AVSubtitle *sub, AVStream *stream,
2560 {
2561  AVBPrint pbuf;
2562 
2564 
2566 
2567  print_str ("media_type", "subtitle");
2568  print_ts ("pts", sub->pts);
2569  print_time("pts_time", sub->pts, &AV_TIME_BASE_Q);
2570  print_int ("format", sub->format);
2571  print_int ("start_display_time", sub->start_display_time);
2572  print_int ("end_display_time", sub->end_display_time);
2573  print_int ("num_rects", sub->num_rects);
2574 
2576 
2577  av_bprint_finalize(&pbuf, NULL);
2578  fflush(stdout);
2579 }
2580 
2583 {
2584  FrameData *fd = frame->opaque_ref ? (FrameData*)frame->opaque_ref->data : NULL;
2585  AVBPrint pbuf;
2586  char val_str[128];
2587  const char *s;
2588  int i;
2589 
2591 
2593 
2595  if (s) print_str ("media_type", s);
2596  else print_str_opt("media_type", "unknown");
2597  print_int("stream_index", stream->index);
2598  print_int("key_frame", !!(frame->flags & AV_FRAME_FLAG_KEY));
2599  print_ts ("pts", frame->pts);
2600  print_time("pts_time", frame->pts, &stream->time_base);
2601  print_ts ("pkt_dts", frame->pkt_dts);
2602  print_time("pkt_dts_time", frame->pkt_dts, &stream->time_base);
2603  print_ts ("best_effort_timestamp", frame->best_effort_timestamp);
2604  print_time("best_effort_timestamp_time", frame->best_effort_timestamp, &stream->time_base);
2605 #if LIBAVUTIL_VERSION_MAJOR < 59
2607  print_duration_ts ("pkt_duration", frame->pkt_duration);
2608  print_duration_time("pkt_duration_time", frame->pkt_duration, &stream->time_base);
2609  )
2610 #endif
2611  print_duration_ts ("duration", frame->duration);
2612  print_duration_time("duration_time", frame->duration, &stream->time_base);
2613  if (fd && fd->pkt_pos != -1) print_fmt ("pkt_pos", "%"PRId64, fd->pkt_pos);
2614  else print_str_opt("pkt_pos", "N/A");
2615  if (fd && fd->pkt_size != -1) print_val ("pkt_size", fd->pkt_size, unit_byte_str);
2616  else print_str_opt("pkt_size", "N/A");
2617 
2618  switch (stream->codecpar->codec_type) {
2619  AVRational sar;
2620 
2621  case AVMEDIA_TYPE_VIDEO:
2622  print_int("width", frame->width);
2623  print_int("height", frame->height);
2624  print_int("crop_top", frame->crop_top);
2625  print_int("crop_bottom", frame->crop_bottom);
2626  print_int("crop_left", frame->crop_left);
2627  print_int("crop_right", frame->crop_right);
2628  s = av_get_pix_fmt_name(frame->format);
2629  if (s) print_str ("pix_fmt", s);
2630  else print_str_opt("pix_fmt", "unknown");
2631  sar = av_guess_sample_aspect_ratio(fmt_ctx, stream, frame);
2632  if (sar.num) {
2633  print_q("sample_aspect_ratio", sar, ':');
2634  } else {
2635  print_str_opt("sample_aspect_ratio", "N/A");
2636  }
2637  print_fmt("pict_type", "%c", av_get_picture_type_char(frame->pict_type));
2638 #if LIBAVUTIL_VERSION_MAJOR < 59
2640  print_int("coded_picture_number", frame->coded_picture_number);
2641  print_int("display_picture_number", frame->display_picture_number);
2642  )
2643 #endif
2644  print_int("interlaced_frame", !!(frame->flags & AV_FRAME_FLAG_INTERLACED));
2645  print_int("top_field_first", !!(frame->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST));
2646  print_int("repeat_pict", frame->repeat_pict);
2647 
2648  print_color_range(w, frame->color_range);
2649  print_color_space(w, frame->colorspace);
2650  print_primaries(w, frame->color_primaries);
2651  print_color_trc(w, frame->color_trc);
2652  print_chroma_location(w, frame->chroma_location);
2653  break;
2654 
2655  case AVMEDIA_TYPE_AUDIO:
2656  s = av_get_sample_fmt_name(frame->format);
2657  if (s) print_str ("sample_fmt", s);
2658  else print_str_opt("sample_fmt", "unknown");
2659  print_int("nb_samples", frame->nb_samples);
2660  print_int("channels", frame->ch_layout.nb_channels);
2661  if (frame->ch_layout.order != AV_CHANNEL_ORDER_UNSPEC) {
2662  av_channel_layout_describe(&frame->ch_layout, val_str, sizeof(val_str));
2663  print_str ("channel_layout", val_str);
2664  } else
2665  print_str_opt("channel_layout", "unknown");
2666  break;
2667  }
2668  if (do_show_frame_tags)
2669  show_tags(w, frame->metadata, SECTION_ID_FRAME_TAGS);
2670  if (do_show_log)
2672  if (frame->nb_side_data) {
2674  for (i = 0; i < frame->nb_side_data; i++) {
2675  AVFrameSideData *sd = frame->side_data[i];
2676  const char *name;
2677 
2680  print_str("side_data_type", name ? name : "unknown");
2681  if (sd->type == AV_FRAME_DATA_DISPLAYMATRIX && sd->size >= 9*4) {
2682  double rotation = av_display_rotation_get((int32_t *)sd->data);
2683  if (isnan(rotation))
2684  rotation = 0;
2685  writer_print_integers(w, "displaymatrix", sd->data, 9, " %11d", 3, 4, 1);
2686  print_int("rotation", rotation);
2687  } else if (sd->type == AV_FRAME_DATA_AFD && sd->size > 0) {
2688  print_int("active_format", *sd->data);
2689  } else if (sd->type == AV_FRAME_DATA_GOP_TIMECODE && sd->size >= 8) {
2690  char tcbuf[AV_TIMECODE_STR_SIZE];
2691  av_timecode_make_mpeg_tc_string(tcbuf, *(int64_t *)(sd->data));
2692  print_str("timecode", tcbuf);
2693  } else if (sd->type == AV_FRAME_DATA_S12M_TIMECODE && sd->size == 16) {
2694  uint32_t *tc = (uint32_t*)sd->data;
2695  int m = FFMIN(tc[0],3);
2697  for (int j = 1; j <= m ; j++) {
2698  char tcbuf[AV_TIMECODE_STR_SIZE];
2699  av_timecode_make_smpte_tc_string2(tcbuf, stream->avg_frame_rate, tc[j], 0, 0);
2701  print_str("value", tcbuf);
2703  }
2705  } else if (sd->type == AV_FRAME_DATA_MASTERING_DISPLAY_METADATA) {
2707 
2708  if (metadata->has_primaries) {
2709  print_q("red_x", metadata->display_primaries[0][0], '/');
2710  print_q("red_y", metadata->display_primaries[0][1], '/');
2711  print_q("green_x", metadata->display_primaries[1][0], '/');
2712  print_q("green_y", metadata->display_primaries[1][1], '/');
2713  print_q("blue_x", metadata->display_primaries[2][0], '/');
2714  print_q("blue_y", metadata->display_primaries[2][1], '/');
2715 
2716  print_q("white_point_x", metadata->white_point[0], '/');
2717  print_q("white_point_y", metadata->white_point[1], '/');
2718  }
2719 
2720  if (metadata->has_luminance) {
2721  print_q("min_luminance", metadata->min_luminance, '/');
2722  print_q("max_luminance", metadata->max_luminance, '/');
2723  }
2724  } else if (sd->type == AV_FRAME_DATA_DYNAMIC_HDR_PLUS) {
2725  AVDynamicHDRPlus *metadata = (AVDynamicHDRPlus *)sd->data;
2726  print_dynamic_hdr10_plus(w, metadata);
2727  } else if (sd->type == AV_FRAME_DATA_CONTENT_LIGHT_LEVEL) {
2729  print_int("max_content", metadata->MaxCLL);
2730  print_int("max_average", metadata->MaxFALL);
2731  } else if (sd->type == AV_FRAME_DATA_ICC_PROFILE) {
2733  if (tag)
2734  print_str(tag->key, tag->value);
2735  print_int("size", sd->size);
2736  } else if (sd->type == AV_FRAME_DATA_DOVI_METADATA) {
2737  print_dovi_metadata(w, (const AVDOVIMetadata *)sd->data);
2738  } else if (sd->type == AV_FRAME_DATA_DYNAMIC_HDR_VIVID) {
2739  AVDynamicHDRVivid *metadata = (AVDynamicHDRVivid *)sd->data;
2740  print_dynamic_hdr_vivid(w, metadata);
2741  } else if (sd->type == AV_FRAME_DATA_AMBIENT_VIEWING_ENVIRONMENT) {
2743  w, (const AVAmbientViewingEnvironment *)sd->data);
2744  }
2746  }
2748  }
2749 
2751 
2752  av_bprint_finalize(&pbuf, NULL);
2753  fflush(stdout);
2754 }
2755 
2757  InputFile *ifile,
2758  AVFrame *frame, const AVPacket *pkt,
2759  int *packet_new)
2760 {
2761  AVFormatContext *fmt_ctx = ifile->fmt_ctx;
2764  AVSubtitle sub;
2765  int ret = 0, got_frame = 0;
2766 
2767  clear_log(1);
2768  if (dec_ctx) {
2769  switch (par->codec_type) {
2770  case AVMEDIA_TYPE_VIDEO:
2771  case AVMEDIA_TYPE_AUDIO:
2772  if (*packet_new) {
2774  if (ret == AVERROR(EAGAIN)) {
2775  ret = 0;
2776  } else if (ret >= 0 || ret == AVERROR_EOF) {
2777  ret = 0;
2778  *packet_new = 0;
2779  }
2780  }
2781  if (ret >= 0) {
2783  if (ret >= 0) {
2784  got_frame = 1;
2785  } else if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
2786  ret = 0;
2787  }
2788  }
2789  break;
2790 
2791  case AVMEDIA_TYPE_SUBTITLE:
2792  if (*packet_new)
2793  ret = avcodec_decode_subtitle2(dec_ctx, &sub, &got_frame, pkt);
2794  *packet_new = 0;
2795  break;
2796  default:
2797  *packet_new = 0;
2798  }
2799  } else {
2800  *packet_new = 0;
2801  }
2802 
2803  if (ret < 0)
2804  return ret;
2805  if (got_frame) {
2806  int is_sub = (par->codec_type == AVMEDIA_TYPE_SUBTITLE);
2808  if (do_show_frames)
2809  if (is_sub)
2810  show_subtitle(w, &sub, ifile->streams[pkt->stream_index].st, fmt_ctx);
2811  else
2813  if (is_sub)
2814  avsubtitle_free(&sub);
2815  }
2816  return got_frame || *packet_new;
2817 }
2818 
2819 static void log_read_interval(const ReadInterval *interval, void *log_ctx, int log_level)
2820 {
2821  av_log(log_ctx, log_level, "id:%d", interval->id);
2822 
2823  if (interval->has_start) {
2824  av_log(log_ctx, log_level, " start:%s%s", interval->start_is_offset ? "+" : "",
2825  av_ts2timestr(interval->start, &AV_TIME_BASE_Q));
2826  } else {
2827  av_log(log_ctx, log_level, " start:N/A");
2828  }
2829 
2830  if (interval->has_end) {
2831  av_log(log_ctx, log_level, " end:%s", interval->end_is_offset ? "+" : "");
2832  if (interval->duration_frames)
2833  av_log(log_ctx, log_level, "#%"PRId64, interval->end);
2834  else
2835  av_log(log_ctx, log_level, "%s", av_ts2timestr(interval->end, &AV_TIME_BASE_Q));
2836  } else {
2837  av_log(log_ctx, log_level, " end:N/A");
2838  }
2839 
2840  av_log(log_ctx, log_level, "\n");
2841 }
2842 
2844  const ReadInterval *interval, int64_t *cur_ts)
2845 {
2846  AVFormatContext *fmt_ctx = ifile->fmt_ctx;
2847  AVPacket *pkt = NULL;
2848  AVFrame *frame = NULL;
2849  int ret = 0, i = 0, frame_count = 0;
2850  int64_t start = -INT64_MAX, end = interval->end;
2851  int has_start = 0, has_end = interval->has_end && !interval->end_is_offset;
2852 
2853  av_log(NULL, AV_LOG_VERBOSE, "Processing read interval ");
2855 
2856  if (interval->has_start) {
2857  int64_t target;
2858  if (interval->start_is_offset) {
2859  if (*cur_ts == AV_NOPTS_VALUE) {
2861  "Could not seek to relative position since current "
2862  "timestamp is not defined\n");
2863  ret = AVERROR(EINVAL);
2864  goto end;
2865  }
2866  target = *cur_ts + interval->start;
2867  } else {
2868  target = interval->start;
2869  }
2870 
2871  av_log(NULL, AV_LOG_VERBOSE, "Seeking to read interval start point %s\n",
2872  av_ts2timestr(target, &AV_TIME_BASE_Q));
2873  if ((ret = avformat_seek_file(fmt_ctx, -1, -INT64_MAX, target, INT64_MAX, 0)) < 0) {
2874  av_log(NULL, AV_LOG_ERROR, "Could not seek to position %"PRId64": %s\n",
2875  interval->start, av_err2str(ret));
2876  goto end;
2877  }
2878  }
2879 
2880  frame = av_frame_alloc();
2881  if (!frame) {
2882  ret = AVERROR(ENOMEM);
2883  goto end;
2884  }
2885  pkt = av_packet_alloc();
2886  if (!pkt) {
2887  ret = AVERROR(ENOMEM);
2888  goto end;
2889  }
2890  while (!av_read_frame(fmt_ctx, pkt)) {
2891  if (fmt_ctx->nb_streams > nb_streams) {
2896  }
2899  int64_t pts = pkt->pts != AV_NOPTS_VALUE ? pkt->pts : pkt->dts;
2900 
2901  if (pts != AV_NOPTS_VALUE)
2902  *cur_ts = av_rescale_q(pts, tb, AV_TIME_BASE_Q);
2903 
2904  if (!has_start && *cur_ts != AV_NOPTS_VALUE) {
2905  start = *cur_ts;
2906  has_start = 1;
2907  }
2908 
2909  if (has_start && !has_end && interval->end_is_offset) {
2910  end = start + interval->end;
2911  has_end = 1;
2912  }
2913 
2914  if (interval->end_is_offset && interval->duration_frames) {
2915  if (frame_count >= interval->end)
2916  break;
2917  } else if (has_end && *cur_ts != AV_NOPTS_VALUE && *cur_ts >= end) {
2918  break;
2919  }
2920 
2921  frame_count++;
2922  if (do_read_packets) {
2923  if (do_show_packets)
2924  show_packet(w, ifile, pkt, i++);
2926  }
2927  if (do_read_frames) {
2928  int packet_new = 1;
2929  FrameData *fd;
2930 
2931  pkt->opaque_ref = av_buffer_allocz(sizeof(*fd));
2932  if (!pkt->opaque_ref) {
2933  ret = AVERROR(ENOMEM);
2934  goto end;
2935  }
2936  fd = (FrameData*)pkt->opaque_ref->data;
2937  fd->pkt_pos = pkt->pos;
2938  fd->pkt_size = pkt->size;
2939 
2940  while (process_frame(w, ifile, frame, pkt, &packet_new) > 0);
2941  }
2942  }
2944  }
2946  //Flush remaining frames that are cached in the decoder
2947  for (i = 0; i < ifile->nb_streams; i++) {
2948  pkt->stream_index = i;
2949  if (do_read_frames) {
2950  while (process_frame(w, ifile, frame, pkt, &(int){1}) > 0);
2951  if (ifile->streams[i].dec_ctx)
2953  }
2954  }
2955 
2956 end:
2957  av_frame_free(&frame);
2958  av_packet_free(&pkt);
2959  if (ret < 0) {
2960  av_log(NULL, AV_LOG_ERROR, "Could not read packets in interval ");
2961  log_read_interval(interval, NULL, AV_LOG_ERROR);
2962  }
2963  return ret;
2964 }
2965 
2967 {
2968  AVFormatContext *fmt_ctx = ifile->fmt_ctx;
2969  int i, ret = 0;
2970  int64_t cur_ts = fmt_ctx->start_time;
2971 
2972  if (read_intervals_nb == 0) {
2973  ReadInterval interval = (ReadInterval) { .has_start = 0, .has_end = 0 };
2974  ret = read_interval_packets(w, ifile, &interval, &cur_ts);
2975  } else {
2976  for (i = 0; i < read_intervals_nb; i++) {
2977  ret = read_interval_packets(w, ifile, &read_intervals[i], &cur_ts);
2978  if (ret < 0)
2979  break;
2980  }
2981  }
2982 
2983  return ret;
2984 }
2985 
2986 static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_idx, InputStream *ist, int in_program)
2987 {
2988  AVStream *stream = ist->st;
2989  AVCodecParameters *par;
2991  char val_str[128];
2992  const char *s;
2993  AVRational sar, dar;
2994  AVBPrint pbuf;
2995  const AVCodecDescriptor *cd;
2996  int ret = 0;
2997  const char *profile = NULL;
2998 
3000 
3002 
3003  print_int("index", stream->index);
3004 
3005  par = stream->codecpar;
3006  dec_ctx = ist->dec_ctx;
3007  if (cd = avcodec_descriptor_get(par->codec_id)) {
3008  print_str("codec_name", cd->name);
3009  if (!do_bitexact) {
3010  print_str("codec_long_name",
3011  cd->long_name ? cd->long_name : "unknown");
3012  }
3013  } else {
3014  print_str_opt("codec_name", "unknown");
3015  if (!do_bitexact) {
3016  print_str_opt("codec_long_name", "unknown");
3017  }
3018  }
3019 
3020  if (!do_bitexact && (profile = avcodec_profile_name(par->codec_id, par->profile)))
3021  print_str("profile", profile);
3022  else {
3023  if (par->profile != AV_PROFILE_UNKNOWN) {
3024  char profile_num[12];
3025  snprintf(profile_num, sizeof(profile_num), "%d", par->profile);
3026  print_str("profile", profile_num);
3027  } else
3028  print_str_opt("profile", "unknown");
3029  }
3030 
3032  if (s) print_str ("codec_type", s);
3033  else print_str_opt("codec_type", "unknown");
3034 
3035  /* print AVI/FourCC tag */
3036  print_str("codec_tag_string", av_fourcc2str(par->codec_tag));
3037  print_fmt("codec_tag", "0x%04"PRIx32, par->codec_tag);
3038 
3039  switch (par->codec_type) {
3040  case AVMEDIA_TYPE_VIDEO:
3041  print_int("width", par->width);
3042  print_int("height", par->height);
3043  if (dec_ctx) {
3044  print_int("coded_width", dec_ctx->coded_width);
3045  print_int("coded_height", dec_ctx->coded_height);
3048  }
3049  print_int("has_b_frames", par->video_delay);
3050  sar = av_guess_sample_aspect_ratio(fmt_ctx, stream, NULL);
3051  if (sar.num) {
3052  print_q("sample_aspect_ratio", sar, ':');
3053  av_reduce(&dar.num, &dar.den,
3054  par->width * sar.num,
3055  par->height * sar.den,
3056  1024*1024);
3057  print_q("display_aspect_ratio", dar, ':');
3058  } else {
3059  print_str_opt("sample_aspect_ratio", "N/A");
3060  print_str_opt("display_aspect_ratio", "N/A");
3061  }
3062  s = av_get_pix_fmt_name(par->format);
3063  if (s) print_str ("pix_fmt", s);
3064  else print_str_opt("pix_fmt", "unknown");
3065  print_int("level", par->level);
3066 
3069  print_color_trc(w, par->color_trc);
3072 
3073  if (par->field_order == AV_FIELD_PROGRESSIVE)
3074  print_str("field_order", "progressive");
3075  else if (par->field_order == AV_FIELD_TT)
3076  print_str("field_order", "tt");
3077  else if (par->field_order == AV_FIELD_BB)
3078  print_str("field_order", "bb");
3079  else if (par->field_order == AV_FIELD_TB)
3080  print_str("field_order", "tb");
3081  else if (par->field_order == AV_FIELD_BT)
3082  print_str("field_order", "bt");
3083  else
3084  print_str_opt("field_order", "unknown");
3085 
3086  if (dec_ctx)
3087  print_int("refs", dec_ctx->refs);
3088  break;
3089 
3090  case AVMEDIA_TYPE_AUDIO:
3092  if (s) print_str ("sample_fmt", s);
3093  else print_str_opt("sample_fmt", "unknown");
3094  print_val("sample_rate", par->sample_rate, unit_hertz_str);
3095  print_int("channels", par->ch_layout.nb_channels);
3096 
3097  if (par->ch_layout.order != AV_CHANNEL_ORDER_UNSPEC) {
3098  av_channel_layout_describe(&par->ch_layout, val_str, sizeof(val_str));
3099  print_str ("channel_layout", val_str);
3100  } else {
3101  print_str_opt("channel_layout", "unknown");
3102  }
3103 
3104  print_int("bits_per_sample", av_get_bits_per_sample(par->codec_id));
3105 
3106  print_int("initial_padding", par->initial_padding);
3107  break;
3108 
3109  case AVMEDIA_TYPE_SUBTITLE:
3110  if (par->width)
3111  print_int("width", par->width);
3112  else
3113  print_str_opt("width", "N/A");
3114  if (par->height)
3115  print_int("height", par->height);
3116  else
3117  print_str_opt("height", "N/A");
3118  break;
3119  }
3120 
3121  if (show_private_data) {
3122  if (dec_ctx && dec_ctx->codec->priv_class)
3124  if (fmt_ctx->iformat->priv_class)
3126  }
3127 
3128  if (fmt_ctx->iformat->flags & AVFMT_SHOW_IDS) print_fmt ("id", "0x%x", stream->id);
3129  else print_str_opt("id", "N/A");
3130  print_q("r_frame_rate", stream->r_frame_rate, '/');
3131  print_q("avg_frame_rate", stream->avg_frame_rate, '/');
3132  print_q("time_base", stream->time_base, '/');
3133  print_ts ("start_pts", stream->start_time);
3134  print_time("start_time", stream->start_time, &stream->time_base);
3135  print_ts ("duration_ts", stream->duration);
3136  print_time("duration", stream->duration, &stream->time_base);
3137  if (par->bit_rate > 0) print_val ("bit_rate", par->bit_rate, unit_bit_per_second_str);
3138  else print_str_opt("bit_rate", "N/A");
3139  if (dec_ctx && dec_ctx->rc_max_rate > 0)
3141  else
3142  print_str_opt("max_bit_rate", "N/A");
3143  if (dec_ctx && dec_ctx->bits_per_raw_sample > 0) print_fmt("bits_per_raw_sample", "%d", dec_ctx->bits_per_raw_sample);
3144  else print_str_opt("bits_per_raw_sample", "N/A");
3145  if (stream->nb_frames) print_fmt ("nb_frames", "%"PRId64, stream->nb_frames);
3146  else print_str_opt("nb_frames", "N/A");
3147  if (nb_streams_frames[stream_idx]) print_fmt ("nb_read_frames", "%"PRIu64, nb_streams_frames[stream_idx]);
3148  else print_str_opt("nb_read_frames", "N/A");
3149  if (nb_streams_packets[stream_idx]) print_fmt ("nb_read_packets", "%"PRIu64, nb_streams_packets[stream_idx]);
3150  else print_str_opt("nb_read_packets", "N/A");
3151  if (do_show_data)
3152  writer_print_data(w, "extradata", par->extradata,
3153  par->extradata_size);
3154 
3155  if (par->extradata_size > 0) {
3156  print_int("extradata_size", par->extradata_size);
3157  writer_print_data_hash(w, "extradata_hash", par->extradata,
3158  par->extradata_size);
3159  }
3160 
3161  /* Print disposition information */
3162 #define PRINT_DISPOSITION(flagname, name) do { \
3163  print_int(name, !!(stream->disposition & AV_DISPOSITION_##flagname)); \
3164  } while (0)
3165 
3168  PRINT_DISPOSITION(DEFAULT, "default");
3169  PRINT_DISPOSITION(DUB, "dub");
3170  PRINT_DISPOSITION(ORIGINAL, "original");
3171  PRINT_DISPOSITION(COMMENT, "comment");
3172  PRINT_DISPOSITION(LYRICS, "lyrics");
3173  PRINT_DISPOSITION(KARAOKE, "karaoke");
3174  PRINT_DISPOSITION(FORCED, "forced");
3175  PRINT_DISPOSITION(HEARING_IMPAIRED, "hearing_impaired");
3176  PRINT_DISPOSITION(VISUAL_IMPAIRED, "visual_impaired");
3177  PRINT_DISPOSITION(CLEAN_EFFECTS, "clean_effects");
3178  PRINT_DISPOSITION(ATTACHED_PIC, "attached_pic");
3179  PRINT_DISPOSITION(TIMED_THUMBNAILS, "timed_thumbnails");
3180  PRINT_DISPOSITION(CAPTIONS, "captions");
3181  PRINT_DISPOSITION(DESCRIPTIONS, "descriptions");
3182  PRINT_DISPOSITION(METADATA, "metadata");
3183  PRINT_DISPOSITION(DEPENDENT, "dependent");
3184  PRINT_DISPOSITION(STILL_IMAGE, "still_image");
3186  }
3187 
3188  if (do_show_stream_tags)
3190 
3191  if (stream->nb_side_data) {
3192  print_pkt_side_data(w, stream->codecpar, stream->side_data, stream->nb_side_data,
3195  }
3196 
3198  av_bprint_finalize(&pbuf, NULL);
3199  fflush(stdout);
3200 
3201  return ret;
3202 }
3203 
3205 {
3206  AVFormatContext *fmt_ctx = ifile->fmt_ctx;
3207  int i, ret = 0;
3208 
3210  for (i = 0; i < ifile->nb_streams; i++)
3211  if (selected_streams[i]) {
3212  ret = show_stream(w, fmt_ctx, i, &ifile->streams[i], 0);
3213  if (ret < 0)
3214  break;
3215  }
3217 
3218  return ret;
3219 }
3220 
3222 {
3223  AVFormatContext *fmt_ctx = ifile->fmt_ctx;
3224  int i, ret = 0;
3225 
3227  print_int("program_id", program->id);
3228  print_int("program_num", program->program_num);
3229  print_int("nb_streams", program->nb_stream_indexes);
3230  print_int("pmt_pid", program->pmt_pid);
3231  print_int("pcr_pid", program->pcr_pid);
3234  if (ret < 0)
3235  goto end;
3236 
3238  for (i = 0; i < program->nb_stream_indexes; i++) {
3239  if (selected_streams[program->stream_index[i]]) {
3240  ret = show_stream(w, fmt_ctx, program->stream_index[i], &ifile->streams[program->stream_index[i]], 1);
3241  if (ret < 0)
3242  break;
3243  }
3244  }
3246 
3247 end:
3249  return ret;
3250 }
3251 
3253 {
3254  AVFormatContext *fmt_ctx = ifile->fmt_ctx;
3255  int i, ret = 0;
3256 
3258  for (i = 0; i < fmt_ctx->nb_programs; i++) {
3260  if (!program)
3261  continue;
3262  ret = show_program(w, ifile, program);
3263  if (ret < 0)
3264  break;
3265  }
3267  return ret;
3268 }
3269 
3271 {
3272  AVFormatContext *fmt_ctx = ifile->fmt_ctx;
3273  int i, ret = 0;
3274 
3276  for (i = 0; i < fmt_ctx->nb_chapters; i++) {
3277  AVChapter *chapter = fmt_ctx->chapters[i];
3278 
3280  print_int("id", chapter->id);
3281  print_q ("time_base", chapter->time_base, '/');
3282  print_int("start", chapter->start);
3283  print_time("start_time", chapter->start, &chapter->time_base);
3284  print_int("end", chapter->end);
3285  print_time("end_time", chapter->end, &chapter->time_base);
3289  }
3291 
3292  return ret;
3293 }
3294 
3295 static int show_format(WriterContext *w, InputFile *ifile)
3296 {
3297  AVFormatContext *fmt_ctx = ifile->fmt_ctx;
3298  char val_str[128];
3299  int64_t size = fmt_ctx->pb ? avio_size(fmt_ctx->pb) : -1;
3300  int ret = 0;
3301 
3303  print_str_validate("filename", fmt_ctx->url);
3304  print_int("nb_streams", fmt_ctx->nb_streams);
3305  print_int("nb_programs", fmt_ctx->nb_programs);
3306  print_str("format_name", fmt_ctx->iformat->name);
3307  if (!do_bitexact) {
3308  if (fmt_ctx->iformat->long_name) print_str ("format_long_name", fmt_ctx->iformat->long_name);
3309  else print_str_opt("format_long_name", "unknown");
3310  }
3311  print_time("start_time", fmt_ctx->start_time, &AV_TIME_BASE_Q);
3312  print_time("duration", fmt_ctx->duration, &AV_TIME_BASE_Q);
3313  if (size >= 0) print_val ("size", size, unit_byte_str);
3314  else print_str_opt("size", "N/A");
3316  else print_str_opt("bit_rate", "N/A");
3317  print_int("probe_score", fmt_ctx->probe_score);
3318  if (do_show_format_tags)
3320 
3322  fflush(stdout);
3323  return ret;
3324 }
3325 
3326 static void show_error(WriterContext *w, int err)
3327 {
3329  print_int("code", err);
3330  print_str("string", av_err2str(err));
3332 }
3333 
3334 static int open_input_file(InputFile *ifile, const char *filename,
3335  const char *print_filename)
3336 {
3337  int err, i;
3339  const AVDictionaryEntry *t = NULL;
3340  int scan_all_pmts_set = 0;
3341 
3343  if (!fmt_ctx)
3344  return AVERROR(ENOMEM);
3345 
3346  if (!av_dict_get(format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE)) {
3347  av_dict_set(&format_opts, "scan_all_pmts", "1", AV_DICT_DONT_OVERWRITE);
3348  scan_all_pmts_set = 1;
3349  }
3350  if ((err = avformat_open_input(&fmt_ctx, filename,
3351  iformat, &format_opts)) < 0) {
3352  print_error(filename, err);
3353  return err;
3354  }
3355  if (print_filename) {
3356  av_freep(&fmt_ctx->url);
3357  fmt_ctx->url = av_strdup(print_filename);
3358  }
3359  ifile->fmt_ctx = fmt_ctx;
3360  if (scan_all_pmts_set)
3361  av_dict_set(&format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE);
3362  while ((t = av_dict_iterate(format_opts, t)))
3363  av_log(NULL, AV_LOG_WARNING, "Option %s skipped - not known to demuxer.\n", t->key);
3364 
3365  if (find_stream_info) {
3366  AVDictionary **opts;
3367  int orig_nb_streams = fmt_ctx->nb_streams;
3368 
3370  if (err < 0)
3371  return err;
3372 
3374 
3375  for (i = 0; i < orig_nb_streams; i++)
3376  av_dict_free(&opts[i]);
3377  av_freep(&opts);
3378 
3379  if (err < 0) {
3380  print_error(filename, err);
3381  return err;
3382  }
3383  }
3384 
3385  av_dump_format(fmt_ctx, 0, filename, 0);
3386 
3387  ifile->streams = av_calloc(fmt_ctx->nb_streams, sizeof(*ifile->streams));
3388  if (!ifile->streams)
3389  exit(1);
3390  ifile->nb_streams = fmt_ctx->nb_streams;
3391 
3392  /* bind a decoder to each input stream */
3393  for (i = 0; i < fmt_ctx->nb_streams; i++) {
3394  InputStream *ist = &ifile->streams[i];
3395  AVStream *stream = fmt_ctx->streams[i];
3396  const AVCodec *codec;
3397 
3398  ist->st = stream;
3399 
3400  if (stream->codecpar->codec_id == AV_CODEC_ID_PROBE) {
3402  "Failed to probe codec for input stream %d\n",
3403  stream->index);
3404  continue;
3405  }
3406 
3407  codec = avcodec_find_decoder(stream->codecpar->codec_id);
3408  if (!codec) {
3410  "Unsupported codec with id %d for input stream %d\n",
3411  stream->codecpar->codec_id, stream->index);
3412  continue;
3413  }
3414  {
3415  AVDictionary *opts;
3416 
3418  fmt_ctx, stream, codec, &opts);
3419  if (err < 0)
3420  exit(1);
3421 
3422  ist->dec_ctx = avcodec_alloc_context3(codec);
3423  if (!ist->dec_ctx)
3424  exit(1);
3425 
3426  err = avcodec_parameters_to_context(ist->dec_ctx, stream->codecpar);
3427  if (err < 0)
3428  exit(1);
3429 
3430  if (do_show_log) {
3431  // For loging it is needed to disable at least frame threads as otherwise
3432  // the log information would need to be reordered and matches up to contexts and frames
3433  // That is in fact possible but not trivial
3434  av_dict_set(&codec_opts, "threads", "1", 0);
3435  }
3436 
3437  av_dict_set(&opts, "flags", "+copy_opaque", AV_DICT_MULTIKEY);
3438 
3439  ist->dec_ctx->pkt_timebase = stream->time_base;
3440 
3441  if (avcodec_open2(ist->dec_ctx, codec, &opts) < 0) {
3442  av_log(NULL, AV_LOG_WARNING, "Could not open codec for input stream %d\n",
3443  stream->index);
3444  exit(1);
3445  }
3446 
3447  if ((t = av_dict_get(opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
3448  av_log(NULL, AV_LOG_ERROR, "Option %s for input stream %d not found\n",
3449  t->key, stream->index);
3450  return AVERROR_OPTION_NOT_FOUND;
3451  }
3452  }
3453  }
3454 
3455  ifile->fmt_ctx = fmt_ctx;
3456  return 0;
3457 }
3458 
3459 static void close_input_file(InputFile *ifile)
3460 {
3461  int i;
3462 
3463  /* close decoder for each stream */
3464  for (i = 0; i < ifile->nb_streams; i++)
3466 
3467  av_freep(&ifile->streams);
3468  ifile->nb_streams = 0;
3469 
3470  avformat_close_input(&ifile->fmt_ctx);
3471 }
3472 
3473 static int probe_file(WriterContext *wctx, const char *filename,
3474  const char *print_filename)
3475 {
3476  InputFile ifile = { 0 };
3477  int ret, i;
3478  int section_id;
3479 
3482 
3483  ret = open_input_file(&ifile, filename, print_filename);
3484  if (ret < 0)
3485  goto end;
3486 
3487 #define CHECK_END if (ret < 0) goto end
3488 
3489  nb_streams = ifile.fmt_ctx->nb_streams;
3493 
3494  for (i = 0; i < ifile.fmt_ctx->nb_streams; i++) {
3495  if (stream_specifier) {
3497  ifile.fmt_ctx->streams[i],
3499  CHECK_END;
3500  else
3501  selected_streams[i] = ret;
3502  ret = 0;
3503  } else {
3504  selected_streams[i] = 1;
3505  }
3506  if (!selected_streams[i])
3507  ifile.fmt_ctx->streams[i]->discard = AVDISCARD_ALL;
3508  }
3509 
3513  section_id = SECTION_ID_PACKETS_AND_FRAMES;
3514  else if (do_show_packets && !do_show_frames)
3515  section_id = SECTION_ID_PACKETS;
3516  else // (!do_show_packets && do_show_frames)
3517  section_id = SECTION_ID_FRAMES;
3519  writer_print_section_header(wctx, section_id);
3520  ret = read_packets(wctx, &ifile);
3523  CHECK_END;
3524  }
3525 
3526  if (do_show_programs) {
3527  ret = show_programs(wctx, &ifile);
3528  CHECK_END;
3529  }
3530 
3531  if (do_show_streams) {
3532  ret = show_streams(wctx, &ifile);
3533  CHECK_END;
3534  }
3535  if (do_show_chapters) {
3536  ret = show_chapters(wctx, &ifile);
3537  CHECK_END;
3538  }
3539  if (do_show_format) {
3540  ret = show_format(wctx, &ifile);
3541  CHECK_END;
3542  }
3543 
3544 end:
3545  if (ifile.fmt_ctx)
3546  close_input_file(&ifile);
3550 
3551  return ret;
3552 }
3553 
3554 static void show_usage(void)
3555 {
3556  av_log(NULL, AV_LOG_INFO, "Simple multimedia streams analyzer\n");
3557  av_log(NULL, AV_LOG_INFO, "usage: %s [OPTIONS] INPUT_FILE\n", program_name);
3558  av_log(NULL, AV_LOG_INFO, "\n");
3559 }
3560 
3562 {
3563  AVBPrint pbuf;
3565 
3567  print_str("version", FFMPEG_VERSION);
3568  print_fmt("copyright", "Copyright (c) %d-%d the FFmpeg developers",
3569  program_birth_year, CONFIG_THIS_YEAR);
3570  print_str("compiler_ident", CC_IDENT);
3571  print_str("configuration", FFMPEG_CONFIGURATION);
3573 
3574  av_bprint_finalize(&pbuf, NULL);
3575 }
3576 
3577 #define SHOW_LIB_VERSION(libname, LIBNAME) \
3578  do { \
3579  if (CONFIG_##LIBNAME) { \
3580  unsigned int version = libname##_version(); \
3581  writer_print_section_header(w, SECTION_ID_LIBRARY_VERSION); \
3582  print_str("name", "lib" #libname); \
3583  print_int("major", LIB##LIBNAME##_VERSION_MAJOR); \
3584  print_int("minor", LIB##LIBNAME##_VERSION_MINOR); \
3585  print_int("micro", LIB##LIBNAME##_VERSION_MICRO); \
3586  print_int("version", version); \
3587  print_str("ident", LIB##LIBNAME##_IDENT); \
3588  writer_print_section_footer(w); \
3589  } \
3590  } while (0)
3591 
3593 {
3595  SHOW_LIB_VERSION(avutil, AVUTIL);
3596  SHOW_LIB_VERSION(avcodec, AVCODEC);
3597  SHOW_LIB_VERSION(avformat, AVFORMAT);
3598  SHOW_LIB_VERSION(avdevice, AVDEVICE);
3599  SHOW_LIB_VERSION(avfilter, AVFILTER);
3600  SHOW_LIB_VERSION(swscale, SWSCALE);
3601  SHOW_LIB_VERSION(swresample, SWRESAMPLE);
3602  SHOW_LIB_VERSION(postproc, POSTPROC);
3604 }
3605 
3606 #define PRINT_PIX_FMT_FLAG(flagname, name) \
3607  do { \
3608  print_int(name, !!(pixdesc->flags & AV_PIX_FMT_FLAG_##flagname)); \
3609  } while (0)
3610 
3612 {
3613  const AVPixFmtDescriptor *pixdesc = NULL;
3614  int i, n;
3615 
3617  while (pixdesc = av_pix_fmt_desc_next(pixdesc)) {
3619  print_str("name", pixdesc->name);
3620  print_int("nb_components", pixdesc->nb_components);
3621  if ((pixdesc->nb_components >= 3) && !(pixdesc->flags & AV_PIX_FMT_FLAG_RGB)) {
3622  print_int ("log2_chroma_w", pixdesc->log2_chroma_w);
3623  print_int ("log2_chroma_h", pixdesc->log2_chroma_h);
3624  } else {
3625  print_str_opt("log2_chroma_w", "N/A");
3626  print_str_opt("log2_chroma_h", "N/A");
3627  }
3628  n = av_get_bits_per_pixel(pixdesc);
3629  if (n) print_int ("bits_per_pixel", n);
3630  else print_str_opt("bits_per_pixel", "N/A");
3633  PRINT_PIX_FMT_FLAG(BE, "big_endian");
3634  PRINT_PIX_FMT_FLAG(PAL, "palette");
3635  PRINT_PIX_FMT_FLAG(BITSTREAM, "bitstream");
3636  PRINT_PIX_FMT_FLAG(HWACCEL, "hwaccel");
3637  PRINT_PIX_FMT_FLAG(PLANAR, "planar");
3638  PRINT_PIX_FMT_FLAG(RGB, "rgb");
3639  PRINT_PIX_FMT_FLAG(ALPHA, "alpha");
3641  }
3642  if (do_show_pixel_format_components && (pixdesc->nb_components > 0)) {
3644  for (i = 0; i < pixdesc->nb_components; i++) {
3646  print_int("index", i + 1);
3647  print_int("bit_depth", pixdesc->comp[i].depth);
3649  }
3651  }
3653  }
3655 }
3656 
3657 static int opt_show_optional_fields(void *optctx, const char *opt, const char *arg)
3658 {
3662 
3664  double num;
3665  int ret = parse_number("show_optional_fields", arg, OPT_INT,
3667  if (ret < 0)
3668  return ret;
3669  show_optional_fields = num;
3670  }
3671  return 0;
3672 }
3673 
3674 static int opt_format(void *optctx, const char *opt, const char *arg)
3675 {
3677  if (!iformat) {
3678  av_log(NULL, AV_LOG_ERROR, "Unknown input format: %s\n", arg);
3679  return AVERROR(EINVAL);
3680  }
3681  return 0;
3682 }
3683 
3684 static inline void mark_section_show_entries(SectionID section_id,
3685  int show_all_entries, AVDictionary *entries)
3686 {
3687  struct section *section = &sections[section_id];
3688 
3690  if (show_all_entries) {
3691  for (const SectionID *id = section->children_ids; *id != -1; id++)
3693  } else {
3694  av_dict_copy(&section->entries_to_show, entries, 0);
3695  }
3696 }
3697 
3698 static int match_section(const char *section_name,
3699  int show_all_entries, AVDictionary *entries)
3700 {
3701  int i, ret = 0;
3702 
3703  for (i = 0; i < FF_ARRAY_ELEMS(sections); i++) {
3704  const struct section *section = &sections[i];
3705  if (!strcmp(section_name, section->name) ||
3706  (section->unique_name && !strcmp(section_name, section->unique_name))) {
3708  "'%s' matches section with unique name '%s'\n", section_name,
3710  ret++;
3712  }
3713  }
3714  return ret;
3715 }
3716 
3717 static int opt_show_entries(void *optctx, const char *opt, const char *arg)
3718 {
3719  const char *p = arg;
3720  int ret = 0;
3721 
3722  while (*p) {
3723  AVDictionary *entries = NULL;
3724  char *section_name = av_get_token(&p, "=:");
3725  int show_all_entries = 0;
3726 
3727  if (!section_name) {
3729  "Missing section name for option '%s'\n", opt);
3730  return AVERROR(EINVAL);
3731  }
3732 
3733  if (*p == '=') {
3734  p++;
3735  while (*p && *p != ':') {
3736  char *entry = av_get_token(&p, ",:");
3737  if (!entry)
3738  break;
3740  "Adding '%s' to the entries to show in section '%s'\n",
3741  entry, section_name);
3742  av_dict_set(&entries, entry, "", AV_DICT_DONT_STRDUP_KEY);
3743  if (*p == ',')
3744  p++;
3745  }
3746  } else {
3747  show_all_entries = 1;
3748  }
3749 
3750  ret = match_section(section_name, show_all_entries, entries);
3751  if (ret == 0) {
3752  av_log(NULL, AV_LOG_ERROR, "No match for section '%s'\n", section_name);
3753  ret = AVERROR(EINVAL);
3754  }
3755  av_dict_free(&entries);
3756  av_free(section_name);
3757 
3758  if (ret <= 0)
3759  break;
3760  if (*p)
3761  p++;
3762  }
3763 
3764  return ret;
3765 }
3766 
3767 static int opt_input_file(void *optctx, const char *arg)
3768 {
3769  if (input_filename) {
3771  "Argument '%s' provided as input filename, but '%s' was already specified.\n",
3772  arg, input_filename);
3773  return AVERROR(EINVAL);
3774  }
3775  if (!strcmp(arg, "-"))
3776  arg = "fd:";
3777  input_filename = arg;
3778 
3779  return 0;
3780 }
3781 
3782 static int opt_input_file_i(void *optctx, const char *opt, const char *arg)
3783 {
3784  opt_input_file(optctx, arg);
3785  return 0;
3786 }
3787 
3788 static int opt_output_file_o(void *optctx, const char *opt, const char *arg)
3789 {
3790  if (output_filename) {
3792  "Argument '%s' provided as output filename, but '%s' was already specified.\n",
3793  arg, output_filename);
3794  return AVERROR(EINVAL);
3795  }
3796  if (!strcmp(arg, "-"))
3797  arg = "fd:";
3798  output_filename = arg;
3799 
3800  return 0;
3801 }
3802 
3803 static int opt_print_filename(void *optctx, const char *opt, const char *arg)
3804 {
3806  return 0;
3807 }
3808 
3809 void show_help_default(const char *opt, const char *arg)
3810 {
3812  show_usage();
3813  show_help_options(options, "Main options:", 0, 0, 0);
3814  printf("\n");
3815 
3818 }
3819 
3820 /**
3821  * Parse interval specification, according to the format:
3822  * INTERVAL ::= [START|+START_OFFSET][%[END|+END_OFFSET]]
3823  * INTERVALS ::= INTERVAL[,INTERVALS]
3824 */
3825 static int parse_read_interval(const char *interval_spec,
3826  ReadInterval *interval)
3827 {
3828  int ret = 0;
3829  char *next, *p, *spec = av_strdup(interval_spec);
3830  if (!spec)
3831  return AVERROR(ENOMEM);
3832 
3833  if (!*spec) {
3834  av_log(NULL, AV_LOG_ERROR, "Invalid empty interval specification\n");
3835  ret = AVERROR(EINVAL);
3836  goto end;
3837  }
3838 
3839  p = spec;
3840  next = strchr(spec, '%');
3841  if (next)
3842  *next++ = 0;
3843 
3844  /* parse first part */
3845  if (*p) {
3846  interval->has_start = 1;
3847 
3848  if (*p == '+') {
3849  interval->start_is_offset = 1;
3850  p++;
3851  } else {
3852  interval->start_is_offset = 0;
3853  }
3854 
3855  ret = av_parse_time(&interval->start, p, 1);
3856  if (ret < 0) {
3857  av_log(NULL, AV_LOG_ERROR, "Invalid interval start specification '%s'\n", p);
3858  goto end;
3859  }
3860  } else {
3861  interval->has_start = 0;
3862  }
3863 
3864  /* parse second part */
3865  p = next;
3866  if (p && *p) {
3867  int64_t us;
3868  interval->has_end = 1;
3869 
3870  if (*p == '+') {
3871  interval->end_is_offset = 1;
3872  p++;
3873  } else {
3874  interval->end_is_offset = 0;
3875  }
3876 
3877  if (interval->end_is_offset && *p == '#') {
3878  long long int lli;
3879  char *tail;
3880  interval->duration_frames = 1;
3881  p++;
3882  lli = strtoll(p, &tail, 10);
3883  if (*tail || lli < 0) {
3885  "Invalid or negative value '%s' for duration number of frames\n", p);
3886  goto end;
3887  }
3888  interval->end = lli;
3889  } else {
3890  interval->duration_frames = 0;
3891  ret = av_parse_time(&us, p, 1);
3892  if (ret < 0) {
3893  av_log(NULL, AV_LOG_ERROR, "Invalid interval end/duration specification '%s'\n", p);
3894  goto end;
3895  }
3896  interval->end = us;
3897  }
3898  } else {
3899  interval->has_end = 0;
3900  }
3901 
3902 end:
3903  av_free(spec);
3904  return ret;
3905 }
3906 
3907 static int parse_read_intervals(const char *intervals_spec)
3908 {
3909  int ret, n, i;
3910  char *p, *spec = av_strdup(intervals_spec);
3911  if (!spec)
3912  return AVERROR(ENOMEM);
3913 
3914  /* preparse specification, get number of intervals */
3915  for (n = 0, p = spec; *p; p++)
3916  if (*p == ',')
3917  n++;
3918  n++;
3919 
3921  if (!read_intervals) {
3922  ret = AVERROR(ENOMEM);
3923  goto end;
3924  }
3925  read_intervals_nb = n;
3926 
3927  /* parse intervals */
3928  p = spec;
3929  for (i = 0; p; i++) {
3930  char *next;
3931 
3933  next = strchr(p, ',');
3934  if (next)
3935  *next++ = 0;
3936 
3937  read_intervals[i].id = i;
3939  if (ret < 0) {
3940  av_log(NULL, AV_LOG_ERROR, "Error parsing read interval #%d '%s'\n",
3941  i, p);
3942  goto end;
3943  }
3944  av_log(NULL, AV_LOG_VERBOSE, "Parsed log interval ");
3946  p = next;
3947  }
3949 
3950 end:
3951  av_free(spec);
3952  return ret;
3953 }
3954 
3955 static int opt_read_intervals(void *optctx, const char *opt, const char *arg)
3956 {
3957  return parse_read_intervals(arg);
3958 }
3959 
3960 static int opt_pretty(void *optctx, const char *opt, const char *arg)
3961 {
3962  show_value_unit = 1;
3963  use_value_prefix = 1;
3966  return 0;
3967 }
3968 
3969 static void print_section(SectionID id, int level)
3970 {
3971  const SectionID *pid;
3972  const struct section *section = &sections[id];
3973  printf("%c%c%c",
3974  section->flags & SECTION_FLAG_IS_WRAPPER ? 'W' : '.',
3975  section->flags & SECTION_FLAG_IS_ARRAY ? 'A' : '.',
3977  printf("%*c %s", level * 4, ' ', section->name);
3978  if (section->unique_name)
3979  printf("/%s", section->unique_name);
3980  printf("\n");
3981 
3982  for (pid = section->children_ids; *pid != -1; pid++)
3983  print_section(*pid, level+1);
3984 }
3985 
3986 static int opt_sections(void *optctx, const char *opt, const char *arg)
3987 {
3988  printf("Sections:\n"
3989  "W.. = Section is a wrapper (contains other sections, no local entries)\n"
3990  ".A. = Section contains an array of elements of the same type\n"
3991  "..V = Section may contain a variable number of fields with variable keys\n"
3992  "FLAGS NAME/UNIQUE_NAME\n"
3993  "---\n");
3995  return 0;
3996 }
3997 
3998 static int opt_show_versions(void *optctx, const char *opt, const char *arg)
3999 {
4002  return 0;
4003 }
4004 
4005 #define DEFINE_OPT_SHOW_SECTION(section, target_section_id) \
4006  static int opt_show_##section(void *optctx, const char *opt, const char *arg) \
4007  { \
4008  mark_section_show_entries(SECTION_ID_##target_section_id, 1, NULL); \
4009  return 0; \
4010  }
4011 
4012 DEFINE_OPT_SHOW_SECTION(chapters, CHAPTERS)
4016 DEFINE_OPT_SHOW_SECTION(library_versions, LIBRARY_VERSIONS)
4017 DEFINE_OPT_SHOW_SECTION(packets, PACKETS)
4018 DEFINE_OPT_SHOW_SECTION(pixel_formats, PIXEL_FORMATS)
4019 DEFINE_OPT_SHOW_SECTION(program_version, PROGRAM_VERSION)
4020 DEFINE_OPT_SHOW_SECTION(streams, STREAMS)
4021 DEFINE_OPT_SHOW_SECTION(programs, PROGRAMS)
4022 
4023 static const OptionDef real_options[] = {
4025  { "f", HAS_ARG, {.func_arg = opt_format}, "force format", "format" },
4026  { "unit", OPT_BOOL, {&show_value_unit}, "show unit of the displayed values" },
4027  { "prefix", OPT_BOOL, {&use_value_prefix}, "use SI prefixes for the displayed values" },
4028  { "byte_binary_prefix", OPT_BOOL, {&use_byte_value_binary_prefix},
4029  "use binary prefixes for byte units" },
4030  { "sexagesimal", OPT_BOOL, {&use_value_sexagesimal_format},
4031  "use sexagesimal format HOURS:MM:SS.MICROSECONDS for time units" },
4032  { "pretty", 0, {.func_arg = opt_pretty},
4033  "prettify the format of displayed values, make it more human readable" },
4034  { "print_format", OPT_STRING | HAS_ARG, { &print_format },
4035  "set the output printing format (available formats are: default, compact, csv, flat, ini, json, xml)", "format" },
4036  { "of", OPT_STRING | HAS_ARG, { &print_format }, "alias for -print_format", "format" },
4037  { "select_streams", OPT_STRING | HAS_ARG, { &stream_specifier }, "select the spe