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