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