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"
43 #include "libavutil/hash.h"
45 #include "libavutil/iamf.h"
48 #include "libavutil/dovi_meta.h"
49 #include "libavutil/mem.h"
50 #include "libavutil/opt.h"
51 #include "libavutil/pixdesc.h"
52 #include "libavutil/spherical.h"
53 #include "libavutil/stereo3d.h"
54 #include "libavutil/dict.h"
55 #include "libavutil/intreadwrite.h"
56 #include "libavutil/libm.h"
57 #include "libavutil/parseutils.h"
58 #include "libavutil/timecode.h"
59 #include "libavutil/timestamp.h"
60 #include "libavdevice/avdevice.h"
61 #include "libavdevice/version.h"
62 #include "libswscale/swscale.h"
63 #include "libswscale/version.h"
65 #include "libswresample/version.h"
67 #include "libpostproc/version.h"
68 #include "libavfilter/version.h"
69 #include "cmdutils.h"
70 #include "opt_common.h"
71 
72 #include "libavutil/thread.h"
73 
74 #if !HAVE_THREADS
75 # ifdef pthread_mutex_lock
76 # undef pthread_mutex_lock
77 # endif
78 # define pthread_mutex_lock(a) do{}while(0)
79 # ifdef pthread_mutex_unlock
80 # undef pthread_mutex_unlock
81 # endif
82 # define pthread_mutex_unlock(a) do{}while(0)
83 #endif
84 
85 // attached as opaque_ref to packets/frames
86 typedef struct FrameData {
88  int pkt_size;
89 } FrameData;
90 
91 typedef struct InputStream {
92  AVStream *st;
93 
95 } InputStream;
96 
97 typedef struct InputFile {
99 
101  int nb_streams;
102 } InputFile;
103 
104 const char program_name[] = "ffprobe";
105 const int program_birth_year = 2007;
106 
107 static int do_bitexact = 0;
108 static int do_count_frames = 0;
109 static int do_count_packets = 0;
110 static int do_read_frames = 0;
111 static int do_read_packets = 0;
112 static int do_show_chapters = 0;
113 static int do_show_error = 0;
114 static int do_show_format = 0;
115 static int do_show_frames = 0;
116 static int do_show_packets = 0;
117 static int do_show_programs = 0;
118 static int do_show_stream_groups = 0;
120 static int do_show_streams = 0;
123 static int do_show_data = 0;
124 static int do_show_program_version = 0;
126 static int do_show_pixel_formats = 0;
129 static int do_show_log = 0;
130 
131 static int do_show_chapter_tags = 0;
132 static int do_show_format_tags = 0;
133 static int do_show_frame_tags = 0;
134 static int do_show_program_tags = 0;
136 static int do_show_stream_tags = 0;
137 static int do_show_packet_tags = 0;
138 
139 static int show_value_unit = 0;
140 static int use_value_prefix = 0;
143 static int show_private_data = 1;
144 
145 #define SHOW_OPTIONAL_FIELDS_AUTO -1
146 #define SHOW_OPTIONAL_FIELDS_NEVER 0
147 #define SHOW_OPTIONAL_FIELDS_ALWAYS 1
149 
150 static char *output_format;
151 static char *stream_specifier;
152 static char *show_data_hash;
153 
154 typedef struct ReadInterval {
155  int id; ///< identifier
156  int64_t start, end; ///< start, end in second/AV_TIME_BASE units
160 } ReadInterval;
161 
163 static int read_intervals_nb = 0;
164 
165 static int find_stream_info = 1;
166 
167 /* section structure definition */
168 
169 #define SECTION_MAX_NB_CHILDREN 11
170 
171 typedef enum {
239 } SectionID;
240 
241 struct section {
242  int id; ///< unique id identifying a section
243  const char *name;
244 
245 #define SECTION_FLAG_IS_WRAPPER 1 ///< the section only contains other sections, but has no data at its own level
246 #define SECTION_FLAG_IS_ARRAY 2 ///< the section contains an array of elements of the same type
247 #define SECTION_FLAG_HAS_VARIABLE_FIELDS 4 ///< the section may contain a variable number of fields with variable keys.
248  /// For these sections the element_name field is mandatory.
249 #define SECTION_FLAG_HAS_TYPE 8 ///< the section contains a type to distinguish multiple nested elements
250 
251  int flags;
252  const SectionID children_ids[SECTION_MAX_NB_CHILDREN+1]; ///< list of children section IDS, terminated by -1
253  const char *element_name; ///< name of the contained element, if provided
254  const char *unique_name; ///< unique section name, in case the name is ambiguous
256  const char *(* get_type)(const void *data); ///< function returning a type if defined, must be defined when SECTION_FLAG_HAS_TYPE is defined
258 };
259 
260 static const char *get_packet_side_data_type(const void *data)
261 {
262  const AVPacketSideData *sd = (const AVPacketSideData *)data;
263  return av_x_if_null(av_packet_side_data_name(sd->type), "unknown");
264 }
265 
266 static const char *get_frame_side_data_type(const void *data)
267 {
268  const AVFrameSideData *sd = (const AVFrameSideData *)data;
269  return av_x_if_null(av_frame_side_data_name(sd->type), "unknown");
270 }
271 
272 static const char *get_raw_string_type(const void *data)
273 {
274  return data;
275 }
276 
277 static const char *get_stream_group_type(const void *data)
278 {
279  const AVStreamGroup *stg = (const AVStreamGroup *)data;
280  return av_x_if_null(avformat_stream_group_name(stg->type), "unknown");
281 }
282 
283 static struct section sections[] = {
285  [SECTION_ID_CHAPTER] = { SECTION_ID_CHAPTER, "chapter", 0, { SECTION_ID_CHAPTER_TAGS, -1 } },
286  [SECTION_ID_CHAPTER_TAGS] = { SECTION_ID_CHAPTER_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "chapter_tags" },
287  [SECTION_ID_ERROR] = { SECTION_ID_ERROR, "error", 0, { -1 } },
288  [SECTION_ID_FORMAT] = { SECTION_ID_FORMAT, "format", 0, { SECTION_ID_FORMAT_TAGS, -1 } },
289  [SECTION_ID_FORMAT_TAGS] = { SECTION_ID_FORMAT_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "format_tags" },
292  [SECTION_ID_FRAME_TAGS] = { SECTION_ID_FRAME_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "frame_tags" },
293  [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" },
297  [SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST] = { SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST, "components", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_SIDE_DATA_COMPONENT, -1 }, .element_name = "component", .unique_name = "frame_side_data_components" },
298  [SECTION_ID_FRAME_SIDE_DATA_COMPONENT] = { SECTION_ID_FRAME_SIDE_DATA_COMPONENT, "component", SECTION_FLAG_HAS_VARIABLE_FIELDS|SECTION_FLAG_HAS_TYPE, { SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST, -1 }, .unique_name = "frame_side_data_component", .element_name = "component_entry", .get_type = get_raw_string_type },
299  [SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST] = { SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST, "pieces", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_SIDE_DATA_PIECE, -1 }, .element_name = "piece", .unique_name = "frame_side_data_pieces" },
300  [SECTION_ID_FRAME_SIDE_DATA_PIECE] = { SECTION_ID_FRAME_SIDE_DATA_PIECE, "piece", SECTION_FLAG_HAS_VARIABLE_FIELDS|SECTION_FLAG_HAS_TYPE, { -1 }, .element_name = "piece_entry", .unique_name = "frame_side_data_piece", .get_type = get_raw_string_type },
302  [SECTION_ID_FRAME_LOG] = { SECTION_ID_FRAME_LOG, "log", 0, { -1 }, },
304  [SECTION_ID_LIBRARY_VERSION] = { SECTION_ID_LIBRARY_VERSION, "library_version", 0, { -1 } },
308  [SECTION_ID_PACKET_TAGS] = { SECTION_ID_PACKET_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "packet_tags" },
309  [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" },
310  [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 },
313  [SECTION_ID_PIXEL_FORMAT_FLAGS] = { SECTION_ID_PIXEL_FORMAT_FLAGS, "flags", 0, { -1 }, .unique_name = "pixel_format_flags" },
314  [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" },
316  [SECTION_ID_PROGRAM_STREAM_DISPOSITION] = { SECTION_ID_PROGRAM_STREAM_DISPOSITION, "disposition", 0, { -1 }, .unique_name = "program_stream_disposition" },
317  [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" },
319  [SECTION_ID_PROGRAM_STREAMS] = { SECTION_ID_PROGRAM_STREAMS, "streams", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PROGRAM_STREAM, -1 }, .unique_name = "program_streams" },
321  [SECTION_ID_PROGRAM_TAGS] = { SECTION_ID_PROGRAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "program_tags" },
322  [SECTION_ID_PROGRAM_VERSION] = { SECTION_ID_PROGRAM_VERSION, "program_version", 0, { -1 } },
324  [SECTION_ID_STREAM_GROUP_STREAM_DISPOSITION] = { SECTION_ID_STREAM_GROUP_STREAM_DISPOSITION, "disposition", 0, { -1 }, .unique_name = "stream_group_stream_disposition" },
325  [SECTION_ID_STREAM_GROUP_STREAM_TAGS] = { SECTION_ID_STREAM_GROUP_STREAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "stream_group_stream_tags" },
327  [SECTION_ID_STREAM_GROUP_COMPONENTS] = { SECTION_ID_STREAM_GROUP_COMPONENTS, "components", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP_COMPONENT, -1 }, .element_name = "component", .unique_name = "stream_group_components" },
328  [SECTION_ID_STREAM_GROUP_COMPONENT] = { SECTION_ID_STREAM_GROUP_COMPONENT, "component", SECTION_FLAG_HAS_VARIABLE_FIELDS|SECTION_FLAG_HAS_TYPE, { SECTION_ID_STREAM_GROUP_SUBCOMPONENTS, -1 }, .unique_name = "stream_group_component", .element_name = "component_entry", .get_type = get_stream_group_type },
331  [SECTION_ID_STREAM_GROUP_PIECES] = { SECTION_ID_STREAM_GROUP_PIECES, "pieces", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP_PIECE, -1 }, .element_name = "piece", .unique_name = "stream_group_pieces" },
332  [SECTION_ID_STREAM_GROUP_PIECE] = { SECTION_ID_STREAM_GROUP_PIECE, "piece", SECTION_FLAG_HAS_VARIABLE_FIELDS|SECTION_FLAG_HAS_TYPE, { SECTION_ID_STREAM_GROUP_SUBPIECES, -1 }, .unique_name = "stream_group_piece", .element_name = "piece_entry", .get_type = get_raw_string_type },
337  [SECTION_ID_STREAM_GROUP_STREAMS] = { SECTION_ID_STREAM_GROUP_STREAMS, "streams", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP_STREAM, -1 }, .unique_name = "stream_group_streams" },
339  [SECTION_ID_STREAM_GROUP_DISPOSITION] = { SECTION_ID_STREAM_GROUP_DISPOSITION, "disposition", 0, { -1 }, .unique_name = "stream_group_disposition" },
340  [SECTION_ID_STREAM_GROUP_TAGS] = { SECTION_ID_STREAM_GROUP_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "stream_group_tags" },
348  [SECTION_ID_STREAM_DISPOSITION] = { SECTION_ID_STREAM_DISPOSITION, "disposition", 0, { -1 }, .unique_name = "stream_disposition" },
349  [SECTION_ID_STREAM_TAGS] = { SECTION_ID_STREAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "stream_tags" },
350  [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" },
351  [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 },
352  [SECTION_ID_SUBTITLE] = { SECTION_ID_SUBTITLE, "subtitle", 0, { -1 } },
353 };
354 
355 static const OptionDef *options;
356 
357 /* FFprobe context */
358 static const char *input_filename;
359 static const char *print_input_filename;
360 static const AVInputFormat *iformat = NULL;
361 static const char *output_filename = NULL;
362 
363 static struct AVHashContext *hash;
364 
365 static const struct {
366  double bin_val;
367  double dec_val;
368  const char *bin_str;
369  const char *dec_str;
370 } si_prefixes[] = {
371  { 1.0, 1.0, "", "" },
372  { 1.024e3, 1e3, "Ki", "K" },
373  { 1.048576e6, 1e6, "Mi", "M" },
374  { 1.073741824e9, 1e9, "Gi", "G" },
375  { 1.099511627776e12, 1e12, "Ti", "T" },
376  { 1.125899906842624e15, 1e15, "Pi", "P" },
377 };
378 
379 static const char unit_second_str[] = "s" ;
380 static const char unit_hertz_str[] = "Hz" ;
381 static const char unit_byte_str[] = "byte" ;
382 static const char unit_bit_per_second_str[] = "bit/s";
383 
384 static int nb_streams;
385 static uint64_t *nb_streams_packets;
386 static uint64_t *nb_streams_frames;
387 static int *selected_streams;
388 
389 #if HAVE_THREADS
390 pthread_mutex_t log_mutex;
391 #endif
392 typedef struct LogBuffer {
395  char *log_message;
397  char *parent_name;
399 }LogBuffer;
400 
402 static int log_buffer_size;
403 
404 static void log_callback(void *ptr, int level, const char *fmt, va_list vl)
405 {
406  AVClass* avc = ptr ? *(AVClass **) ptr : NULL;
407  va_list vl2;
408  char line[1024];
409  static int print_prefix = 1;
410  void *new_log_buffer;
411 
412  va_copy(vl2, vl);
413  av_log_default_callback(ptr, level, fmt, vl);
414  av_log_format_line(ptr, level, fmt, vl2, line, sizeof(line), &print_prefix);
415  va_end(vl2);
416 
417 #if HAVE_THREADS
418  pthread_mutex_lock(&log_mutex);
419 
420  new_log_buffer = av_realloc_array(log_buffer, log_buffer_size + 1, sizeof(*log_buffer));
421  if (new_log_buffer) {
422  char *msg;
423  int i;
424 
425  log_buffer = new_log_buffer;
426  memset(&log_buffer[log_buffer_size], 0, sizeof(log_buffer[log_buffer_size]));
428  if (avc) {
431  }
434  for (i=strlen(msg) - 1; i>=0 && msg[i] == '\n'; i--) {
435  msg[i] = 0;
436  }
437  if (avc && avc->parent_log_context_offset) {
438  AVClass** parent = *(AVClass ***) (((uint8_t *) ptr) +
440  if (parent && *parent) {
441  log_buffer[log_buffer_size].parent_name = av_strdup((*parent)->item_name(parent));
443  (*parent)->get_category ? (*parent)->get_category(parent) :(*parent)->category;
444  }
445  }
446  log_buffer_size ++;
447  }
448 
449  pthread_mutex_unlock(&log_mutex);
450 #endif
451 }
452 
453 struct unit_value {
454  union { double d; int64_t i; } val;
455  const char *unit;
456 };
457 
458 static char *value_string(char *buf, int buf_size, struct unit_value uv)
459 {
460  double vald;
461  int64_t vali;
462  int show_float = 0;
463 
464  if (uv.unit == unit_second_str) {
465  vald = uv.val.d;
466  show_float = 1;
467  } else {
468  vald = vali = uv.val.i;
469  }
470 
472  double secs;
473  int hours, mins;
474  secs = vald;
475  mins = (int)secs / 60;
476  secs = secs - mins * 60;
477  hours = mins / 60;
478  mins %= 60;
479  snprintf(buf, buf_size, "%d:%02d:%09.6f", hours, mins, secs);
480  } else {
481  const char *prefix_string = "";
482 
483  if (use_value_prefix && vald > 1) {
484  int64_t index;
485 
487  index = (int64_t) (log2(vald)) / 10;
489  vald /= si_prefixes[index].bin_val;
490  prefix_string = si_prefixes[index].bin_str;
491  } else {
492  index = (int64_t) (log10(vald)) / 3;
494  vald /= si_prefixes[index].dec_val;
495  prefix_string = si_prefixes[index].dec_str;
496  }
497  vali = vald;
498  }
499 
500  if (show_float || (use_value_prefix && vald != (int64_t)vald))
501  snprintf(buf, buf_size, "%f", vald);
502  else
503  snprintf(buf, buf_size, "%"PRId64, vali);
504  av_strlcatf(buf, buf_size, "%s%s%s", *prefix_string || show_value_unit ? " " : "",
505  prefix_string, show_value_unit ? uv.unit : "");
506  }
507 
508  return buf;
509 }
510 
511 /* WRITERS API */
512 
513 typedef struct WriterContext WriterContext;
514 
515 #define WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS 1
516 #define WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER 2
517 
518 typedef enum {
524 
525 typedef struct Writer {
526  const AVClass *priv_class; ///< private class of the writer, if any
527  int priv_size; ///< private size for the writer context
528  const char *name;
529 
530  int (*init) (WriterContext *wctx);
531  void (*uninit)(WriterContext *wctx);
532 
533  void (*print_section_header)(WriterContext *wctx, const void *data);
535  void (*print_integer) (WriterContext *wctx, const char *, int64_t);
536  void (*print_rational) (WriterContext *wctx, AVRational *q, char *sep);
537  void (*print_string) (WriterContext *wctx, const char *, const char *);
538  int flags; ///< a combination or WRITER_FLAG_*
539 } Writer;
540 
541 #define SECTION_MAX_NB_LEVELS 12
542 
544  const AVClass *class; ///< class of the writer
545  const Writer *writer; ///< the Writer of which this is an instance
546  AVIOContext *avio; ///< the I/O context used to write
547 
548  void (* writer_w8)(WriterContext *wctx, int b);
549  void (* writer_put_str)(WriterContext *wctx, const char *str);
550  void (* writer_printf)(WriterContext *wctx, const char *fmt, ...);
551 
552  char *name; ///< name of this writer instance
553  void *priv; ///< private data for use by the filter
554 
555  const struct section *sections; ///< array containing all sections
556  int nb_sections; ///< number of sections
557 
558  int level; ///< current level, starting from 0
559 
560  /** number of the item printed in the given section, starting from 0 */
562 
563  /** section per each level */
565  AVBPrint section_pbuf[SECTION_MAX_NB_LEVELS]; ///< generic print buffer dedicated to each section,
566  /// used by various writers
567 
568  unsigned int nb_section_packet; ///< number of the packet section in case we are in "packets_and_frames" section
569  unsigned int nb_section_frame; ///< number of the frame section in case we are in "packets_and_frames" section
570  unsigned int nb_section_packet_frame; ///< nb_section_packet or nb_section_frame according if is_packets_and_frames
571 
575 };
576 
577 static const char *writer_get_name(void *p)
578 {
579  WriterContext *wctx = p;
580  return wctx->writer->name;
581 }
582 
583 #define OFFSET(x) offsetof(WriterContext, x)
584 
585 static const AVOption writer_options[] = {
586  { "string_validation", "set string validation mode",
587  OFFSET(string_validation), AV_OPT_TYPE_INT, {.i64=WRITER_STRING_VALIDATION_REPLACE}, 0, WRITER_STRING_VALIDATION_NB-1, .unit = "sv" },
588  { "sv", "set string validation mode",
589  OFFSET(string_validation), AV_OPT_TYPE_INT, {.i64=WRITER_STRING_VALIDATION_REPLACE}, 0, WRITER_STRING_VALIDATION_NB-1, .unit = "sv" },
590  { "ignore", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = WRITER_STRING_VALIDATION_IGNORE}, .unit = "sv" },
591  { "replace", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = WRITER_STRING_VALIDATION_REPLACE}, .unit = "sv" },
592  { "fail", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = WRITER_STRING_VALIDATION_FAIL}, .unit = "sv" },
593  { "string_validation_replacement", "set string validation replacement string", OFFSET(string_validation_replacement), AV_OPT_TYPE_STRING, {.str=""}},
594  { "svr", "set string validation replacement string", OFFSET(string_validation_replacement), AV_OPT_TYPE_STRING, {.str="\xEF\xBF\xBD"}},
595  { NULL }
596 };
597 
598 static void *writer_child_next(void *obj, void *prev)
599 {
600  WriterContext *ctx = obj;
601  if (!prev && ctx->writer && ctx->writer->priv_class && ctx->priv)
602  return ctx->priv;
603  return NULL;
604 }
605 
606 static const AVClass writer_class = {
607  .class_name = "Writer",
608  .item_name = writer_get_name,
609  .option = writer_options,
610  .version = LIBAVUTIL_VERSION_INT,
611  .child_next = writer_child_next,
612 };
613 
614 static int writer_close(WriterContext **wctx)
615 {
616  int i;
617  int ret = 0;
618 
619  if (!*wctx)
620  return -1;
621 
622  if ((*wctx)->writer->uninit)
623  (*wctx)->writer->uninit(*wctx);
624  for (i = 0; i < SECTION_MAX_NB_LEVELS; i++)
625  av_bprint_finalize(&(*wctx)->section_pbuf[i], NULL);
626  if ((*wctx)->writer->priv_class)
627  av_opt_free((*wctx)->priv);
628  av_freep(&((*wctx)->priv));
629  av_opt_free(*wctx);
630  if ((*wctx)->avio) {
631  avio_flush((*wctx)->avio);
632  ret = avio_close((*wctx)->avio);
633  }
634  av_freep(wctx);
635  return ret;
636 }
637 
638 static void bprint_bytes(AVBPrint *bp, const uint8_t *ubuf, size_t ubuf_size)
639 {
640  int i;
641  av_bprintf(bp, "0X");
642  for (i = 0; i < ubuf_size; i++)
643  av_bprintf(bp, "%02X", ubuf[i]);
644 }
645 
646 static inline void writer_w8_avio(WriterContext *wctx, int b)
647 {
648  avio_w8(wctx->avio, b);
649 }
650 
651 static inline void writer_put_str_avio(WriterContext *wctx, const char *str)
652 {
653  avio_write(wctx->avio, str, strlen(str));
654 }
655 
656 static inline void writer_printf_avio(WriterContext *wctx, const char *fmt, ...)
657 {
658  va_list ap;
659 
660  va_start(ap, fmt);
661  avio_vprintf(wctx->avio, fmt, ap);
662  va_end(ap);
663 }
664 
665 static inline void writer_w8_printf(WriterContext *wctx, int b)
666 {
667  printf("%c", b);
668 }
669 
670 static inline void writer_put_str_printf(WriterContext *wctx, const char *str)
671 {
672  printf("%s", str);
673 }
674 
675 static inline void writer_printf_printf(WriterContext *wctx, const char *fmt, ...)
676 {
677  va_list ap;
678 
679  va_start(ap, fmt);
680  vprintf(fmt, ap);
681  va_end(ap);
682 }
683 
684 static int writer_open(WriterContext **wctx, const Writer *writer, const char *args,
685  const struct section *sections, int nb_sections, const char *output)
686 {
687  int i, ret = 0;
688 
689  if (!(*wctx = av_mallocz(sizeof(WriterContext)))) {
690  ret = AVERROR(ENOMEM);
691  goto fail;
692  }
693 
694  if (!((*wctx)->priv = av_mallocz(writer->priv_size))) {
695  ret = AVERROR(ENOMEM);
696  goto fail;
697  }
698 
699  (*wctx)->class = &writer_class;
700  (*wctx)->writer = writer;
701  (*wctx)->level = -1;
702  (*wctx)->sections = sections;
703  (*wctx)->nb_sections = nb_sections;
704 
705  av_opt_set_defaults(*wctx);
706 
707  if (writer->priv_class) {
708  void *priv_ctx = (*wctx)->priv;
709  *((const AVClass **)priv_ctx) = writer->priv_class;
710  av_opt_set_defaults(priv_ctx);
711  }
712 
713  /* convert options to dictionary */
714  if (args) {
716  const AVDictionaryEntry *opt = NULL;
717 
718  if ((ret = av_dict_parse_string(&opts, args, "=", ":", 0)) < 0) {
719  av_log(*wctx, AV_LOG_ERROR, "Failed to parse option string '%s' provided to writer context\n", args);
720  av_dict_free(&opts);
721  goto fail;
722  }
723 
724  while ((opt = av_dict_iterate(opts, opt))) {
725  if ((ret = av_opt_set(*wctx, opt->key, opt->value, AV_OPT_SEARCH_CHILDREN)) < 0) {
726  av_log(*wctx, AV_LOG_ERROR, "Failed to set option '%s' with value '%s' provided to writer context\n",
727  opt->key, opt->value);
728  av_dict_free(&opts);
729  goto fail;
730  }
731  }
732 
733  av_dict_free(&opts);
734  }
735 
736  /* validate replace string */
737  {
738  const uint8_t *p = (*wctx)->string_validation_replacement;
739  const uint8_t *endp = p + strlen(p);
740  while (*p) {
741  const uint8_t *p0 = p;
742  int32_t code;
743  ret = av_utf8_decode(&code, &p, endp, (*wctx)->string_validation_utf8_flags);
744  if (ret < 0) {
745  AVBPrint bp;
747  bprint_bytes(&bp, p0, p-p0),
748  av_log(wctx, AV_LOG_ERROR,
749  "Invalid UTF8 sequence %s found in string validation replace '%s'\n",
750  bp.str, (*wctx)->string_validation_replacement);
751  return ret;
752  }
753  }
754  }
755 
756  if (!output_filename) {
757  (*wctx)->writer_w8 = writer_w8_printf;
758  (*wctx)->writer_put_str = writer_put_str_printf;
759  (*wctx)->writer_printf = writer_printf_printf;
760  } else {
761  if ((ret = avio_open(&(*wctx)->avio, output, AVIO_FLAG_WRITE)) < 0) {
762  av_log(*wctx, AV_LOG_ERROR,
763  "Failed to open output '%s' with error: %s\n", output, av_err2str(ret));
764  goto fail;
765  }
766  (*wctx)->writer_w8 = writer_w8_avio;
767  (*wctx)->writer_put_str = writer_put_str_avio;
768  (*wctx)->writer_printf = writer_printf_avio;
769  }
770 
771  for (i = 0; i < SECTION_MAX_NB_LEVELS; i++)
772  av_bprint_init(&(*wctx)->section_pbuf[i], 1, AV_BPRINT_SIZE_UNLIMITED);
773 
774  if ((*wctx)->writer->init)
775  ret = (*wctx)->writer->init(*wctx);
776  if (ret < 0)
777  goto fail;
778 
779  return 0;
780 
781 fail:
782  writer_close(wctx);
783  return ret;
784 }
785 
787  const void *data,
788  int section_id)
789 {
790  int parent_section_id;
791  wctx->level++;
793  parent_section_id = wctx->level ?
794  (wctx->section[wctx->level-1])->id : SECTION_ID_NONE;
795 
796  wctx->nb_item[wctx->level] = 0;
797  wctx->section[wctx->level] = &wctx->sections[section_id];
798 
799  if (section_id == SECTION_ID_PACKETS_AND_FRAMES) {
800  wctx->nb_section_packet = wctx->nb_section_frame =
801  wctx->nb_section_packet_frame = 0;
802  } else if (parent_section_id == SECTION_ID_PACKETS_AND_FRAMES) {
803  wctx->nb_section_packet_frame = section_id == SECTION_ID_PACKET ?
804  wctx->nb_section_packet : wctx->nb_section_frame;
805  }
806 
807  if (wctx->writer->print_section_header)
808  wctx->writer->print_section_header(wctx, data);
809 }
810 
812 {
813  int section_id = wctx->section[wctx->level]->id;
814  int parent_section_id = wctx->level ?
815  wctx->section[wctx->level-1]->id : SECTION_ID_NONE;
816 
817  if (parent_section_id != SECTION_ID_NONE)
818  wctx->nb_item[wctx->level-1]++;
819  if (parent_section_id == SECTION_ID_PACKETS_AND_FRAMES) {
820  if (section_id == SECTION_ID_PACKET) wctx->nb_section_packet++;
821  else wctx->nb_section_frame++;
822  }
823  if (wctx->writer->print_section_footer)
824  wctx->writer->print_section_footer(wctx);
825  wctx->level--;
826 }
827 
828 static inline void writer_print_integer(WriterContext *wctx,
829  const char *key, int64_t val)
830 {
831  const struct section *section = wctx->section[wctx->level];
832 
834  wctx->writer->print_integer(wctx, key, val);
835  wctx->nb_item[wctx->level]++;
836  }
837 }
838 
839 static inline int validate_string(WriterContext *wctx, char **dstp, const char *src)
840 {
841  const uint8_t *p, *endp;
842  AVBPrint dstbuf;
843  int invalid_chars_nb = 0, ret = 0;
844 
846 
847  endp = src + strlen(src);
848  for (p = src; *p;) {
849  uint32_t code;
850  int invalid = 0;
851  const uint8_t *p0 = p;
852 
853  if (av_utf8_decode(&code, &p, endp, wctx->string_validation_utf8_flags) < 0) {
854  AVBPrint bp;
856  bprint_bytes(&bp, p0, p-p0);
857  av_log(wctx, AV_LOG_DEBUG,
858  "Invalid UTF-8 sequence %s found in string '%s'\n", bp.str, src);
859  invalid = 1;
860  }
861 
862  if (invalid) {
863  invalid_chars_nb++;
864 
865  switch (wctx->string_validation) {
867  av_log(wctx, AV_LOG_ERROR,
868  "Invalid UTF-8 sequence found in string '%s'\n", src);
870  goto end;
871  break;
872 
874  av_bprintf(&dstbuf, "%s", wctx->string_validation_replacement);
875  break;
876  }
877  }
878 
879  if (!invalid || wctx->string_validation == WRITER_STRING_VALIDATION_IGNORE)
880  av_bprint_append_data(&dstbuf, p0, p-p0);
881  }
882 
883  if (invalid_chars_nb && wctx->string_validation == WRITER_STRING_VALIDATION_REPLACE) {
884  av_log(wctx, AV_LOG_WARNING,
885  "%d invalid UTF-8 sequence(s) found in string '%s', replaced with '%s'\n",
886  invalid_chars_nb, src, wctx->string_validation_replacement);
887  }
888 
889 end:
890  av_bprint_finalize(&dstbuf, dstp);
891  return ret;
892 }
893 
894 #define PRINT_STRING_OPT 1
895 #define PRINT_STRING_VALIDATE 2
896 
897 static inline int writer_print_string(WriterContext *wctx,
898  const char *key, const char *val, int flags)
899 {
900  const struct section *section = wctx->section[wctx->level];
901  int ret = 0;
902 
905  && (flags & PRINT_STRING_OPT)
907  return 0;
908 
911  char *key1 = NULL, *val1 = NULL;
912  ret = validate_string(wctx, &key1, key);
913  if (ret < 0) goto end;
914  ret = validate_string(wctx, &val1, val);
915  if (ret < 0) goto end;
916  wctx->writer->print_string(wctx, key1, val1);
917  end:
918  if (ret < 0) {
919  av_log(wctx, AV_LOG_ERROR,
920  "Invalid key=value string combination %s=%s in section %s\n",
922  }
923  av_free(key1);
924  av_free(val1);
925  } else {
926  wctx->writer->print_string(wctx, key, val);
927  }
928 
929  wctx->nb_item[wctx->level]++;
930  }
931 
932  return ret;
933 }
934 
935 static inline void writer_print_rational(WriterContext *wctx,
936  const char *key, AVRational q, char sep)
937 {
938  AVBPrint buf;
940  av_bprintf(&buf, "%d%c%d", q.num, sep, q.den);
941  writer_print_string(wctx, key, buf.str, 0);
942 }
943 
944 static void writer_print_time(WriterContext *wctx, const char *key,
945  int64_t ts, const AVRational *time_base, int is_duration)
946 {
947  char buf[128];
948 
949  if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0)) {
951  } else {
952  double d = ts * av_q2d(*time_base);
953  struct unit_value uv;
954  uv.val.d = d;
955  uv.unit = unit_second_str;
956  value_string(buf, sizeof(buf), uv);
957  writer_print_string(wctx, key, buf, 0);
958  }
959 }
960 
961 static void writer_print_ts(WriterContext *wctx, const char *key, int64_t ts, int is_duration)
962 {
963  if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0)) {
965  } else {
966  writer_print_integer(wctx, key, ts);
967  }
968 }
969 
970 static void writer_print_data(WriterContext *wctx, const char *name,
971  const uint8_t *data, int size)
972 {
973  AVBPrint bp;
974  int offset = 0, l, i;
975 
977  av_bprintf(&bp, "\n");
978  while (size) {
979  av_bprintf(&bp, "%08x: ", offset);
980  l = FFMIN(size, 16);
981  for (i = 0; i < l; i++) {
982  av_bprintf(&bp, "%02x", data[i]);
983  if (i & 1)
984  av_bprintf(&bp, " ");
985  }
986  av_bprint_chars(&bp, ' ', 41 - 2 * i - i / 2);
987  for (i = 0; i < l; i++)
988  av_bprint_chars(&bp, data[i] - 32U < 95 ? data[i] : '.', 1);
989  av_bprintf(&bp, "\n");
990  offset += l;
991  data += l;
992  size -= l;
993  }
994  writer_print_string(wctx, name, bp.str, 0);
995  av_bprint_finalize(&bp, NULL);
996 }
997 
998 static void writer_print_data_hash(WriterContext *wctx, const char *name,
999  const uint8_t *data, int size)
1000 {
1001  char *p, buf[AV_HASH_MAX_SIZE * 2 + 64] = { 0 };
1002 
1003  if (!hash)
1004  return;
1005  av_hash_init(hash);
1007  snprintf(buf, sizeof(buf), "%s:", av_hash_get_name(hash));
1008  p = buf + strlen(buf);
1009  av_hash_final_hex(hash, p, buf + sizeof(buf) - p);
1010  writer_print_string(wctx, name, buf, 0);
1011 }
1012 
1013 static void writer_print_integers(WriterContext *wctx, const char *name,
1014  uint8_t *data, int size, const char *format,
1015  int columns, int bytes, int offset_add)
1016 {
1017  AVBPrint bp;
1018  int offset = 0, l, i;
1019 
1021  av_bprintf(&bp, "\n");
1022  while (size) {
1023  av_bprintf(&bp, "%08x: ", offset);
1024  l = FFMIN(size, columns);
1025  for (i = 0; i < l; i++) {
1026  if (bytes == 1) av_bprintf(&bp, format, *data);
1027  else if (bytes == 2) av_bprintf(&bp, format, AV_RN16(data));
1028  else if (bytes == 4) av_bprintf(&bp, format, AV_RN32(data));
1029  data += bytes;
1030  size --;
1031  }
1032  av_bprintf(&bp, "\n");
1033  offset += offset_add;
1034  }
1035  writer_print_string(wctx, name, bp.str, 0);
1036  av_bprint_finalize(&bp, NULL);
1037 }
1038 
1039 #define writer_w8(wctx_, b_) (wctx_)->writer_w8(wctx_, b_)
1040 #define writer_put_str(wctx_, str_) (wctx_)->writer_put_str(wctx_, str_)
1041 #define writer_printf(wctx_, fmt_, ...) (wctx_)->writer_printf(wctx_, fmt_, __VA_ARGS__)
1042 
1043 #define MAX_REGISTERED_WRITERS_NB 64
1044 
1046 
1047 static int writer_register(const Writer *writer)
1048 {
1049  static int next_registered_writer_idx = 0;
1050 
1051  if (next_registered_writer_idx == MAX_REGISTERED_WRITERS_NB)
1052  return AVERROR(ENOMEM);
1053 
1054  registered_writers[next_registered_writer_idx++] = writer;
1055  return 0;
1056 }
1057 
1058 static const Writer *writer_get_by_name(const char *name)
1059 {
1060  int i;
1061 
1062  for (i = 0; registered_writers[i]; i++)
1063  if (!strcmp(registered_writers[i]->name, name))
1064  return registered_writers[i];
1065 
1066  return NULL;
1067 }
1068 
1069 
1070 /* WRITERS */
1071 
1072 #define DEFINE_WRITER_CLASS(name) \
1073 static const char *name##_get_name(void *ctx) \
1074 { \
1075  return #name ; \
1076 } \
1077 static const AVClass name##_class = { \
1078  .class_name = #name, \
1079  .item_name = name##_get_name, \
1080  .option = name##_options \
1081 }
1082 
1083 /* Default output */
1084 
1085 typedef struct DefaultContext {
1086  const AVClass *class;
1087  int nokey;
1090 } DefaultContext;
1091 
1092 #undef OFFSET
1093 #define OFFSET(x) offsetof(DefaultContext, x)
1094 
1095 static const AVOption default_options[] = {
1096  { "noprint_wrappers", "do not print headers and footers", OFFSET(noprint_wrappers), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
1097  { "nw", "do not print headers and footers", OFFSET(noprint_wrappers), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
1098  { "nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
1099  { "nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
1100  {NULL},
1101 };
1102 
1103 DEFINE_WRITER_CLASS(default);
1104 
1105 /* lame uppercasing routine, assumes the string is lower case ASCII */
1106 static inline char *upcase_string(char *dst, size_t dst_size, const char *src)
1107 {
1108  int i;
1109  for (i = 0; src[i] && i < dst_size-1; i++)
1110  dst[i] = av_toupper(src[i]);
1111  dst[i] = 0;
1112  return dst;
1113 }
1114 
1115 static void default_print_section_header(WriterContext *wctx, const void *data)
1116 {
1117  DefaultContext *def = wctx->priv;
1118  char buf[32];
1119  const struct section *section = wctx->section[wctx->level];
1120  const struct section *parent_section = wctx->level ?
1121  wctx->section[wctx->level-1] : NULL;
1122 
1123  av_bprint_clear(&wctx->section_pbuf[wctx->level]);
1124  if (parent_section &&
1125  !(parent_section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))) {
1126  def->nested_section[wctx->level] = 1;
1127  av_bprintf(&wctx->section_pbuf[wctx->level], "%s%s:",
1128  wctx->section_pbuf[wctx->level-1].str,
1129  upcase_string(buf, sizeof(buf),
1131  }
1132 
1133  if (def->noprint_wrappers || def->nested_section[wctx->level])
1134  return;
1135 
1137  writer_printf(wctx, "[%s]\n", upcase_string(buf, sizeof(buf), section->name));
1138 }
1139 
1141 {
1142  DefaultContext *def = wctx->priv;
1143  const struct section *section = wctx->section[wctx->level];
1144  char buf[32];
1145 
1146  if (def->noprint_wrappers || def->nested_section[wctx->level])
1147  return;
1148 
1150  writer_printf(wctx, "[/%s]\n", upcase_string(buf, sizeof(buf), section->name));
1151 }
1152 
1153 static void default_print_str(WriterContext *wctx, const char *key, const char *value)
1154 {
1155  DefaultContext *def = wctx->priv;
1156 
1157  if (!def->nokey)
1158  writer_printf(wctx, "%s%s=", wctx->section_pbuf[wctx->level].str, key);
1159  writer_printf(wctx, "%s\n", value);
1160 }
1161 
1162 static void default_print_int(WriterContext *wctx, const char *key, int64_t value)
1163 {
1164  DefaultContext *def = wctx->priv;
1165 
1166  if (!def->nokey)
1167  writer_printf(wctx, "%s%s=", wctx->section_pbuf[wctx->level].str, key);
1168  writer_printf(wctx, "%"PRId64"\n", value);
1169 }
1170 
1171 static const Writer default_writer = {
1172  .name = "default",
1173  .priv_size = sizeof(DefaultContext),
1176  .print_integer = default_print_int,
1177  .print_string = default_print_str,
1179  .priv_class = &default_class,
1180 };
1181 
1182 /* Compact output */
1183 
1184 /**
1185  * Apply C-language-like string escaping.
1186  */
1187 static const char *c_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
1188 {
1189  const char *p;
1190 
1191  for (p = src; *p; p++) {
1192  switch (*p) {
1193  case '\b': av_bprintf(dst, "%s", "\\b"); break;
1194  case '\f': av_bprintf(dst, "%s", "\\f"); break;
1195  case '\n': av_bprintf(dst, "%s", "\\n"); break;
1196  case '\r': av_bprintf(dst, "%s", "\\r"); break;
1197  case '\\': av_bprintf(dst, "%s", "\\\\"); break;
1198  default:
1199  if (*p == sep)
1200  av_bprint_chars(dst, '\\', 1);
1201  av_bprint_chars(dst, *p, 1);
1202  }
1203  }
1204  return dst->str;
1205 }
1206 
1207 /**
1208  * Quote fields containing special characters, check RFC4180.
1209  */
1210 static const char *csv_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
1211 {
1212  char meta_chars[] = { sep, '"', '\n', '\r', '\0' };
1213  int needs_quoting = !!src[strcspn(src, meta_chars)];
1214 
1215  if (needs_quoting)
1216  av_bprint_chars(dst, '"', 1);
1217 
1218  for (; *src; src++) {
1219  if (*src == '"')
1220  av_bprint_chars(dst, '"', 1);
1221  av_bprint_chars(dst, *src, 1);
1222  }
1223  if (needs_quoting)
1224  av_bprint_chars(dst, '"', 1);
1225  return dst->str;
1226 }
1227 
1228 static const char *none_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
1229 {
1230  return src;
1231 }
1232 
1233 typedef struct CompactContext {
1234  const AVClass *class;
1236  char item_sep;
1237  int nokey;
1240  const char * (*escape_str)(AVBPrint *dst, const char *src, const char sep, void *log_ctx);
1244 } CompactContext;
1245 
1246 #undef OFFSET
1247 #define OFFSET(x) offsetof(CompactContext, x)
1248 
1249 static const AVOption compact_options[]= {
1250  {"item_sep", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str="|"}, 0, 0 },
1251  {"s", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str="|"}, 0, 0 },
1252  {"nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
1253  {"nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
1254  {"escape", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="c"}, 0, 0 },
1255  {"e", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="c"}, 0, 0 },
1256  {"print_section", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
1257  {"p", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
1258  {NULL},
1259 };
1260 
1261 DEFINE_WRITER_CLASS(compact);
1262 
1264 {
1265  CompactContext *compact = wctx->priv;
1266 
1267  if (strlen(compact->item_sep_str) != 1) {
1268  av_log(wctx, AV_LOG_ERROR, "Item separator '%s' specified, but must contain a single character\n",
1269  compact->item_sep_str);
1270  return AVERROR(EINVAL);
1271  }
1272  compact->item_sep = compact->item_sep_str[0];
1273 
1274  if (!strcmp(compact->escape_mode_str, "none")) compact->escape_str = none_escape_str;
1275  else if (!strcmp(compact->escape_mode_str, "c" )) compact->escape_str = c_escape_str;
1276  else if (!strcmp(compact->escape_mode_str, "csv" )) compact->escape_str = csv_escape_str;
1277  else {
1278  av_log(wctx, AV_LOG_ERROR, "Unknown escape mode '%s'\n", compact->escape_mode_str);
1279  return AVERROR(EINVAL);
1280  }
1281 
1282  return 0;
1283 }
1284 
1285 static void compact_print_section_header(WriterContext *wctx, const void *data)
1286 {
1287  CompactContext *compact = wctx->priv;
1288  const struct section *section = wctx->section[wctx->level];
1289  const struct section *parent_section = wctx->level ?
1290  wctx->section[wctx->level-1] : NULL;
1291  compact->terminate_line[wctx->level] = 1;
1292  compact->has_nested_elems[wctx->level] = 0;
1293 
1294  av_bprint_clear(&wctx->section_pbuf[wctx->level]);
1295  if (parent_section &&
1298  !(parent_section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))))) {
1299 
1300  /* define a prefix for elements not contained in an array or
1301  in a wrapper, or for array elements with a type */
1302  const char *element_name = (char *)av_x_if_null(section->element_name, section->name);
1303  AVBPrint *section_pbuf = &wctx->section_pbuf[wctx->level];
1304 
1305  compact->nested_section[wctx->level] = 1;
1306  compact->has_nested_elems[wctx->level-1] = 1;
1307 
1308  av_bprintf(section_pbuf, "%s%s",
1309  wctx->section_pbuf[wctx->level-1].str, element_name);
1310 
1312  // add /TYPE to prefix
1313  av_bprint_chars(section_pbuf, '/', 1);
1314 
1315  // normalize section type, replace special characters and lower case
1316  for (const char *p = section->get_type(data); *p; p++) {
1317  char c =
1318  (*p >= '0' && *p <= '9') ||
1319  (*p >= 'a' && *p <= 'z') ||
1320  (*p >= 'A' && *p <= 'Z') ? av_tolower(*p) : '_';
1321  av_bprint_chars(section_pbuf, c, 1);
1322  }
1323  }
1324  av_bprint_chars(section_pbuf, ':', 1);
1325 
1326  wctx->nb_item[wctx->level] = wctx->nb_item[wctx->level-1];
1327  } else {
1328  if (parent_section && !(parent_section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY)) &&
1329  wctx->level && wctx->nb_item[wctx->level-1])
1330  writer_w8(wctx, compact->item_sep);
1331  if (compact->print_section &&
1333  writer_printf(wctx, "%s%c", section->name, compact->item_sep);
1334  }
1335 }
1336 
1338 {
1339  CompactContext *compact = wctx->priv;
1340 
1341  if (!compact->nested_section[wctx->level] &&
1342  compact->terminate_line[wctx->level] &&
1344  writer_w8(wctx, '\n');
1345 }
1346 
1347 static void compact_print_str(WriterContext *wctx, const char *key, const char *value)
1348 {
1349  CompactContext *compact = wctx->priv;
1350  AVBPrint buf;
1351 
1352  if (wctx->nb_item[wctx->level]) writer_w8(wctx, compact->item_sep);
1353  if (!compact->nokey)
1354  writer_printf(wctx, "%s%s=", wctx->section_pbuf[wctx->level].str, key);
1356  writer_put_str(wctx, compact->escape_str(&buf, value, compact->item_sep, wctx));
1357  av_bprint_finalize(&buf, NULL);
1358 }
1359 
1360 static void compact_print_int(WriterContext *wctx, const char *key, int64_t value)
1361 {
1362  CompactContext *compact = wctx->priv;
1363 
1364  if (wctx->nb_item[wctx->level]) writer_w8(wctx, compact->item_sep);
1365  if (!compact->nokey)
1366  writer_printf(wctx, "%s%s=", wctx->section_pbuf[wctx->level].str, key);
1367  writer_printf(wctx, "%"PRId64, value);
1368 }
1369 
1370 static const Writer compact_writer = {
1371  .name = "compact",
1372  .priv_size = sizeof(CompactContext),
1373  .init = compact_init,
1376  .print_integer = compact_print_int,
1377  .print_string = compact_print_str,
1379  .priv_class = &compact_class,
1380 };
1381 
1382 /* CSV output */
1383 
1384 #undef OFFSET
1385 #define OFFSET(x) offsetof(CompactContext, x)
1386 
1387 static const AVOption csv_options[] = {
1388  {"item_sep", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str=","}, 0, 0 },
1389  {"s", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str=","}, 0, 0 },
1390  {"nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
1391  {"nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
1392  {"escape", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="csv"}, 0, 0 },
1393  {"e", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="csv"}, 0, 0 },
1394  {"print_section", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
1395  {"p", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
1396  {NULL},
1397 };
1398 
1400 
1401 static const Writer csv_writer = {
1402  .name = "csv",
1403  .priv_size = sizeof(CompactContext),
1404  .init = compact_init,
1407  .print_integer = compact_print_int,
1408  .print_string = compact_print_str,
1410  .priv_class = &csv_class,
1411 };
1412 
1413 /* Flat output */
1414 
1415 typedef struct FlatContext {
1416  const AVClass *class;
1417  const char *sep_str;
1418  char sep;
1420 } FlatContext;
1421 
1422 #undef OFFSET
1423 #define OFFSET(x) offsetof(FlatContext, x)
1424 
1425 static const AVOption flat_options[]= {
1426  {"sep_char", "set separator", OFFSET(sep_str), AV_OPT_TYPE_STRING, {.str="."}, 0, 0 },
1427  {"s", "set separator", OFFSET(sep_str), AV_OPT_TYPE_STRING, {.str="."}, 0, 0 },
1428  {"hierarchical", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
1429  {"h", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
1430  {NULL},
1431 };
1432 
1434 
1436 {
1437  FlatContext *flat = wctx->priv;
1438 
1439  if (strlen(flat->sep_str) != 1) {
1440  av_log(wctx, AV_LOG_ERROR, "Item separator '%s' specified, but must contain a single character\n",
1441  flat->sep_str);
1442  return AVERROR(EINVAL);
1443  }
1444  flat->sep = flat->sep_str[0];
1445 
1446  return 0;
1447 }
1448 
1449 static const char *flat_escape_key_str(AVBPrint *dst, const char *src, const char sep)
1450 {
1451  const char *p;
1452 
1453  for (p = src; *p; p++) {
1454  if (!((*p >= '0' && *p <= '9') ||
1455  (*p >= 'a' && *p <= 'z') ||
1456  (*p >= 'A' && *p <= 'Z')))
1457  av_bprint_chars(dst, '_', 1);
1458  else
1459  av_bprint_chars(dst, *p, 1);
1460  }
1461  return dst->str;
1462 }
1463 
1464 static const char *flat_escape_value_str(AVBPrint *dst, const char *src)
1465 {
1466  const char *p;
1467 
1468  for (p = src; *p; p++) {
1469  switch (*p) {
1470  case '\n': av_bprintf(dst, "%s", "\\n"); break;
1471  case '\r': av_bprintf(dst, "%s", "\\r"); break;
1472  case '\\': av_bprintf(dst, "%s", "\\\\"); break;
1473  case '"': av_bprintf(dst, "%s", "\\\""); break;
1474  case '`': av_bprintf(dst, "%s", "\\`"); break;
1475  case '$': av_bprintf(dst, "%s", "\\$"); break;
1476  default: av_bprint_chars(dst, *p, 1); break;
1477  }
1478  }
1479  return dst->str;
1480 }
1481 
1482 static void flat_print_section_header(WriterContext *wctx, const void *data)
1483 {
1484  FlatContext *flat = wctx->priv;
1485  AVBPrint *buf = &wctx->section_pbuf[wctx->level];
1486  const struct section *section = wctx->section[wctx->level];
1487  const struct section *parent_section = wctx->level ?
1488  wctx->section[wctx->level-1] : NULL;
1489 
1490  /* build section header */
1491  av_bprint_clear(buf);
1492  if (!parent_section)
1493  return;
1494  av_bprintf(buf, "%s", wctx->section_pbuf[wctx->level-1].str);
1495 
1496  if (flat->hierarchical ||
1498  av_bprintf(buf, "%s%s", wctx->section[wctx->level]->name, flat->sep_str);
1499 
1500  if (parent_section->flags & SECTION_FLAG_IS_ARRAY) {
1501  int n = parent_section->id == SECTION_ID_PACKETS_AND_FRAMES ?
1502  wctx->nb_section_packet_frame : wctx->nb_item[wctx->level-1];
1503  av_bprintf(buf, "%d%s", n, flat->sep_str);
1504  }
1505  }
1506 }
1507 
1508 static void flat_print_int(WriterContext *wctx, const char *key, int64_t value)
1509 {
1510  writer_printf(wctx, "%s%s=%"PRId64"\n", wctx->section_pbuf[wctx->level].str, key, value);
1511 }
1512 
1513 static void flat_print_str(WriterContext *wctx, const char *key, const char *value)
1514 {
1515  FlatContext *flat = wctx->priv;
1516  AVBPrint buf;
1517 
1518  writer_put_str(wctx, wctx->section_pbuf[wctx->level].str);
1520  writer_printf(wctx, "%s=", flat_escape_key_str(&buf, key, flat->sep));
1521  av_bprint_clear(&buf);
1522  writer_printf(wctx, "\"%s\"\n", flat_escape_value_str(&buf, value));
1523  av_bprint_finalize(&buf, NULL);
1524 }
1525 
1526 static const Writer flat_writer = {
1527  .name = "flat",
1528  .priv_size = sizeof(FlatContext),
1529  .init = flat_init,
1531  .print_integer = flat_print_int,
1532  .print_string = flat_print_str,
1534  .priv_class = &flat_class,
1535 };
1536 
1537 /* INI format output */
1538 
1539 typedef struct INIContext {
1540  const AVClass *class;
1542 } INIContext;
1543 
1544 #undef OFFSET
1545 #define OFFSET(x) offsetof(INIContext, x)
1546 
1547 static const AVOption ini_options[] = {
1548  {"hierarchical", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
1549  {"h", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
1550  {NULL},
1551 };
1552 
1553 DEFINE_WRITER_CLASS(ini);
1554 
1555 static char *ini_escape_str(AVBPrint *dst, const char *src)
1556 {
1557  int i = 0;
1558  char c = 0;
1559 
1560  while (c = src[i++]) {
1561  switch (c) {
1562  case '\b': av_bprintf(dst, "%s", "\\b"); break;
1563  case '\f': av_bprintf(dst, "%s", "\\f"); break;
1564  case '\n': av_bprintf(dst, "%s", "\\n"); break;
1565  case '\r': av_bprintf(dst, "%s", "\\r"); break;
1566  case '\t': av_bprintf(dst, "%s", "\\t"); break;
1567  case '\\':
1568  case '#' :
1569  case '=' :
1570  case ':' : av_bprint_chars(dst, '\\', 1);
1571  default:
1572  if ((unsigned char)c < 32)
1573  av_bprintf(dst, "\\x00%02x", c & 0xff);
1574  else
1575  av_bprint_chars(dst, c, 1);
1576  break;
1577  }
1578  }
1579  return dst->str;
1580 }
1581 
1582 static void ini_print_section_header(WriterContext *wctx, const void *data)
1583 {
1584  INIContext *ini = wctx->priv;
1585  AVBPrint *buf = &wctx->section_pbuf[wctx->level];
1586  const struct section *section = wctx->section[wctx->level];
1587  const struct section *parent_section = wctx->level ?
1588  wctx->section[wctx->level-1] : NULL;
1589 
1590  av_bprint_clear(buf);
1591  if (!parent_section) {
1592  writer_put_str(wctx, "# ffprobe output\n\n");
1593  return;
1594  }
1595 
1596  if (wctx->nb_item[wctx->level-1])
1597  writer_w8(wctx, '\n');
1598 
1599  av_bprintf(buf, "%s", wctx->section_pbuf[wctx->level-1].str);
1600  if (ini->hierarchical ||
1602  av_bprintf(buf, "%s%s", buf->str[0] ? "." : "", wctx->section[wctx->level]->name);
1603 
1604  if (parent_section->flags & SECTION_FLAG_IS_ARRAY) {
1605  int n = parent_section->id == SECTION_ID_PACKETS_AND_FRAMES ?
1606  wctx->nb_section_packet_frame : wctx->nb_item[wctx->level-1];
1607  av_bprintf(buf, ".%d", n);
1608  }
1609  }
1610 
1612  writer_printf(wctx, "[%s]\n", buf->str);
1613 }
1614 
1615 static void ini_print_str(WriterContext *wctx, const char *key, const char *value)
1616 {
1617  AVBPrint buf;
1618 
1620  writer_printf(wctx, "%s=", ini_escape_str(&buf, key));
1621  av_bprint_clear(&buf);
1622  writer_printf(wctx, "%s\n", ini_escape_str(&buf, value));
1623  av_bprint_finalize(&buf, NULL);
1624 }
1625 
1626 static void ini_print_int(WriterContext *wctx, const char *key, int64_t value)
1627 {
1628  writer_printf(wctx, "%s=%"PRId64"\n", key, value);
1629 }
1630 
1631 static const Writer ini_writer = {
1632  .name = "ini",
1633  .priv_size = sizeof(INIContext),
1635  .print_integer = ini_print_int,
1636  .print_string = ini_print_str,
1638  .priv_class = &ini_class,
1639 };
1640 
1641 /* JSON output */
1642 
1643 typedef struct JSONContext {
1644  const AVClass *class;
1646  int compact;
1647  const char *item_sep, *item_start_end;
1648 } JSONContext;
1649 
1650 #undef OFFSET
1651 #define OFFSET(x) offsetof(JSONContext, x)
1652 
1653 static const AVOption json_options[]= {
1654  { "compact", "enable compact output", OFFSET(compact), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
1655  { "c", "enable compact output", OFFSET(compact), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
1656  { NULL }
1657 };
1658 
1659 DEFINE_WRITER_CLASS(json);
1660 
1662 {
1663  JSONContext *json = wctx->priv;
1664 
1665  json->item_sep = json->compact ? ", " : ",\n";
1666  json->item_start_end = json->compact ? " " : "\n";
1667 
1668  return 0;
1669 }
1670 
1671 static const char *json_escape_str(AVBPrint *dst, const char *src, void *log_ctx)
1672 {
1673  static const char json_escape[] = {'"', '\\', '\b', '\f', '\n', '\r', '\t', 0};
1674  static const char json_subst[] = {'"', '\\', 'b', 'f', 'n', 'r', 't', 0};
1675  const char *p;
1676 
1677  for (p = src; *p; p++) {
1678  char *s = strchr(json_escape, *p);
1679  if (s) {
1680  av_bprint_chars(dst, '\\', 1);
1681  av_bprint_chars(dst, json_subst[s - json_escape], 1);
1682  } else if ((unsigned char)*p < 32) {
1683  av_bprintf(dst, "\\u00%02x", *p & 0xff);
1684  } else {
1685  av_bprint_chars(dst, *p, 1);
1686  }
1687  }
1688  return dst->str;
1689 }
1690 
1691 #define JSON_INDENT() writer_printf(wctx, "%*c", json->indent_level * 4, ' ')
1692 
1693 static void json_print_section_header(WriterContext *wctx, const void *data)
1694 {
1695  JSONContext *json = wctx->priv;
1696  AVBPrint buf;
1697  const struct section *section = wctx->section[wctx->level];
1698  const struct section *parent_section = wctx->level ?
1699  wctx->section[wctx->level-1] : NULL;
1700 
1701  if (wctx->level && wctx->nb_item[wctx->level-1])
1702  writer_put_str(wctx, ",\n");
1703 
1705  writer_put_str(wctx, "{\n");
1706  json->indent_level++;
1707  } else {
1709  json_escape_str(&buf, section->name, wctx);
1710  JSON_INDENT();
1711 
1712  json->indent_level++;
1714  writer_printf(wctx, "\"%s\": [\n", buf.str);
1715  } else if (parent_section && !(parent_section->flags & SECTION_FLAG_IS_ARRAY)) {
1716  writer_printf(wctx, "\"%s\": {%s", buf.str, json->item_start_end);
1717  } else {
1718  writer_printf(wctx, "{%s", json->item_start_end);
1719 
1720  /* this is required so the parser can distinguish between packets and frames */
1721  if (parent_section && parent_section->id == SECTION_ID_PACKETS_AND_FRAMES) {
1722  if (!json->compact)
1723  JSON_INDENT();
1724  writer_printf(wctx, "\"type\": \"%s\"", section->name);
1725  wctx->nb_item[wctx->level]++;
1726  }
1727  }
1728  av_bprint_finalize(&buf, NULL);
1729  }
1730 }
1731 
1733 {
1734  JSONContext *json = wctx->priv;
1735  const struct section *section = wctx->section[wctx->level];
1736 
1737  if (wctx->level == 0) {
1738  json->indent_level--;
1739  writer_put_str(wctx, "\n}\n");
1740  } else if (section->flags & SECTION_FLAG_IS_ARRAY) {
1741  writer_w8(wctx, '\n');
1742  json->indent_level--;
1743  JSON_INDENT();
1744  writer_w8(wctx, ']');
1745  } else {
1746  writer_put_str(wctx, json->item_start_end);
1747  json->indent_level--;
1748  if (!json->compact)
1749  JSON_INDENT();
1750  writer_w8(wctx, '}');
1751  }
1752 }
1753 
1754 static inline void json_print_item_str(WriterContext *wctx,
1755  const char *key, const char *value)
1756 {
1757  AVBPrint buf;
1758 
1760  writer_printf(wctx, "\"%s\":", json_escape_str(&buf, key, wctx));
1761  av_bprint_clear(&buf);
1762  writer_printf(wctx, " \"%s\"", json_escape_str(&buf, value, wctx));
1763  av_bprint_finalize(&buf, NULL);
1764 }
1765 
1766 static void json_print_str(WriterContext *wctx, const char *key, const char *value)
1767 {
1768  JSONContext *json = wctx->priv;
1769  const struct section *parent_section = wctx->level ?
1770  wctx->section[wctx->level-1] : NULL;
1771 
1772  if (wctx->nb_item[wctx->level] || (parent_section && parent_section->id == SECTION_ID_PACKETS_AND_FRAMES))
1773  writer_put_str(wctx, json->item_sep);
1774  if (!json->compact)
1775  JSON_INDENT();
1776  json_print_item_str(wctx, key, value);
1777 }
1778 
1779 static void json_print_int(WriterContext *wctx, const char *key, int64_t value)
1780 {
1781  JSONContext *json = wctx->priv;
1782  const struct section *parent_section = wctx->level ?
1783  wctx->section[wctx->level-1] : NULL;
1784  AVBPrint buf;
1785 
1786  if (wctx->nb_item[wctx->level] || (parent_section && parent_section->id == SECTION_ID_PACKETS_AND_FRAMES))
1787  writer_put_str(wctx, json->item_sep);
1788  if (!json->compact)
1789  JSON_INDENT();
1790 
1792  writer_printf(wctx, "\"%s\": %"PRId64, json_escape_str(&buf, key, wctx), value);
1793  av_bprint_finalize(&buf, NULL);
1794 }
1795 
1796 static const Writer json_writer = {
1797  .name = "json",
1798  .priv_size = sizeof(JSONContext),
1799  .init = json_init,
1802  .print_integer = json_print_int,
1803  .print_string = json_print_str,
1805  .priv_class = &json_class,
1806 };
1807 
1808 /* XML output */
1809 
1810 typedef struct XMLContext {
1811  const AVClass *class;
1816 } XMLContext;
1817 
1818 #undef OFFSET
1819 #define OFFSET(x) offsetof(XMLContext, x)
1820 
1821 static const AVOption xml_options[] = {
1822  {"fully_qualified", "specify if the output should be fully qualified", OFFSET(fully_qualified), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
1823  {"q", "specify if the output should be fully qualified", OFFSET(fully_qualified), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
1824  {"xsd_strict", "ensure that the output is XSD compliant", OFFSET(xsd_strict), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
1825  {"x", "ensure that the output is XSD compliant", OFFSET(xsd_strict), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
1826  {NULL},
1827 };
1828 
1829 DEFINE_WRITER_CLASS(xml);
1830 
1831 static av_cold int xml_init(WriterContext *wctx)
1832 {
1833  XMLContext *xml = wctx->priv;
1834 
1835  if (xml->xsd_strict) {
1836  xml->fully_qualified = 1;
1837 #define CHECK_COMPLIANCE(opt, opt_name) \
1838  if (opt) { \
1839  av_log(wctx, AV_LOG_ERROR, \
1840  "XSD-compliant output selected but option '%s' was selected, XML output may be non-compliant.\n" \
1841  "You need to disable such option with '-no%s'\n", opt_name, opt_name); \
1842  return AVERROR(EINVAL); \
1843  }
1844  CHECK_COMPLIANCE(show_private_data, "private");
1847  }
1848 
1849  return 0;
1850 }
1851 
1852 #define XML_INDENT() writer_printf(wctx, "%*c", xml->indent_level * 4, ' ')
1853 
1854 static void xml_print_section_header(WriterContext *wctx, const void *data)
1855 {
1856  XMLContext *xml = wctx->priv;
1857  const struct section *section = wctx->section[wctx->level];
1858  const struct section *parent_section = wctx->level ?
1859  wctx->section[wctx->level-1] : NULL;
1860 
1861  if (wctx->level == 0) {
1862  const char *qual = " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
1863  "xmlns:ffprobe=\"http://www.ffmpeg.org/schema/ffprobe\" "
1864  "xsi:schemaLocation=\"http://www.ffmpeg.org/schema/ffprobe ffprobe.xsd\"";
1865 
1866  writer_put_str(wctx, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1867  writer_printf(wctx, "<%sffprobe%s>\n",
1868  xml->fully_qualified ? "ffprobe:" : "",
1869  xml->fully_qualified ? qual : "");
1870  return;
1871  }
1872 
1873  if (xml->within_tag) {
1874  xml->within_tag = 0;
1875  writer_put_str(wctx, ">\n");
1876  }
1877 
1878  if (parent_section && (parent_section->flags & SECTION_FLAG_IS_WRAPPER) &&
1879  wctx->level && wctx->nb_item[wctx->level-1])
1880  writer_w8(wctx, '\n');
1881  xml->indent_level++;
1882 
1884  XML_INDENT(); writer_printf(wctx, "<%s", section->name);
1885 
1887  AVBPrint buf;
1891  writer_printf(wctx, " type=\"%s\"", buf.str);
1892  }
1893  writer_printf(wctx, ">\n", section->name);
1894  } else {
1895  XML_INDENT(); writer_printf(wctx, "<%s ", section->name);
1896  xml->within_tag = 1;
1897  }
1898 }
1899 
1901 {
1902  XMLContext *xml = wctx->priv;
1903  const struct section *section = wctx->section[wctx->level];
1904 
1905  if (wctx->level == 0) {
1906  writer_printf(wctx, "</%sffprobe>\n", xml->fully_qualified ? "ffprobe:" : "");
1907  } else if (xml->within_tag) {
1908  xml->within_tag = 0;
1909  writer_put_str(wctx, "/>\n");
1910  xml->indent_level--;
1911  } else {
1912  XML_INDENT(); writer_printf(wctx, "</%s>\n", section->name);
1913  xml->indent_level--;
1914  }
1915 }
1916 
1917 static void xml_print_value(WriterContext *wctx, const char *key,
1918  const char *str, int64_t num, const int is_int)
1919 {
1920  AVBPrint buf;
1921  XMLContext *xml = wctx->priv;
1922  const struct section *section = wctx->section[wctx->level];
1923 
1925 
1927  xml->indent_level++;
1928  XML_INDENT();
1929  av_bprint_escape(&buf, key, NULL,
1931  writer_printf(wctx, "<%s key=\"%s\"",
1932  section->element_name, buf.str);
1933  av_bprint_clear(&buf);
1934 
1935  if (is_int) {
1936  writer_printf(wctx, " value=\"%"PRId64"\"/>\n", num);
1937  } else {
1938  av_bprint_escape(&buf, str, NULL,
1940  writer_printf(wctx, " value=\"%s\"/>\n", buf.str);
1941  }
1942  xml->indent_level--;
1943  } else {
1944  if (wctx->nb_item[wctx->level])
1945  writer_w8(wctx, ' ');
1946 
1947  if (is_int) {
1948  writer_printf(wctx, "%s=\"%"PRId64"\"", key, num);
1949  } else {
1950  av_bprint_escape(&buf, str, NULL,
1952  writer_printf(wctx, "%s=\"%s\"", key, buf.str);
1953  }
1954  }
1955 
1956  av_bprint_finalize(&buf, NULL);
1957 }
1958 
1959 static inline void xml_print_str(WriterContext *wctx, const char *key, const char *value) {
1960  xml_print_value(wctx, key, value, 0, 0);
1961 }
1962 
1963 static void xml_print_int(WriterContext *wctx, const char *key, int64_t value)
1964 {
1965  xml_print_value(wctx, key, NULL, value, 1);
1966 }
1967 
1968 static Writer xml_writer = {
1969  .name = "xml",
1970  .priv_size = sizeof(XMLContext),
1971  .init = xml_init,
1974  .print_integer = xml_print_int,
1975  .print_string = xml_print_str,
1977  .priv_class = &xml_class,
1978 };
1979 
1980 static void writer_register_all(void)
1981 {
1982  static int initialized;
1983 
1984  if (initialized)
1985  return;
1986  initialized = 1;
1987 
1995 }
1996 
1997 #define print_fmt(k, f, ...) do { \
1998  av_bprint_clear(&pbuf); \
1999  av_bprintf(&pbuf, f, __VA_ARGS__); \
2000  writer_print_string(w, k, pbuf.str, 0); \
2001 } while (0)
2002 
2003 #define print_list_fmt(k, f, n, m, ...) do { \
2004  av_bprint_clear(&pbuf); \
2005  for (int idx = 0; idx < n; idx++) { \
2006  for (int idx2 = 0; idx2 < m; idx2++) { \
2007  if (idx > 0 || idx2 > 0) \
2008  av_bprint_chars(&pbuf, ' ', 1); \
2009  av_bprintf(&pbuf, f, __VA_ARGS__); \
2010  } \
2011  } \
2012  writer_print_string(w, k, pbuf.str, 0); \
2013 } while (0)
2014 
2015 #define print_int(k, v) writer_print_integer(w, k, v)
2016 #define print_q(k, v, s) writer_print_rational(w, k, v, s)
2017 #define print_str(k, v) writer_print_string(w, k, v, 0)
2018 #define print_str_opt(k, v) writer_print_string(w, k, v, PRINT_STRING_OPT)
2019 #define print_str_validate(k, v) writer_print_string(w, k, v, PRINT_STRING_VALIDATE)
2020 #define print_time(k, v, tb) writer_print_time(w, k, v, tb, 0)
2021 #define print_ts(k, v) writer_print_ts(w, k, v, 0)
2022 #define print_duration_time(k, v, tb) writer_print_time(w, k, v, tb, 1)
2023 #define print_duration_ts(k, v) writer_print_ts(w, k, v, 1)
2024 #define print_val(k, v, u) do { \
2025  struct unit_value uv; \
2026  uv.val.i = v; \
2027  uv.unit = u; \
2028  writer_print_string(w, k, value_string(val_str, sizeof(val_str), uv), 0); \
2029 } while (0)
2030 
2031 #define print_section_header(s) writer_print_section_header(w, NULL, s)
2032 #define print_section_header_data(s, d) writer_print_section_header(w, d, s)
2033 #define print_section_footer(s) writer_print_section_footer(w, s)
2034 
2035 #define REALLOCZ_ARRAY_STREAM(ptr, cur_n, new_n) \
2036 { \
2037  ret = av_reallocp_array(&(ptr), (new_n), sizeof(*(ptr))); \
2038  if (ret < 0) \
2039  goto end; \
2040  memset( (ptr) + (cur_n), 0, ((new_n) - (cur_n)) * sizeof(*(ptr)) ); \
2041 }
2042 
2043 static inline int show_tags(WriterContext *w, AVDictionary *tags, int section_id)
2044 {
2045  const AVDictionaryEntry *tag = NULL;
2046  int ret = 0;
2047 
2048  if (!tags)
2049  return 0;
2050  writer_print_section_header(w, NULL, section_id);
2051 
2052  while ((tag = av_dict_iterate(tags, tag))) {
2053  if ((ret = print_str_validate(tag->key, tag->value)) < 0)
2054  break;
2055  }
2057 
2058  return ret;
2059 }
2060 
2062 {
2063  if (!dovi)
2064  return;
2065 
2066  {
2067  const AVDOVIRpuDataHeader *hdr = av_dovi_get_header(dovi);
2068  const AVDOVIDataMapping *mapping = av_dovi_get_mapping(dovi);
2070  AVBPrint pbuf;
2071 
2073 
2074  // header
2075  print_int("rpu_type", hdr->rpu_type);
2076  print_int("rpu_format", hdr->rpu_format);
2077  print_int("vdr_rpu_profile", hdr->vdr_rpu_profile);
2078  print_int("vdr_rpu_level", hdr->vdr_rpu_level);
2079  print_int("chroma_resampling_explicit_filter_flag",
2081  print_int("coef_data_type", hdr->coef_data_type);
2082  print_int("coef_log2_denom", hdr->coef_log2_denom);
2083  print_int("vdr_rpu_normalized_idc", hdr->vdr_rpu_normalized_idc);
2084  print_int("bl_video_full_range_flag", hdr->bl_video_full_range_flag);
2085  print_int("bl_bit_depth", hdr->bl_bit_depth);
2086  print_int("el_bit_depth", hdr->el_bit_depth);
2087  print_int("vdr_bit_depth", hdr->vdr_bit_depth);
2088  print_int("spatial_resampling_filter_flag",
2090  print_int("el_spatial_resampling_filter_flag",
2092  print_int("disable_residual_flag", hdr->disable_residual_flag);
2093 
2094  // data mapping values
2095  print_int("vdr_rpu_id", mapping->vdr_rpu_id);
2096  print_int("mapping_color_space", mapping->mapping_color_space);
2097  print_int("mapping_chroma_format_idc",
2098  mapping->mapping_chroma_format_idc);
2099 
2100  print_int("nlq_method_idc", mapping->nlq_method_idc);
2101  switch (mapping->nlq_method_idc) {
2102  case AV_DOVI_NLQ_NONE:
2103  print_str("nlq_method_idc_name", "none");
2104  break;
2105  case AV_DOVI_NLQ_LINEAR_DZ:
2106  print_str("nlq_method_idc_name", "linear_dz");
2107  break;
2108  default:
2109  print_str("nlq_method_idc_name", "unknown");
2110  break;
2111  }
2112 
2113  print_int("num_x_partitions", mapping->num_x_partitions);
2114  print_int("num_y_partitions", mapping->num_y_partitions);
2115 
2117 
2118  for (int c = 0; c < 3; c++) {
2119  const AVDOVIReshapingCurve *curve = &mapping->curves[c];
2121 
2122  print_list_fmt("pivots", "%"PRIu16, curve->num_pivots, 1, curve->pivots[idx]);
2123 
2125  for (int i = 0; i < curve->num_pivots - 1; i++) {
2126  AVBPrint piece_buf;
2127 
2128  av_bprint_init(&piece_buf, 0, AV_BPRINT_SIZE_AUTOMATIC);
2129  switch (curve->mapping_idc[i]) {
2131  av_bprintf(&piece_buf, "Polynomial");
2132  break;
2133  case AV_DOVI_MAPPING_MMR:
2134  av_bprintf(&piece_buf, "MMR");
2135  break;
2136  default:
2137  av_bprintf(&piece_buf, "Unknown");
2138  break;
2139  }
2140  av_bprintf(&piece_buf, " mapping");
2141 
2143  print_int("mapping_idc", curve->mapping_idc[i]);
2144  switch (curve->mapping_idc[i]) {
2146  print_str("mapping_idc_name", "polynomial");
2147  print_int("poly_order", curve->poly_order[i]);
2148  print_list_fmt("poly_coef", "%"PRIi64,
2149  curve->poly_order[i] + 1, 1,
2150  curve->poly_coef[i][idx]);
2151  break;
2152  case AV_DOVI_MAPPING_MMR:
2153  print_str("mapping_idc_name", "mmr");
2154  print_int("mmr_order", curve->mmr_order[i]);
2155  print_int("mmr_constant", curve->mmr_constant[i]);
2156  print_list_fmt("mmr_coef", "%"PRIi64,
2157  curve->mmr_order[i], 7,
2158  curve->mmr_coef[i][idx][idx2]);
2159  break;
2160  default:
2161  print_str("mapping_idc_name", "unknown");
2162  break;
2163  }
2164 
2165  // SECTION_ID_FRAME_SIDE_DATA_PIECE
2167  }
2168 
2169  // SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST
2171 
2172  if (mapping->nlq_method_idc != AV_DOVI_NLQ_NONE) {
2173  const AVDOVINLQParams *nlq = &mapping->nlq[c];
2174  print_int("nlq_offset", nlq->nlq_offset);
2175  print_int("vdr_in_max", nlq->vdr_in_max);
2176 
2177  switch (mapping->nlq_method_idc) {
2178  case AV_DOVI_NLQ_LINEAR_DZ:
2179  print_int("linear_deadzone_slope", nlq->linear_deadzone_slope);
2180  print_int("linear_deadzone_threshold", nlq->linear_deadzone_threshold);
2181  break;
2182  }
2183  }
2184 
2185  // SECTION_ID_FRAME_SIDE_DATA_COMPONENT
2187  }
2188 
2189  // SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST
2191 
2192  // color metadata
2193  print_int("dm_metadata_id", color->dm_metadata_id);
2194  print_int("scene_refresh_flag", color->scene_refresh_flag);
2195  print_list_fmt("ycc_to_rgb_matrix", "%d/%d",
2196  FF_ARRAY_ELEMS(color->ycc_to_rgb_matrix), 1,
2197  color->ycc_to_rgb_matrix[idx].num,
2198  color->ycc_to_rgb_matrix[idx].den);
2199  print_list_fmt("ycc_to_rgb_offset", "%d/%d",
2200  FF_ARRAY_ELEMS(color->ycc_to_rgb_offset), 1,
2201  color->ycc_to_rgb_offset[idx].num,
2202  color->ycc_to_rgb_offset[idx].den);
2203  print_list_fmt("rgb_to_lms_matrix", "%d/%d",
2204  FF_ARRAY_ELEMS(color->rgb_to_lms_matrix), 1,
2205  color->rgb_to_lms_matrix[idx].num,
2206  color->rgb_to_lms_matrix[idx].den);
2207  print_int("signal_eotf", color->signal_eotf);
2208  print_int("signal_eotf_param0", color->signal_eotf_param0);
2209  print_int("signal_eotf_param1", color->signal_eotf_param1);
2210  print_int("signal_eotf_param2", color->signal_eotf_param2);
2211  print_int("signal_bit_depth", color->signal_bit_depth);
2212  print_int("signal_color_space", color->signal_color_space);
2213  print_int("signal_chroma_format", color->signal_chroma_format);
2214  print_int("signal_full_range_flag", color->signal_full_range_flag);
2215  print_int("source_min_pq", color->source_min_pq);
2216  print_int("source_max_pq", color->source_max_pq);
2217  print_int("source_diagonal", color->source_diagonal);
2218 
2219  av_bprint_finalize(&pbuf, NULL);
2220  }
2221 }
2222 
2224 {
2225  if (!metadata)
2226  return;
2227  print_int("application version", metadata->application_version);
2228  print_int("num_windows", metadata->num_windows);
2229  for (int n = 1; n < metadata->num_windows; n++) {
2230  const AVHDRPlusColorTransformParams *params = &metadata->params[n];
2231  print_q("window_upper_left_corner_x",
2232  params->window_upper_left_corner_x,'/');
2233  print_q("window_upper_left_corner_y",
2234  params->window_upper_left_corner_y,'/');
2235  print_q("window_lower_right_corner_x",
2236  params->window_lower_right_corner_x,'/');
2237  print_q("window_lower_right_corner_y",
2238  params->window_lower_right_corner_y,'/');
2239  print_q("window_upper_left_corner_x",
2240  params->window_upper_left_corner_x,'/');
2241  print_q("window_upper_left_corner_y",
2242  params->window_upper_left_corner_y,'/');
2243  print_int("center_of_ellipse_x",
2244  params->center_of_ellipse_x ) ;
2245  print_int("center_of_ellipse_y",
2246  params->center_of_ellipse_y );
2247  print_int("rotation_angle",
2248  params->rotation_angle);
2249  print_int("semimajor_axis_internal_ellipse",
2251  print_int("semimajor_axis_external_ellipse",
2253  print_int("semiminor_axis_external_ellipse",
2255  print_int("overlap_process_option",
2256  params->overlap_process_option);
2257  }
2258  print_q("targeted_system_display_maximum_luminance",
2261  print_int("num_rows_targeted_system_display_actual_peak_luminance",
2263  print_int("num_cols_targeted_system_display_actual_peak_luminance",
2265  for (int i = 0; i < metadata->num_rows_targeted_system_display_actual_peak_luminance; i++) {
2266  for (int j = 0; j < metadata->num_cols_targeted_system_display_actual_peak_luminance; j++) {
2267  print_q("targeted_system_display_actual_peak_luminance",
2269  }
2270  }
2271  }
2272  for (int n = 0; n < metadata->num_windows; n++) {
2273  const AVHDRPlusColorTransformParams *params = &metadata->params[n];
2274  for (int i = 0; i < 3; i++) {
2275  print_q("maxscl",params->maxscl[i],'/');
2276  }
2277  print_q("average_maxrgb",
2278  params->average_maxrgb,'/');
2279  print_int("num_distribution_maxrgb_percentiles",
2281  for (int i = 0; i < params->num_distribution_maxrgb_percentiles; i++) {
2282  print_int("distribution_maxrgb_percentage",
2283  params->distribution_maxrgb[i].percentage);
2284  print_q("distribution_maxrgb_percentile",
2285  params->distribution_maxrgb[i].percentile,'/');
2286  }
2287  print_q("fraction_bright_pixels",
2288  params->fraction_bright_pixels,'/');
2289  }
2291  print_int("num_rows_mastering_display_actual_peak_luminance",
2293  print_int("num_cols_mastering_display_actual_peak_luminance",
2295  for (int i = 0; i < metadata->num_rows_mastering_display_actual_peak_luminance; i++) {
2296  for (int j = 0; j < metadata->num_cols_mastering_display_actual_peak_luminance; j++) {
2297  print_q("mastering_display_actual_peak_luminance",
2298  metadata->mastering_display_actual_peak_luminance[i][j],'/');
2299  }
2300  }
2301  }
2302 
2303  for (int n = 0; n < metadata->num_windows; n++) {
2304  const AVHDRPlusColorTransformParams *params = &metadata->params[n];
2305  if (params->tone_mapping_flag) {
2306  print_q("knee_point_x", params->knee_point_x,'/');
2307  print_q("knee_point_y", params->knee_point_y,'/');
2308  print_int("num_bezier_curve_anchors",
2309  params->num_bezier_curve_anchors );
2310  for (int i = 0; i < params->num_bezier_curve_anchors; i++) {
2311  print_q("bezier_curve_anchors",
2312  params->bezier_curve_anchors[i],'/');
2313  }
2314  }
2315  if (params->color_saturation_mapping_flag) {
2316  print_q("color_saturation_weight",
2317  params->color_saturation_weight,'/');
2318  }
2319  }
2320 }
2321 
2323 {
2324  if (!metadata)
2325  return;
2326  print_int("system_start_code", metadata->system_start_code);
2327  print_int("num_windows", metadata->num_windows);
2328 
2329  for (int n = 0; n < metadata->num_windows; n++) {
2330  const AVHDRVividColorTransformParams *params = &metadata->params[n];
2331 
2332  print_q("minimum_maxrgb", params->minimum_maxrgb, '/');
2333  print_q("average_maxrgb", params->average_maxrgb, '/');
2334  print_q("variance_maxrgb", params->variance_maxrgb, '/');
2335  print_q("maximum_maxrgb", params->maximum_maxrgb, '/');
2336  }
2337 
2338  for (int n = 0; n < metadata->num_windows; n++) {
2339  const AVHDRVividColorTransformParams *params = &metadata->params[n];
2340 
2341  print_int("tone_mapping_mode_flag", params->tone_mapping_mode_flag);
2342  if (params->tone_mapping_mode_flag) {
2343  print_int("tone_mapping_param_num", params->tone_mapping_param_num);
2344  for (int i = 0; i < params->tone_mapping_param_num; i++) {
2345  const AVHDRVividColorToneMappingParams *tm_params = &params->tm_params[i];
2346 
2347  print_q("targeted_system_display_maximum_luminance",
2349  print_int("base_enable_flag", tm_params->base_enable_flag);
2350  if (tm_params->base_enable_flag) {
2351  print_q("base_param_m_p", tm_params->base_param_m_p, '/');
2352  print_q("base_param_m_m", tm_params->base_param_m_m, '/');
2353  print_q("base_param_m_a", tm_params->base_param_m_a, '/');
2354  print_q("base_param_m_b", tm_params->base_param_m_b, '/');
2355  print_q("base_param_m_n", tm_params->base_param_m_n, '/');
2356 
2357  print_int("base_param_k1", tm_params->base_param_k1);
2358  print_int("base_param_k2", tm_params->base_param_k2);
2359  print_int("base_param_k3", tm_params->base_param_k3);
2360  print_int("base_param_Delta_enable_mode",
2361  tm_params->base_param_Delta_enable_mode);
2362  print_q("base_param_Delta", tm_params->base_param_Delta, '/');
2363  }
2364  print_int("3Spline_enable_flag", tm_params->three_Spline_enable_flag);
2365  if (tm_params->three_Spline_enable_flag) {
2366  print_int("3Spline_num", tm_params->three_Spline_num);
2367 
2368  for (int j = 0; j < tm_params->three_Spline_num; j++) {
2369  const AVHDRVivid3SplineParams *three_spline = &tm_params->three_spline[j];
2370  print_int("3Spline_TH_mode", three_spline->th_mode);
2371  if (three_spline->th_mode == 0 || three_spline->th_mode == 2)
2372  print_q("3Spline_TH_enable_MB", three_spline->th_enable_mb, '/');
2373  print_q("3Spline_TH_enable", three_spline->th_enable, '/');
2374  print_q("3Spline_TH_Delta1", three_spline->th_delta1, '/');
2375  print_q("3Spline_TH_Delta2", three_spline->th_delta2, '/');
2376  print_q("3Spline_enable_Strength", three_spline->enable_strength, '/');
2377  }
2378  }
2379  }
2380  }
2381 
2382  print_int("color_saturation_mapping_flag", params->color_saturation_mapping_flag);
2383  if (params->color_saturation_mapping_flag) {
2384  print_int("color_saturation_num", params->color_saturation_num);
2385  for (int i = 0; i < params->color_saturation_num; i++) {
2386  print_q("color_saturation_gain", params->color_saturation_gain[i], '/');
2387  }
2388  }
2389  }
2390 }
2391 
2393  const AVAmbientViewingEnvironment *env)
2394 {
2395  if (!env)
2396  return;
2397 
2398  print_q("ambient_illuminance", env->ambient_illuminance, '/');
2399  print_q("ambient_light_x", env->ambient_light_x, '/');
2400  print_q("ambient_light_y", env->ambient_light_y, '/');
2401 }
2402 
2404  const AVFilmGrainParams *fgp)
2405 {
2406  const char *color_range, *color_primaries, *color_trc, *color_space;
2407  const char *const film_grain_type_names[] = {
2408  [AV_FILM_GRAIN_PARAMS_NONE] = "none",
2409  [AV_FILM_GRAIN_PARAMS_AV1] = "av1",
2410  [AV_FILM_GRAIN_PARAMS_H274] = "h274",
2411  };
2412 
2413  AVBPrint pbuf;
2414  if (!fgp || fgp->type >= FF_ARRAY_ELEMS(film_grain_type_names))
2415  return;
2416 
2419  color_trc = av_color_transfer_name(fgp->color_trc);
2420  color_space = av_color_space_name(fgp->color_space);
2421 
2423  print_str("type", film_grain_type_names[fgp->type]);
2424  print_fmt("seed", "%"PRIu64, fgp->seed);
2425  print_int("width", fgp->width);
2426  print_int("height", fgp->height);
2427  print_int("subsampling_x", fgp->subsampling_x);
2428  print_int("subsampling_y", fgp->subsampling_y);
2429  print_str("color_range", color_range ? color_range : "unknown");
2430  print_str("color_primaries", color_primaries ? color_primaries : "unknown");
2431  print_str("color_trc", color_trc ? color_trc : "unknown");
2432  print_str("color_space", color_space ? color_space : "unknown");
2433 
2434  switch (fgp->type) {
2436  break;
2437  case AV_FILM_GRAIN_PARAMS_AV1: {
2438  const AVFilmGrainAOMParams *aom = &fgp->codec.aom;
2439  const int num_ar_coeffs_y = 2 * aom->ar_coeff_lag * (aom->ar_coeff_lag + 1);
2440  const int num_ar_coeffs_uv = num_ar_coeffs_y + !!aom->num_y_points;
2441  print_int("chroma_scaling_from_luma", aom->chroma_scaling_from_luma);
2442  print_int("scaling_shift", aom->scaling_shift);
2443  print_int("ar_coeff_lag", aom->ar_coeff_lag);
2444  print_int("ar_coeff_shift", aom->ar_coeff_shift);
2445  print_int("grain_scale_shift", aom->grain_scale_shift);
2446  print_int("overlap_flag", aom->overlap_flag);
2447  print_int("limit_output_range", aom->limit_output_range);
2448 
2450 
2451  if (aom->num_y_points) {
2453 
2454  print_int("bit_depth_luma", fgp->bit_depth_luma);
2455  print_list_fmt("y_points_value", "%"PRIu8, aom->num_y_points, 1, aom->y_points[idx][0]);
2456  print_list_fmt("y_points_scaling", "%"PRIu8, aom->num_y_points, 1, aom->y_points[idx][1]);
2457  print_list_fmt("ar_coeffs_y", "%"PRId8, num_ar_coeffs_y, 1, aom->ar_coeffs_y[idx]);
2458 
2459  // SECTION_ID_FRAME_SIDE_DATA_COMPONENT
2461  }
2462 
2463  for (int uv = 0; uv < 2; uv++) {
2464  if (!aom->num_uv_points[uv] && !aom->chroma_scaling_from_luma)
2465  continue;
2466 
2468 
2469  print_int("bit_depth_chroma", fgp->bit_depth_chroma);
2470  print_list_fmt("uv_points_value", "%"PRIu8, aom->num_uv_points[uv], 1, aom->uv_points[uv][idx][0]);
2471  print_list_fmt("uv_points_scaling", "%"PRIu8, aom->num_uv_points[uv], 1, aom->uv_points[uv][idx][1]);
2472  print_list_fmt("ar_coeffs_uv", "%"PRId8, num_ar_coeffs_uv, 1, aom->ar_coeffs_uv[uv][idx]);
2473  print_int("uv_mult", aom->uv_mult[uv]);
2474  print_int("uv_mult_luma", aom->uv_mult_luma[uv]);
2475  print_int("uv_offset", aom->uv_offset[uv]);
2476 
2477  // SECTION_ID_FRAME_SIDE_DATA_COMPONENT
2479  }
2480 
2481  // SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST
2483  break;
2484  }
2486  const AVFilmGrainH274Params *h274 = &fgp->codec.h274;
2487  print_int("model_id", h274->model_id);
2488  print_int("blending_mode_id", h274->blending_mode_id);
2489  print_int("log2_scale_factor", h274->log2_scale_factor);
2490 
2492 
2493  for (int c = 0; c < 3; c++) {
2494  if (!h274->component_model_present[c])
2495  continue;
2496 
2498  print_int(c ? "bit_depth_chroma" : "bit_depth_luma", c ? fgp->bit_depth_chroma : fgp->bit_depth_luma);
2499 
2501  for (int i = 0; i < h274->num_intensity_intervals[c]; i++) {
2502 
2504  print_int("intensity_interval_lower_bound", h274->intensity_interval_lower_bound[c][i]);
2505  print_int("intensity_interval_upper_bound", h274->intensity_interval_upper_bound[c][i]);
2506  print_list_fmt("comp_model_value", "%"PRId16, h274->num_model_values[c], 1, h274->comp_model_value[c][i][idx]);
2507 
2508  // SECTION_ID_FRAME_SIDE_DATA_PIECE
2510  }
2511 
2512  // SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST
2514 
2515  // SECTION_ID_FRAME_SIDE_DATA_COMPONENT
2517  }
2518 
2519  // SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST
2521  break;
2522  }
2523  }
2524 
2525  av_bprint_finalize(&pbuf, NULL);
2526 }
2527 
2529  AVCodecParameters *par,
2530  const AVPacketSideData *sd,
2531  SectionID id_data)
2532 {
2533  const char *name = av_packet_side_data_name(sd->type);
2534 
2535  writer_print_section_header(w, sd, id_data);
2536  print_str("side_data_type", name ? name : "unknown");
2537  if (sd->type == AV_PKT_DATA_DISPLAYMATRIX && sd->size >= 9*4) {
2538  double rotation = av_display_rotation_get((int32_t *)sd->data);
2539  if (isnan(rotation))
2540  rotation = 0;
2541  writer_print_integers(w, "displaymatrix", sd->data, 9, " %11d", 3, 4, 1);
2542  print_int("rotation", rotation);
2543  } else if (sd->type == AV_PKT_DATA_STEREO3D) {
2544  const AVStereo3D *stereo = (AVStereo3D *)sd->data;
2545  print_str("type", av_stereo3d_type_name(stereo->type));
2546  print_int("inverted", !!(stereo->flags & AV_STEREO3D_FLAG_INVERT));
2547  print_str("view", av_stereo3d_view_name(stereo->view));
2548  print_str("primary_eye", av_stereo3d_primary_eye_name(stereo->primary_eye));
2549  print_int("baseline", stereo->baseline);
2550  print_q("horizontal_disparity_adjustment", stereo->horizontal_disparity_adjustment, '/');
2551  print_q("horizontal_field_of_view", stereo->horizontal_field_of_view, '/');
2552  } else if (sd->type == AV_PKT_DATA_SPHERICAL) {
2553  const AVSphericalMapping *spherical = (AVSphericalMapping *)sd->data;
2554  print_str("projection", av_spherical_projection_name(spherical->projection));
2555  if (spherical->projection == AV_SPHERICAL_CUBEMAP) {
2556  print_int("padding", spherical->padding);
2557  } else if (spherical->projection == AV_SPHERICAL_EQUIRECTANGULAR_TILE) {
2558  size_t l, t, r, b;
2559  av_spherical_tile_bounds(spherical, par->width, par->height,
2560  &l, &t, &r, &b);
2561  print_int("bound_left", l);
2562  print_int("bound_top", t);
2563  print_int("bound_right", r);
2564  print_int("bound_bottom", b);
2565  }
2566 
2567  print_int("yaw", (double) spherical->yaw / (1 << 16));
2568  print_int("pitch", (double) spherical->pitch / (1 << 16));
2569  print_int("roll", (double) spherical->roll / (1 << 16));
2570  } else if (sd->type == AV_PKT_DATA_SKIP_SAMPLES && sd->size == 10) {
2571  print_int("skip_samples", AV_RL32(sd->data));
2572  print_int("discard_padding", AV_RL32(sd->data + 4));
2573  print_int("skip_reason", AV_RL8(sd->data + 8));
2574  print_int("discard_reason", AV_RL8(sd->data + 9));
2575  } else if (sd->type == AV_PKT_DATA_MASTERING_DISPLAY_METADATA) {
2577 
2578  if (metadata->has_primaries) {
2579  print_q("red_x", metadata->display_primaries[0][0], '/');
2580  print_q("red_y", metadata->display_primaries[0][1], '/');
2581  print_q("green_x", metadata->display_primaries[1][0], '/');
2582  print_q("green_y", metadata->display_primaries[1][1], '/');
2583  print_q("blue_x", metadata->display_primaries[2][0], '/');
2584  print_q("blue_y", metadata->display_primaries[2][1], '/');
2585 
2586  print_q("white_point_x", metadata->white_point[0], '/');
2587  print_q("white_point_y", metadata->white_point[1], '/');
2588  }
2589 
2590  if (metadata->has_luminance) {
2591  print_q("min_luminance", metadata->min_luminance, '/');
2592  print_q("max_luminance", metadata->max_luminance, '/');
2593  }
2594  } else if (sd->type == AV_PKT_DATA_CONTENT_LIGHT_LEVEL) {
2596  print_int("max_content", metadata->MaxCLL);
2597  print_int("max_average", metadata->MaxFALL);
2598  } else if (sd->type == AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT) {
2600  w, (const AVAmbientViewingEnvironment *)sd->data);
2601  } else if (sd->type == AV_PKT_DATA_DYNAMIC_HDR10_PLUS) {
2602  AVDynamicHDRPlus *metadata = (AVDynamicHDRPlus *)sd->data;
2603  print_dynamic_hdr10_plus(w, metadata);
2604  } else if (sd->type == AV_PKT_DATA_DOVI_CONF) {
2606  const char *comp = "unknown";
2607  print_int("dv_version_major", dovi->dv_version_major);
2608  print_int("dv_version_minor", dovi->dv_version_minor);
2609  print_int("dv_profile", dovi->dv_profile);
2610  print_int("dv_level", dovi->dv_level);
2611  print_int("rpu_present_flag", dovi->rpu_present_flag);
2612  print_int("el_present_flag", dovi->el_present_flag);
2613  print_int("bl_present_flag", dovi->bl_present_flag);
2614  print_int("dv_bl_signal_compatibility_id", dovi->dv_bl_signal_compatibility_id);
2615  switch (dovi->dv_md_compression)
2616  {
2617  case AV_DOVI_COMPRESSION_NONE: comp = "none"; break;
2618  case AV_DOVI_COMPRESSION_LIMITED: comp = "limited"; break;
2619  case AV_DOVI_COMPRESSION_RESERVED: comp = "reserved"; break;
2620  case AV_DOVI_COMPRESSION_EXTENDED: comp = "extended"; break;
2621  }
2622  print_str("dv_md_compression", comp);
2623  } else if (sd->type == AV_PKT_DATA_AUDIO_SERVICE_TYPE) {
2624  enum AVAudioServiceType *t = (enum AVAudioServiceType *)sd->data;
2625  print_int("service_type", *t);
2626  } else if (sd->type == AV_PKT_DATA_MPEGTS_STREAM_ID) {
2627  print_int("id", *sd->data);
2628  } else if (sd->type == AV_PKT_DATA_CPB_PROPERTIES) {
2629  const AVCPBProperties *prop = (AVCPBProperties *)sd->data;
2630  print_int("max_bitrate", prop->max_bitrate);
2631  print_int("min_bitrate", prop->min_bitrate);
2632  print_int("avg_bitrate", prop->avg_bitrate);
2633  print_int("buffer_size", prop->buffer_size);
2634  print_int("vbv_delay", prop->vbv_delay);
2635  } else if (sd->type == AV_PKT_DATA_WEBVTT_IDENTIFIER ||
2637  if (do_show_data)
2638  writer_print_data(w, "data", sd->data, sd->size);
2639  writer_print_data_hash(w, "data_hash", sd->data, sd->size);
2640  } else if (sd->type == AV_PKT_DATA_FRAME_CROPPING && sd->size >= sizeof(uint32_t) * 4) {
2641  print_int("crop_top", AV_RL32(sd->data));
2642  print_int("crop_bottom", AV_RL32(sd->data + 4));
2643  print_int("crop_left", AV_RL32(sd->data + 8));
2644  print_int("crop_right", AV_RL32(sd->data + 12));
2645  } else if (sd->type == AV_PKT_DATA_AFD && sd->size > 0) {
2646  print_int("active_format", *sd->data);
2647  }
2648 }
2649 
2650 static void print_private_data(WriterContext *w, void *priv_data)
2651 {
2652  const AVOption *opt = NULL;
2653  while (opt = av_opt_next(priv_data, opt)) {
2654  uint8_t *str;
2655  if (!(opt->flags & AV_OPT_FLAG_EXPORT)) continue;
2656  if (av_opt_get(priv_data, opt->name, 0, &str) >= 0) {
2657  print_str(opt->name, str);
2658  av_free(str);
2659  }
2660  }
2661 }
2662 
2664 {
2665  const char *val = av_color_range_name(color_range);
2667  print_str_opt("color_range", "unknown");
2668  } else {
2669  print_str("color_range", val);
2670  }
2671 }
2672 
2673 static void print_color_space(WriterContext *w, enum AVColorSpace color_space)
2674 {
2675  const char *val = av_color_space_name(color_space);
2676  if (!val || color_space == AVCOL_SPC_UNSPECIFIED) {
2677  print_str_opt("color_space", "unknown");
2678  } else {
2679  print_str("color_space", val);
2680  }
2681 }
2682 
2684 {
2687  print_str_opt("color_primaries", "unknown");
2688  } else {
2689  print_str("color_primaries", val);
2690  }
2691 }
2692 
2694 {
2695  const char *val = av_color_transfer_name(color_trc);
2696  if (!val || color_trc == AVCOL_TRC_UNSPECIFIED) {
2697  print_str_opt("color_transfer", "unknown");
2698  } else {
2699  print_str("color_transfer", val);
2700  }
2701 }
2702 
2703 static void print_chroma_location(WriterContext *w, enum AVChromaLocation chroma_location)
2704 {
2705  const char *val = av_chroma_location_name(chroma_location);
2706  if (!val || chroma_location == AVCHROMA_LOC_UNSPECIFIED) {
2707  print_str_opt("chroma_location", "unspecified");
2708  } else {
2709  print_str("chroma_location", val);
2710  }
2711 }
2712 
2713 static void clear_log(int need_lock)
2714 {
2715  int i;
2716 
2717  if (need_lock)
2718  pthread_mutex_lock(&log_mutex);
2719  for (i=0; i<log_buffer_size; i++) {
2720  av_freep(&log_buffer[i].context_name);
2721  av_freep(&log_buffer[i].parent_name);
2722  av_freep(&log_buffer[i].log_message);
2723  }
2724  log_buffer_size = 0;
2725  if(need_lock)
2726  pthread_mutex_unlock(&log_mutex);
2727 }
2728 
2729 static int show_log(WriterContext *w, int section_ids, int section_id, int log_level)
2730 {
2731  int i;
2732  pthread_mutex_lock(&log_mutex);
2733  if (!log_buffer_size) {
2734  pthread_mutex_unlock(&log_mutex);
2735  return 0;
2736  }
2737  writer_print_section_header(w, NULL, section_ids);
2738 
2739  for (i=0; i<log_buffer_size; i++) {
2740  if (log_buffer[i].log_level <= log_level) {
2741  writer_print_section_header(w, NULL, section_id);
2742  print_str("context", log_buffer[i].context_name);
2743  print_int("level", log_buffer[i].log_level);
2744  print_int("category", log_buffer[i].category);
2745  if (log_buffer[i].parent_name) {
2746  print_str("parent_context", log_buffer[i].parent_name);
2747  print_int("parent_category", log_buffer[i].parent_category);
2748  } else {
2749  print_str_opt("parent_context", "N/A");
2750  print_str_opt("parent_category", "N/A");
2751  }
2752  print_str("message", log_buffer[i].log_message);
2754  }
2755  }
2756  clear_log(0);
2757  pthread_mutex_unlock(&log_mutex);
2758 
2760 
2761  return 0;
2762 }
2763 
2764 static void show_packet(WriterContext *w, InputFile *ifile, AVPacket *pkt, int packet_idx)
2765 {
2766  char val_str[128];
2767  AVStream *st = ifile->streams[pkt->stream_index].st;
2768  AVBPrint pbuf;
2769  const char *s;
2770 
2772 
2774 
2776  if (s) print_str ("codec_type", s);
2777  else print_str_opt("codec_type", "unknown");
2778  print_int("stream_index", pkt->stream_index);
2779  print_ts ("pts", pkt->pts);
2780  print_time("pts_time", pkt->pts, &st->time_base);
2781  print_ts ("dts", pkt->dts);
2782  print_time("dts_time", pkt->dts, &st->time_base);
2783  print_duration_ts("duration", pkt->duration);
2784  print_duration_time("duration_time", pkt->duration, &st->time_base);
2785  print_val("size", pkt->size, unit_byte_str);
2786  if (pkt->pos != -1) print_fmt ("pos", "%"PRId64, pkt->pos);
2787  else print_str_opt("pos", "N/A");
2788  print_fmt("flags", "%c%c%c", pkt->flags & AV_PKT_FLAG_KEY ? 'K' : '_',
2789  pkt->flags & AV_PKT_FLAG_DISCARD ? 'D' : '_',
2790  pkt->flags & AV_PKT_FLAG_CORRUPT ? 'C' : '_');
2791  if (do_show_data)
2792  writer_print_data(w, "data", pkt->data, pkt->size);
2793  writer_print_data_hash(w, "data_hash", pkt->data, pkt->size);
2794 
2795  if (pkt->side_data_elems) {
2796  size_t size;
2797  const uint8_t *side_metadata;
2798 
2800  if (side_metadata && size && do_show_packet_tags) {
2801  AVDictionary *dict = NULL;
2802  if (av_packet_unpack_dictionary(side_metadata, size, &dict) >= 0)
2804  av_dict_free(&dict);
2805  }
2806 
2808  for (int i = 0; i < pkt->side_data_elems; i++) {
2812  }
2814  }
2815 
2817 
2818  av_bprint_finalize(&pbuf, NULL);
2819  fflush(stdout);
2820 }
2821 
2822 static void show_subtitle(WriterContext *w, AVSubtitle *sub, AVStream *stream,
2824 {
2825  AVBPrint pbuf;
2826 
2828 
2830 
2831  print_str ("media_type", "subtitle");
2832  print_ts ("pts", sub->pts);
2833  print_time("pts_time", sub->pts, &AV_TIME_BASE_Q);
2834  print_int ("format", sub->format);
2835  print_int ("start_display_time", sub->start_display_time);
2836  print_int ("end_display_time", sub->end_display_time);
2837  print_int ("num_rects", sub->num_rects);
2838 
2840 
2841  av_bprint_finalize(&pbuf, NULL);
2842  fflush(stdout);
2843 }
2844 
2846  const AVFrame *frame,
2847  const AVStream *stream)
2848 {
2850 
2851  for (int i = 0; i < frame->nb_side_data; i++) {
2852  const AVFrameSideData *sd = frame->side_data[i];
2853  const char *name;
2854 
2857  print_str("side_data_type", name ? name : "unknown");
2858  if (sd->type == AV_FRAME_DATA_DISPLAYMATRIX && sd->size >= 9*4) {
2859  double rotation = av_display_rotation_get((int32_t *)sd->data);
2860  if (isnan(rotation))
2861  rotation = 0;
2862  writer_print_integers(w, "displaymatrix", sd->data, 9, " %11d", 3, 4, 1);
2863  print_int("rotation", rotation);
2864  } else if (sd->type == AV_FRAME_DATA_AFD && sd->size > 0) {
2865  print_int("active_format", *sd->data);
2866  } else if (sd->type == AV_FRAME_DATA_GOP_TIMECODE && sd->size >= 8) {
2867  char tcbuf[AV_TIMECODE_STR_SIZE];
2868  av_timecode_make_mpeg_tc_string(tcbuf, *(int64_t *)(sd->data));
2869  print_str("timecode", tcbuf);
2870  } else if (sd->type == AV_FRAME_DATA_S12M_TIMECODE && sd->size == 16) {
2871  uint32_t *tc = (uint32_t*)sd->data;
2872  int m = FFMIN(tc[0],3);
2874  for (int j = 1; j <= m ; j++) {
2875  char tcbuf[AV_TIMECODE_STR_SIZE];
2876  av_timecode_make_smpte_tc_string2(tcbuf, stream->avg_frame_rate, tc[j], 0, 0);
2878  print_str("value", tcbuf);
2880  }
2882  } else if (sd->type == AV_FRAME_DATA_MASTERING_DISPLAY_METADATA) {
2884 
2885  if (metadata->has_primaries) {
2886  print_q("red_x", metadata->display_primaries[0][0], '/');
2887  print_q("red_y", metadata->display_primaries[0][1], '/');
2888  print_q("green_x", metadata->display_primaries[1][0], '/');
2889  print_q("green_y", metadata->display_primaries[1][1], '/');
2890  print_q("blue_x", metadata->display_primaries[2][0], '/');
2891  print_q("blue_y", metadata->display_primaries[2][1], '/');
2892 
2893  print_q("white_point_x", metadata->white_point[0], '/');
2894  print_q("white_point_y", metadata->white_point[1], '/');
2895  }
2896 
2897  if (metadata->has_luminance) {
2898  print_q("min_luminance", metadata->min_luminance, '/');
2899  print_q("max_luminance", metadata->max_luminance, '/');
2900  }
2901  } else if (sd->type == AV_FRAME_DATA_DYNAMIC_HDR_PLUS) {
2902  AVDynamicHDRPlus *metadata = (AVDynamicHDRPlus *)sd->data;
2903  print_dynamic_hdr10_plus(w, metadata);
2904  } else if (sd->type == AV_FRAME_DATA_CONTENT_LIGHT_LEVEL) {
2906  print_int("max_content", metadata->MaxCLL);
2907  print_int("max_average", metadata->MaxFALL);
2908  } else if (sd->type == AV_FRAME_DATA_ICC_PROFILE) {
2910  if (tag)
2911  print_str(tag->key, tag->value);
2912  print_int("size", sd->size);
2913  } else if (sd->type == AV_FRAME_DATA_DOVI_METADATA) {
2914  print_dovi_metadata(w, (const AVDOVIMetadata *)sd->data);
2915  } else if (sd->type == AV_FRAME_DATA_DYNAMIC_HDR_VIVID) {
2916  AVDynamicHDRVivid *metadata = (AVDynamicHDRVivid *)sd->data;
2917  print_dynamic_hdr_vivid(w, metadata);
2918  } else if (sd->type == AV_FRAME_DATA_AMBIENT_VIEWING_ENVIRONMENT) {
2920  } else if (sd->type == AV_FRAME_DATA_FILM_GRAIN_PARAMS) {
2922  print_film_grain_params(w, fgp);
2923  } else if (sd->type == AV_FRAME_DATA_VIEW_ID) {
2924  print_int("view_id", *(int*)sd->data);
2925  }
2927  }
2929 }
2930 
2933 {
2934  FrameData *fd = frame->opaque_ref ? (FrameData*)frame->opaque_ref->data : NULL;
2935  AVBPrint pbuf;
2936  char val_str[128];
2937  const char *s;
2938 
2940 
2942 
2944  if (s) print_str ("media_type", s);
2945  else print_str_opt("media_type", "unknown");
2946  print_int("stream_index", stream->index);
2947  print_int("key_frame", !!(frame->flags & AV_FRAME_FLAG_KEY));
2948  print_ts ("pts", frame->pts);
2949  print_time("pts_time", frame->pts, &stream->time_base);
2950  print_ts ("pkt_dts", frame->pkt_dts);
2951  print_time("pkt_dts_time", frame->pkt_dts, &stream->time_base);
2952  print_ts ("best_effort_timestamp", frame->best_effort_timestamp);
2953  print_time("best_effort_timestamp_time", frame->best_effort_timestamp, &stream->time_base);
2954  print_duration_ts ("duration", frame->duration);
2955  print_duration_time("duration_time", frame->duration, &stream->time_base);
2956  if (fd && fd->pkt_pos != -1) print_fmt ("pkt_pos", "%"PRId64, fd->pkt_pos);
2957  else print_str_opt("pkt_pos", "N/A");
2958  if (fd && fd->pkt_size != -1) print_val ("pkt_size", fd->pkt_size, unit_byte_str);
2959  else print_str_opt("pkt_size", "N/A");
2960 
2961  switch (stream->codecpar->codec_type) {
2962  AVRational sar;
2963 
2964  case AVMEDIA_TYPE_VIDEO:
2965  print_int("width", frame->width);
2966  print_int("height", frame->height);
2967  print_int("crop_top", frame->crop_top);
2968  print_int("crop_bottom", frame->crop_bottom);
2969  print_int("crop_left", frame->crop_left);
2970  print_int("crop_right", frame->crop_right);
2971  s = av_get_pix_fmt_name(frame->format);
2972  if (s) print_str ("pix_fmt", s);
2973  else print_str_opt("pix_fmt", "unknown");
2974  sar = av_guess_sample_aspect_ratio(fmt_ctx, stream, frame);
2975  if (sar.num) {
2976  print_q("sample_aspect_ratio", sar, ':');
2977  } else {
2978  print_str_opt("sample_aspect_ratio", "N/A");
2979  }
2980  print_fmt("pict_type", "%c", av_get_picture_type_char(frame->pict_type));
2981  print_int("interlaced_frame", !!(frame->flags & AV_FRAME_FLAG_INTERLACED));
2982  print_int("top_field_first", !!(frame->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST));
2983  print_int("repeat_pict", frame->repeat_pict);
2984 
2985  print_color_range(w, frame->color_range);
2986  print_color_space(w, frame->colorspace);
2987  print_primaries(w, frame->color_primaries);
2988  print_color_trc(w, frame->color_trc);
2989  print_chroma_location(w, frame->chroma_location);
2990  break;
2991 
2992  case AVMEDIA_TYPE_AUDIO:
2993  s = av_get_sample_fmt_name(frame->format);
2994  if (s) print_str ("sample_fmt", s);
2995  else print_str_opt("sample_fmt", "unknown");
2996  print_int("nb_samples", frame->nb_samples);
2997  print_int("channels", frame->ch_layout.nb_channels);
2998  if (frame->ch_layout.order != AV_CHANNEL_ORDER_UNSPEC) {
2999  av_channel_layout_describe(&frame->ch_layout, val_str, sizeof(val_str));
3000  print_str ("channel_layout", val_str);
3001  } else
3002  print_str_opt("channel_layout", "unknown");
3003  break;
3004  }
3005  if (do_show_frame_tags)
3006  show_tags(w, frame->metadata, SECTION_ID_FRAME_TAGS);
3007  if (do_show_log)
3009  if (frame->nb_side_data)
3010  print_frame_side_data(w, frame, stream);
3011 
3013 
3014  av_bprint_finalize(&pbuf, NULL);
3015  fflush(stdout);
3016 }
3017 
3019  InputFile *ifile,
3020  AVFrame *frame, const AVPacket *pkt,
3021  int *packet_new)
3022 {
3023  AVFormatContext *fmt_ctx = ifile->fmt_ctx;
3026  AVSubtitle sub;
3027  int ret = 0, got_frame = 0;
3028 
3029  clear_log(1);
3030  if (dec_ctx) {
3031  switch (par->codec_type) {
3032  case AVMEDIA_TYPE_VIDEO:
3033  case AVMEDIA_TYPE_AUDIO:
3034  if (*packet_new) {
3036  if (ret == AVERROR(EAGAIN)) {
3037  ret = 0;
3038  } else if (ret >= 0 || ret == AVERROR_EOF) {
3039  ret = 0;
3040  *packet_new = 0;
3041  }
3042  }
3043  if (ret >= 0) {
3045  if (ret >= 0) {
3046  got_frame = 1;
3047  } else if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
3048  ret = 0;
3049  }
3050  }
3051  break;
3052 
3053  case AVMEDIA_TYPE_SUBTITLE:
3054  if (*packet_new)
3055  ret = avcodec_decode_subtitle2(dec_ctx, &sub, &got_frame, pkt);
3056  *packet_new = 0;
3057  break;
3058  default:
3059  *packet_new = 0;
3060  }
3061  } else {
3062  *packet_new = 0;
3063  }
3064 
3065  if (ret < 0)
3066  return ret;
3067  if (got_frame) {
3068  int is_sub = (par->codec_type == AVMEDIA_TYPE_SUBTITLE);
3070  if (do_show_frames)
3071  if (is_sub)
3072  show_subtitle(w, &sub, ifile->streams[pkt->stream_index].st, fmt_ctx);
3073  else
3075  if (is_sub)
3076  avsubtitle_free(&sub);
3077  }
3078  return got_frame || *packet_new;
3079 }
3080 
3081 static void log_read_interval(const ReadInterval *interval, void *log_ctx, int log_level)
3082 {
3083  av_log(log_ctx, log_level, "id:%d", interval->id);
3084 
3085  if (interval->has_start) {
3086  av_log(log_ctx, log_level, " start:%s%s", interval->start_is_offset ? "+" : "",
3087  av_ts2timestr(interval->start, &AV_TIME_BASE_Q));
3088  } else {
3089  av_log(log_ctx, log_level, " start:N/A");
3090  }
3091 
3092  if (interval->has_end) {
3093  av_log(log_ctx, log_level, " end:%s", interval->end_is_offset ? "+" : "");
3094  if (interval->duration_frames)
3095  av_log(log_ctx, log_level, "#%"PRId64, interval->end);
3096  else
3097  av_log(log_ctx, log_level, "%s", av_ts2timestr(interval->end, &AV_TIME_BASE_Q));
3098  } else {
3099  av_log(log_ctx, log_level, " end:N/A");
3100  }
3101 
3102  av_log(log_ctx, log_level, "\n");
3103 }
3104 
3106  const ReadInterval *interval, int64_t *cur_ts)
3107 {
3108  AVFormatContext *fmt_ctx = ifile->fmt_ctx;
3109  AVPacket *pkt = NULL;
3110  AVFrame *frame = NULL;
3111  int ret = 0, i = 0, frame_count = 0;
3112  int64_t start = -INT64_MAX, end = interval->end;
3113  int has_start = 0, has_end = interval->has_end && !interval->end_is_offset;
3114 
3115  av_log(NULL, AV_LOG_VERBOSE, "Processing read interval ");
3117 
3118  if (interval->has_start) {
3119  int64_t target;
3120  if (interval->start_is_offset) {
3121  if (*cur_ts == AV_NOPTS_VALUE) {
3123  "Could not seek to relative position since current "
3124  "timestamp is not defined\n");
3125  ret = AVERROR(EINVAL);
3126  goto end;
3127  }
3128  target = *cur_ts + interval->start;
3129  } else {
3130  target = interval->start;
3131  }
3132 
3133  av_log(NULL, AV_LOG_VERBOSE, "Seeking to read interval start point %s\n",
3134  av_ts2timestr(target, &AV_TIME_BASE_Q));
3135  if ((ret = avformat_seek_file(fmt_ctx, -1, -INT64_MAX, target, INT64_MAX, 0)) < 0) {
3136  av_log(NULL, AV_LOG_ERROR, "Could not seek to position %"PRId64": %s\n",
3137  interval->start, av_err2str(ret));
3138  goto end;
3139  }
3140  }
3141 
3142  frame = av_frame_alloc();
3143  if (!frame) {
3144  ret = AVERROR(ENOMEM);
3145  goto end;
3146  }
3147  pkt = av_packet_alloc();
3148  if (!pkt) {
3149  ret = AVERROR(ENOMEM);
3150  goto end;
3151  }
3152  while (!av_read_frame(fmt_ctx, pkt)) {
3153  if (fmt_ctx->nb_streams > nb_streams) {
3158  }
3160  AVRational tb = ifile->streams[pkt->stream_index].st->time_base;
3161  int64_t pts = pkt->pts != AV_NOPTS_VALUE ? pkt->pts : pkt->dts;
3162 
3163  if (pts != AV_NOPTS_VALUE)
3164  *cur_ts = av_rescale_q(pts, tb, AV_TIME_BASE_Q);
3165 
3166  if (!has_start && *cur_ts != AV_NOPTS_VALUE) {
3167  start = *cur_ts;
3168  has_start = 1;
3169  }
3170 
3171  if (has_start && !has_end && interval->end_is_offset) {
3172  end = start + interval->end;
3173  has_end = 1;
3174  }
3175 
3176  if (interval->end_is_offset && interval->duration_frames) {
3177  if (frame_count >= interval->end)
3178  break;
3179  } else if (has_end && *cur_ts != AV_NOPTS_VALUE && *cur_ts >= end) {
3180  break;
3181  }
3182 
3183  frame_count++;
3184  if (do_read_packets) {
3185  if (do_show_packets)
3186  show_packet(w, ifile, pkt, i++);
3188  }
3189  if (do_read_frames) {
3190  int packet_new = 1;
3191  FrameData *fd;
3192 
3193  pkt->opaque_ref = av_buffer_allocz(sizeof(*fd));
3194  if (!pkt->opaque_ref) {
3195  ret = AVERROR(ENOMEM);
3196  goto end;
3197  }
3198  fd = (FrameData*)pkt->opaque_ref->data;
3199  fd->pkt_pos = pkt->pos;
3200  fd->pkt_size = pkt->size;
3201 
3202  while (process_frame(w, ifile, frame, pkt, &packet_new) > 0);
3203  }
3204  }
3206  }
3208  //Flush remaining frames that are cached in the decoder
3209  for (i = 0; i < ifile->nb_streams; i++) {
3210  pkt->stream_index = i;
3211  if (do_read_frames) {
3212  while (process_frame(w, ifile, frame, pkt, &(int){1}) > 0);
3213  if (ifile->streams[i].dec_ctx)
3215  }
3216  }
3217 
3218 end:
3219  av_frame_free(&frame);
3220  av_packet_free(&pkt);
3221  if (ret < 0) {
3222  av_log(NULL, AV_LOG_ERROR, "Could not read packets in interval ");
3223  log_read_interval(interval, NULL, AV_LOG_ERROR);
3224  }
3225  return ret;
3226 }
3227 
3229 {
3230  AVFormatContext *fmt_ctx = ifile->fmt_ctx;
3231  int i, ret = 0;
3232  int64_t cur_ts = fmt_ctx->start_time;
3233 
3234  if (read_intervals_nb == 0) {
3235  ReadInterval interval = (ReadInterval) { .has_start = 0, .has_end = 0 };
3236  ret = read_interval_packets(w, ifile, &interval, &cur_ts);
3237  } else {
3238  for (i = 0; i < read_intervals_nb; i++) {
3239  ret = read_interval_packets(w, ifile, &read_intervals[i], &cur_ts);
3240  if (ret < 0)
3241  break;
3242  }
3243  }
3244 
3245  return ret;
3246 }
3247 
3248 static void print_dispositions(WriterContext *w, uint32_t disposition, SectionID section_id)
3249 {
3250  writer_print_section_header(w, NULL, section_id);
3251  for (int i = 0; i < sizeof(disposition) * CHAR_BIT; i++) {
3252  const char *disposition_str = av_disposition_to_string(1U << i);
3253 
3254  if (disposition_str)
3255  print_int(disposition_str, !!(disposition & (1U << i)));
3256  }
3258 }
3259 
3260 #define IN_PROGRAM 1
3261 #define IN_STREAM_GROUP 2
3262 
3263 static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_idx, InputStream *ist, int container)
3264 {
3265  AVStream *stream = ist->st;
3266  AVCodecParameters *par;
3268  char val_str[128];
3269  const char *s;
3270  AVRational sar, dar;
3271  AVBPrint pbuf;
3272  const AVCodecDescriptor *cd;
3273  const SectionID section_header[] = {
3277  };
3278  const SectionID section_disposition[] = {
3282  };
3283  const SectionID section_tags[] = {
3287  };
3288  int ret = 0;
3289  const char *profile = NULL;
3290 
3291  av_assert0(container < FF_ARRAY_ELEMS(section_header));
3292 
3294 
3295  writer_print_section_header(w, NULL, section_header[container]);
3296 
3297  print_int("index", stream->index);
3298 
3299  par = stream->codecpar;
3300  dec_ctx = ist->dec_ctx;
3301  if (cd = avcodec_descriptor_get(par->codec_id)) {
3302  print_str("codec_name", cd->name);
3303  if (!do_bitexact) {
3304  print_str("codec_long_name",
3305  cd->long_name ? cd->long_name : "unknown");
3306  }
3307  } else {
3308  print_str_opt("codec_name", "unknown");
3309  if (!do_bitexact) {
3310  print_str_opt("codec_long_name", "unknown");
3311  }
3312  }
3313 
3314  if (!do_bitexact && (profile = avcodec_profile_name(par->codec_id, par->profile)))
3315  print_str("profile", profile);
3316  else {
3317  if (par->profile != AV_PROFILE_UNKNOWN) {
3318  char profile_num[12];
3319  snprintf(profile_num, sizeof(profile_num), "%d", par->profile);
3320  print_str("profile", profile_num);
3321  } else
3322  print_str_opt("profile", "unknown");
3323  }
3324 
3326  if (s) print_str ("codec_type", s);
3327  else print_str_opt("codec_type", "unknown");
3328 
3329  /* print AVI/FourCC tag */
3330  print_str("codec_tag_string", av_fourcc2str(par->codec_tag));
3331  print_fmt("codec_tag", "0x%04"PRIx32, par->codec_tag);
3332 
3333  switch (par->codec_type) {
3334  case AVMEDIA_TYPE_VIDEO:
3335  print_int("width", par->width);
3336  print_int("height", par->height);
3337  if (dec_ctx) {
3338  print_int("coded_width", dec_ctx->coded_width);
3339  print_int("coded_height", dec_ctx->coded_height);
3342  }
3343  print_int("has_b_frames", par->video_delay);
3344  sar = av_guess_sample_aspect_ratio(fmt_ctx, stream, NULL);
3345  if (sar.num) {
3346  print_q("sample_aspect_ratio", sar, ':');
3347  av_reduce(&dar.num, &dar.den,
3348  (int64_t) par->width * sar.num,
3349  (int64_t) par->height * sar.den,
3350  1024*1024);
3351  print_q("display_aspect_ratio", dar, ':');
3352  } else {
3353  print_str_opt("sample_aspect_ratio", "N/A");
3354  print_str_opt("display_aspect_ratio", "N/A");
3355  }
3356  s = av_get_pix_fmt_name(par->format);
3357  if (s) print_str ("pix_fmt", s);
3358  else print_str_opt("pix_fmt", "unknown");
3359  print_int("level", par->level);
3360 
3363  print_color_trc(w, par->color_trc);
3366 
3367  if (par->field_order == AV_FIELD_PROGRESSIVE)
3368  print_str("field_order", "progressive");
3369  else if (par->field_order == AV_FIELD_TT)
3370  print_str("field_order", "tt");
3371  else if (par->field_order == AV_FIELD_BB)
3372  print_str("field_order", "bb");
3373  else if (par->field_order == AV_FIELD_TB)
3374  print_str("field_order", "tb");
3375  else if (par->field_order == AV_FIELD_BT)
3376  print_str("field_order", "bt");
3377  else
3378  print_str_opt("field_order", "unknown");
3379 
3380  if (dec_ctx)
3381  print_int("refs", dec_ctx->refs);
3382  break;
3383 
3384  case AVMEDIA_TYPE_AUDIO:
3386  if (s) print_str ("sample_fmt", s);
3387  else print_str_opt("sample_fmt", "unknown");
3388  print_val("sample_rate", par->sample_rate, unit_hertz_str);
3389  print_int("channels", par->ch_layout.nb_channels);
3390 
3391  if (par->ch_layout.order != AV_CHANNEL_ORDER_UNSPEC) {
3392  av_channel_layout_describe(&par->ch_layout, val_str, sizeof(val_str));
3393  print_str ("channel_layout", val_str);
3394  } else {
3395  print_str_opt("channel_layout", "unknown");
3396  }
3397 
3398  print_int("bits_per_sample", av_get_bits_per_sample(par->codec_id));
3399 
3400  print_int("initial_padding", par->initial_padding);
3401  break;
3402 
3403  case AVMEDIA_TYPE_SUBTITLE:
3404  if (par->width)
3405  print_int("width", par->width);
3406  else
3407  print_str_opt("width", "N/A");
3408  if (par->height)
3409  print_int("height", par->height);
3410  else
3411  print_str_opt("height", "N/A");
3412  break;
3413  }
3414 
3415  if (show_private_data) {
3416  if (dec_ctx && dec_ctx->codec->priv_class)
3418  if (fmt_ctx->iformat->priv_class)
3420  }
3421 
3422  if (fmt_ctx->iformat->flags & AVFMT_SHOW_IDS) print_fmt ("id", "0x%x", stream->id);
3423  else print_str_opt("id", "N/A");
3424  print_q("r_frame_rate", stream->r_frame_rate, '/');
3425  print_q("avg_frame_rate", stream->avg_frame_rate, '/');
3426  print_q("time_base", stream->time_base, '/');
3427  print_ts ("start_pts", stream->start_time);
3428  print_time("start_time", stream->start_time, &stream->time_base);
3429  print_ts ("duration_ts", stream->duration);
3430  print_time("duration", stream->duration, &stream->time_base);
3431  if (par->bit_rate > 0) print_val ("bit_rate", par->bit_rate, unit_bit_per_second_str);
3432  else print_str_opt("bit_rate", "N/A");
3433  if (dec_ctx && dec_ctx->rc_max_rate > 0)
3435  else
3436  print_str_opt("max_bit_rate", "N/A");
3437  if (dec_ctx && dec_ctx->bits_per_raw_sample > 0) print_fmt("bits_per_raw_sample", "%d", dec_ctx->bits_per_raw_sample);
3438  else print_str_opt("bits_per_raw_sample", "N/A");
3439  if (stream->nb_frames) print_fmt ("nb_frames", "%"PRId64, stream->nb_frames);
3440  else print_str_opt("nb_frames", "N/A");
3441  if (nb_streams_frames[stream_idx]) print_fmt ("nb_read_frames", "%"PRIu64, nb_streams_frames[stream_idx]);
3442  else print_str_opt("nb_read_frames", "N/A");
3443  if (nb_streams_packets[stream_idx]) print_fmt ("nb_read_packets", "%"PRIu64, nb_streams_packets[stream_idx]);
3444  else print_str_opt("nb_read_packets", "N/A");
3445  if (do_show_data)
3446  writer_print_data(w, "extradata", par->extradata,
3447  par->extradata_size);
3448 
3449  if (par->extradata_size > 0) {
3450  print_int("extradata_size", par->extradata_size);
3451  writer_print_data_hash(w, "extradata_hash", par->extradata,
3452  par->extradata_size);
3453  }
3454 
3455  /* Print disposition information */
3457  av_assert0(container < FF_ARRAY_ELEMS(section_disposition));
3458  print_dispositions(w, stream->disposition, section_disposition[container]);
3459  }
3460 
3461  if (do_show_stream_tags) {
3462  av_assert0(container < FF_ARRAY_ELEMS(section_tags));
3463  ret = show_tags(w, stream->metadata, section_tags[container]);
3464  }
3465 
3466  if (stream->codecpar->nb_coded_side_data) {
3468  for (int i = 0; i < stream->codecpar->nb_coded_side_data; i++) {
3469  print_pkt_side_data(w, stream->codecpar, &stream->codecpar->coded_side_data[i],
3472  }
3474  }
3475 
3477  av_bprint_finalize(&pbuf, NULL);
3478  fflush(stdout);
3479 
3480  return ret;
3481 }
3482 
3484 {
3485  AVFormatContext *fmt_ctx = ifile->fmt_ctx;
3486  int i, ret = 0;
3487 
3489  for (i = 0; i < ifile->nb_streams; i++)
3490  if (selected_streams[i]) {
3491  ret = show_stream(w, fmt_ctx, i, &ifile->streams[i], 0);
3492  if (ret < 0)
3493  break;
3494  }
3496 
3497  return ret;
3498 }
3499 
3501 {
3502  AVFormatContext *fmt_ctx = ifile->fmt_ctx;
3503  int i, ret = 0;
3504 
3506  print_int("program_id", program->id);
3507  print_int("program_num", program->program_num);
3508  print_int("nb_streams", program->nb_stream_indexes);
3509  print_int("pmt_pid", program->pmt_pid);
3510  print_int("pcr_pid", program->pcr_pid);
3513  if (ret < 0)
3514  goto end;
3515 
3517  for (i = 0; i < program->nb_stream_indexes; i++) {
3518  if (selected_streams[program->stream_index[i]]) {
3519  ret = show_stream(w, fmt_ctx, program->stream_index[i], &ifile->streams[program->stream_index[i]], IN_PROGRAM);
3520  if (ret < 0)
3521  break;
3522  }
3523  }
3525 
3526 end:
3528  return ret;
3529 }
3530 
3532 {
3533  AVFormatContext *fmt_ctx = ifile->fmt_ctx;
3534  int i, ret = 0;
3535 
3537  for (i = 0; i < fmt_ctx->nb_programs; i++) {
3539  if (!program)
3540  continue;
3541  ret = show_program(w, ifile, program);
3542  if (ret < 0)
3543  break;
3544  }
3546  return ret;
3547 }
3548 
3550  const AVStreamGroupTileGrid *tile_grid)
3551 {
3553  print_int("nb_tiles", tile_grid->nb_tiles);
3554  print_int("coded_width", tile_grid->coded_width);
3555  print_int("coded_height", tile_grid->coded_height);
3556  print_int("horizontal_offset", tile_grid->horizontal_offset);
3557  print_int("vertical_offset", tile_grid->vertical_offset);
3558  print_int("width", tile_grid->width);
3559  print_int("height", tile_grid->height);
3561  for (int i = 0; i < tile_grid->nb_tiles; i++) {
3563  print_int("stream_index", tile_grid->offsets[i].idx);
3564  print_int("tile_horizontal_offset", tile_grid->offsets[i].horizontal);
3565  print_int("tile_vertical_offset", tile_grid->offsets[i].vertical);
3567  }
3570 }
3571 
3573  const AVIAMFParamDefinition *param, SectionID section_id)
3574 {
3575  SectionID subsection_id, parameter_section_id;
3576  subsection_id = sections[section_id].children_ids[0];
3577  av_assert0(subsection_id != -1);
3578  parameter_section_id = sections[subsection_id].children_ids[0];
3579  av_assert0(parameter_section_id != -1);
3580  writer_print_section_header(w, "IAMF Param Definition", section_id);
3581  print_str("name", name);
3582  print_int("nb_subblocks", param->nb_subblocks);
3583  print_int("type", param->type);
3584  print_int("parameter_id", param->parameter_id);
3585  print_int("parameter_rate", param->parameter_rate);
3586  print_int("duration", param->duration);
3587  print_int("constant_subblock_duration", param->constant_subblock_duration);
3588  if (param->nb_subblocks > 0)
3589  writer_print_section_header(w, NULL, subsection_id);
3590  for (int i = 0; i < param->nb_subblocks; i++) {
3591  const void *subblock = av_iamf_param_definition_get_subblock(param, i);
3592  switch(param->type) {
3594  const AVIAMFMixGain *mix = subblock;
3595  writer_print_section_header(w, "IAMF Mix Gain Parameters", parameter_section_id);
3596  print_int("subblock_duration", mix->subblock_duration);
3597  print_int("animation_type", mix->animation_type);
3598  print_q("start_point_value", mix->start_point_value, '/');
3599  print_q("end_point_value", mix->end_point_value, '/');
3600  print_q("control_point_value", mix->control_point_value, '/');
3601  print_q("control_point_relative_time", mix->control_point_relative_time, '/');
3602  writer_print_section_footer(w); // parameter_section_id
3603  break;
3604  }
3606  const AVIAMFDemixingInfo *demix = subblock;
3607  writer_print_section_header(w, "IAMF Demixing Info", parameter_section_id);
3608  print_int("subblock_duration", demix->subblock_duration);
3609  print_int("dmixp_mode", demix->dmixp_mode);
3610  writer_print_section_footer(w); // parameter_section_id
3611  break;
3612  }
3614  const AVIAMFReconGain *recon = subblock;
3615  writer_print_section_header(w, "IAMF Recon Gain", parameter_section_id);
3616  print_int("subblock_duration", recon->subblock_duration);
3617  writer_print_section_footer(w); // parameter_section_id
3618  break;
3619  }
3620  }
3621  }
3622  if (param->nb_subblocks > 0)
3623  writer_print_section_footer(w); // subsection_id
3624  writer_print_section_footer(w); // section_id
3625 }
3626 
3628  const AVIAMFAudioElement *audio_element)
3629 {
3631  print_int("nb_layers", audio_element->nb_layers);
3632  print_int("audio_element_type", audio_element->audio_element_type);
3633  print_int("default_w", audio_element->default_w);
3635  for (int i = 0; i < audio_element->nb_layers; i++) {
3636  const AVIAMFLayer *layer = audio_element->layers[i];
3637  char val_str[128];
3639  av_channel_layout_describe(&layer->ch_layout, val_str, sizeof(val_str));
3640  print_str("channel_layout", val_str);
3642  print_int("output_gain_flags", layer->output_gain_flags);
3643  print_q("output_gain", layer->output_gain, '/');
3644  } else if (audio_element->audio_element_type == AV_IAMF_AUDIO_ELEMENT_TYPE_SCENE)
3645  print_int("ambisonics_mode", layer->ambisonics_mode);
3646  writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_SUBCOMPONENT
3647  }
3648  if (audio_element->demixing_info)
3649  print_iamf_param_definition(w, "demixing_info", audio_element->demixing_info,
3651  if (audio_element->recon_gain_info)
3652  print_iamf_param_definition(w, "recon_gain_info", audio_element->recon_gain_info,
3654  writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_SUBCOMPONENTS
3655  writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_COMPONENT
3656 }
3657 
3659 {
3661  print_int("nb_elements", submix->nb_elements);
3662  print_int("nb_layouts", submix->nb_layouts);
3663  print_q("default_mix_gain", submix->default_mix_gain, '/');
3665  for (int i = 0; i < submix->nb_elements; i++) {
3666  const AVIAMFSubmixElement *element = submix->elements[i];
3668  print_int("stream_id", element->audio_element_id);
3669  print_q("default_mix_gain", element->default_mix_gain, '/');
3670  print_int("headphones_rendering_mode", element->headphones_rendering_mode);
3672  if (element->annotations) {
3673  const AVDictionaryEntry *annotation = NULL;
3675  while (annotation = av_dict_iterate(element->annotations, annotation))
3676  print_str(annotation->key, annotation->value);
3677  writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_SUBPIECE
3678  }
3679  if (element->element_mix_config)
3680  print_iamf_param_definition(w, "element_mix_config", element->element_mix_config,
3682  writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_SUBPIECES
3683  writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_PIECE
3684  }
3685  if (submix->output_mix_config)
3686  print_iamf_param_definition(w, "output_mix_config", submix->output_mix_config,
3688  for (int i = 0; i < submix->nb_layouts; i++) {
3689  const AVIAMFSubmixLayout *layout = submix->layouts[i];
3690  char val_str[128];
3692  av_channel_layout_describe(&layout->sound_system, val_str, sizeof(val_str));
3693  print_str("sound_system", val_str);
3694  print_q("integrated_loudness", layout->integrated_loudness, '/');
3695  print_q("digital_peak", layout->digital_peak, '/');
3696  print_q("true_peak", layout->true_peak, '/');
3697  print_q("dialogue_anchored_loudness", layout->dialogue_anchored_loudness, '/');
3698  print_q("album_anchored_loudness", layout->album_anchored_loudness, '/');
3699  writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_PIECE
3700  }
3701  writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_PIECES
3702  writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_SUBCOMPONENT
3703 }
3704 
3706  const AVIAMFMixPresentation *mix_presentation)
3707 {
3709  print_int("nb_submixes", mix_presentation->nb_submixes);
3711  if (mix_presentation->annotations) {
3712  const AVDictionaryEntry *annotation = NULL;
3714  while (annotation = av_dict_iterate(mix_presentation->annotations, annotation))
3715  print_str(annotation->key, annotation->value);
3716  writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_SUBCOMPONENT
3717  }
3718  for (int i = 0; i < mix_presentation->nb_submixes; i++)
3719  print_iamf_submix_params(w, mix_presentation->submixes[i]);
3720  writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_SUBCOMPONENTS
3721  writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_COMPONENT
3722 }
3723 
3725 {
3733  writer_print_section_footer(w); // SECTION_ID_STREAM_GROUP_COMPONENTS
3734 }
3735 
3737 {
3738  AVFormatContext *fmt_ctx = ifile->fmt_ctx;
3739  AVBPrint pbuf;
3740  int i, ret = 0;
3741 
3744  print_int("index", stg->index);
3745  if (fmt_ctx->iformat->flags & AVFMT_SHOW_IDS) print_fmt ("id", "0x%"PRIx64, stg->id);
3746  else print_str_opt("id", "N/A");
3747  print_int("nb_streams", stg->nb_streams);
3748  if (stg->type != AV_STREAM_GROUP_PARAMS_NONE)
3749  print_str("type", av_x_if_null(avformat_stream_group_name(stg->type), "unknown"));
3750  else
3751  print_str_opt("type", "unknown");
3754 
3755  /* Print disposition information */
3758 
3761  if (ret < 0)
3762  goto end;
3763 
3765  for (i = 0; i < stg->nb_streams; i++) {
3766  if (selected_streams[stg->streams[i]->index]) {
3767  ret = show_stream(w, fmt_ctx, stg->streams[i]->index, &ifile->streams[stg->streams[i]->index], IN_STREAM_GROUP);
3768  if (ret < 0)
3769  break;
3770  }
3771  }
3773 
3774 end:
3775  av_bprint_finalize(&pbuf, NULL);
3777  return ret;
3778 }
3779 
3781 {
3782  AVFormatContext *fmt_ctx = ifile->fmt_ctx;
3783  int i, ret = 0;
3784 
3786  for (i = 0; i < fmt_ctx->nb_stream_groups; i++) {
3788 
3789  ret = show_stream_group(w, ifile, stg);
3790  if (ret < 0)
3791  break;
3792  }
3794  return ret;
3795 }
3796 
3798 {
3799  AVFormatContext *fmt_ctx = ifile->fmt_ctx;
3800  int i, ret = 0;
3801 
3803  for (i = 0; i < fmt_ctx->nb_chapters; i++) {
3804  AVChapter *chapter = fmt_ctx->chapters[i];
3805 
3807  print_int("id", chapter->