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