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