FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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 "version.h"
28 
29 #include <string.h>
30 
31 #include "libavformat/avformat.h"
32 #include "libavcodec/avcodec.h"
33 #include "libavutil/avassert.h"
34 #include "libavutil/avstring.h"
35 #include "libavutil/bprint.h"
36 #include "libavutil/opt.h"
37 #include "libavutil/pixdesc.h"
38 #include "libavutil/dict.h"
39 #include "libavutil/libm.h"
40 #include "libavutil/timecode.h"
41 #include "libavdevice/avdevice.h"
42 #include "libswscale/swscale.h"
45 #include "cmdutils.h"
46 
47 const char program_name[] = "ffprobe";
48 const int program_birth_year = 2007;
49 
50 static int do_bitexact = 0;
51 static int do_count_frames = 0;
52 static int do_count_packets = 0;
53 static int do_read_frames = 0;
54 static int do_read_packets = 0;
55 static int do_show_chapters = 0;
56 static int do_show_error = 0;
57 static int do_show_format = 0;
58 static int do_show_frames = 0;
59 static int do_show_packets = 0;
60 static int do_show_streams = 0;
62 static int do_show_data = 0;
63 static int do_show_program_version = 0;
64 static int do_show_library_versions = 0;
65 
66 static int show_value_unit = 0;
67 static int use_value_prefix = 0;
70 static int show_private_data = 1;
71 
72 static char *print_format;
73 static char *stream_specifier;
74 
75 /* section structure definition */
76 
77 #define SECTION_MAX_NB_CHILDREN 10
78 
79 struct section {
80  int id; ///< unique id identifying a section
81  const char *name;
82 
83 #define SECTION_FLAG_IS_WRAPPER 1 ///< the section only contains other sections, but has no data at its own level
84 #define SECTION_FLAG_IS_ARRAY 2 ///< the section contains an array of elements of the same type
85 #define SECTION_FLAG_HAS_VARIABLE_FIELDS 4 ///< the section may contain a variable number of fields with variable keys.
86  /// For these sections the element_name field is mandatory.
87  int flags;
88  int children_ids[SECTION_MAX_NB_CHILDREN+1]; ///< list of children section IDS, terminated by -1
89  const char *element_name; ///< name of the contained element, if provided
90  const char *unique_name; ///< unique section name, in case the name is ambiguous
93 };
94 
95 typedef enum {
117 } SectionID;
118 
119 static struct section sections[] = {
121  [SECTION_ID_CHAPTER] = { SECTION_ID_CHAPTER, "chapter", 0, { SECTION_ID_CHAPTER_TAGS, -1 } },
122  [SECTION_ID_CHAPTER_TAGS] = { SECTION_ID_CHAPTER_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "chapter_tags" },
123  [SECTION_ID_ERROR] = { SECTION_ID_ERROR, "error", 0, { -1 } },
124  [SECTION_ID_FORMAT] = { SECTION_ID_FORMAT, "format", 0, { SECTION_ID_FORMAT_TAGS, -1 } },
125  [SECTION_ID_FORMAT_TAGS] = { SECTION_ID_FORMAT_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "format_tags" },
127  [SECTION_ID_FRAME] = { SECTION_ID_FRAME, "frame", 0, { SECTION_ID_FRAME_TAGS, -1 } },
128  [SECTION_ID_FRAME_TAGS] = { SECTION_ID_FRAME_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "frame_tags" },
130  [SECTION_ID_LIBRARY_VERSION] = { SECTION_ID_LIBRARY_VERSION, "library_version", 0, { -1 } },
133  [SECTION_ID_PACKET] = { SECTION_ID_PACKET, "packet", 0, { -1 } },
134  [SECTION_ID_PROGRAM_VERSION] = { SECTION_ID_PROGRAM_VERSION, "program_version", 0, { -1 } },
140  [SECTION_ID_STREAM_DISPOSITION] = { SECTION_ID_STREAM_DISPOSITION, "disposition", 0, { -1 }, .unique_name = "stream_disposition" },
141  [SECTION_ID_STREAM_TAGS] = { SECTION_ID_STREAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "stream_tags" },
142 };
143 
144 static const OptionDef *options;
145 
146 /* FFprobe context */
147 static const char *input_filename;
148 static AVInputFormat *iformat = NULL;
149 
150 static const char *const binary_unit_prefixes [] = { "", "Ki", "Mi", "Gi", "Ti", "Pi" };
151 static const char *const decimal_unit_prefixes[] = { "", "K" , "M" , "G" , "T" , "P" };
152 
153 static const char unit_second_str[] = "s" ;
154 static const char unit_hertz_str[] = "Hz" ;
155 static const char unit_byte_str[] = "byte" ;
156 static const char unit_bit_per_second_str[] = "bit/s";
157 
158 static uint64_t *nb_streams_packets;
159 static uint64_t *nb_streams_frames;
160 static int *selected_streams;
161 
162 static void ffprobe_cleanup(int ret)
163 {
164  int i;
165  for (i = 0; i < FF_ARRAY_ELEMS(sections); i++)
166  av_dict_free(&(sections[i].entries_to_show));
167 }
168 
169 struct unit_value {
170  union { double d; long long int i; } val;
171  const char *unit;
172 };
173 
174 static char *value_string(char *buf, int buf_size, struct unit_value uv)
175 {
176  double vald;
177  long long int vali;
178  int show_float = 0;
179 
180  if (uv.unit == unit_second_str) {
181  vald = uv.val.d;
182  show_float = 1;
183  } else {
184  vald = vali = uv.val.i;
185  }
186 
188  double secs;
189  int hours, mins;
190  secs = vald;
191  mins = (int)secs / 60;
192  secs = secs - mins * 60;
193  hours = mins / 60;
194  mins %= 60;
195  snprintf(buf, buf_size, "%d:%02d:%09.6f", hours, mins, secs);
196  } else {
197  const char *prefix_string = "";
198 
199  if (use_value_prefix && vald > 1) {
200  long long int index;
201 
203  index = (long long int) (log2(vald)) / 10;
204  index = av_clip(index, 0, FF_ARRAY_ELEMS(binary_unit_prefixes) - 1);
205  vald /= exp2(index * 10);
206  prefix_string = binary_unit_prefixes[index];
207  } else {
208  index = (long long int) (log10(vald)) / 3;
209  index = av_clip(index, 0, FF_ARRAY_ELEMS(decimal_unit_prefixes) - 1);
210  vald /= pow(10, index * 3);
211  prefix_string = decimal_unit_prefixes[index];
212  }
213  }
214 
215  if (show_float || (use_value_prefix && vald != (long long int)vald))
216  snprintf(buf, buf_size, "%f", vald);
217  else
218  snprintf(buf, buf_size, "%lld", vali);
219  av_strlcatf(buf, buf_size, "%s%s%s", *prefix_string || show_value_unit ? " " : "",
220  prefix_string, show_value_unit ? uv.unit : "");
221  }
222 
223  return buf;
224 }
225 
226 /* WRITERS API */
227 
228 typedef struct WriterContext WriterContext;
229 
230 #define WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS 1
231 #define WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER 2
232 
233 typedef struct Writer {
234  const AVClass *priv_class; ///< private class of the writer, if any
235  int priv_size; ///< private size for the writer context
236  const char *name;
237 
238  int (*init) (WriterContext *wctx);
240 
243  void (*print_integer) (WriterContext *wctx, const char *, long long int);
244  void (*print_rational) (WriterContext *wctx, AVRational *q, char *sep);
245  void (*print_string) (WriterContext *wctx, const char *, const char *);
246  int flags; ///< a combination or WRITER_FLAG_*
247 } Writer;
248 
249 #define SECTION_MAX_NB_LEVELS 10
250 
252  const AVClass *class; ///< class of the writer
253  const Writer *writer; ///< the Writer of which this is an instance
254  char *name; ///< name of this writer instance
255  void *priv; ///< private data for use by the filter
256 
257  const struct section *sections; ///< array containing all sections
258  int nb_sections; ///< number of sections
259 
260  int level; ///< current level, starting from 0
261 
262  /** number of the item printed in the given section, starting from 0 */
264 
265  /** section per each level */
267  AVBPrint section_pbuf[SECTION_MAX_NB_LEVELS]; ///< generic print buffer dedicated to each section,
268  /// used by various writers
269 
270  unsigned int nb_section_packet; ///< number of the packet section in case we are in "packets_and_frames" section
271  unsigned int nb_section_frame; ///< number of the frame section in case we are in "packets_and_frames" section
272  unsigned int nb_section_packet_frame; ///< nb_section_packet or nb_section_frame according if is_packets_and_frames
273 };
274 
275 static const char *writer_get_name(void *p)
276 {
277  WriterContext *wctx = p;
278  return wctx->writer->name;
279 }
280 
281 static const AVClass writer_class = {
282  "Writer",
284  NULL,
286 };
287 
288 static void writer_close(WriterContext **wctx)
289 {
290  int i;
291 
292  if (!*wctx)
293  return;
294 
295  if ((*wctx)->writer->uninit)
296  (*wctx)->writer->uninit(*wctx);
297  for (i = 0; i < SECTION_MAX_NB_LEVELS; i++)
298  av_bprint_finalize(&(*wctx)->section_pbuf[i], NULL);
299  if ((*wctx)->writer->priv_class)
300  av_opt_free((*wctx)->priv);
301  av_freep(&((*wctx)->priv));
302  av_freep(wctx);
303 }
304 
305 static int writer_open(WriterContext **wctx, const Writer *writer, const char *args,
306  const struct section *sections, int nb_sections)
307 {
308  int i, ret = 0;
309 
310  if (!(*wctx = av_mallocz(sizeof(WriterContext)))) {
311  ret = AVERROR(ENOMEM);
312  goto fail;
313  }
314 
315  if (!((*wctx)->priv = av_mallocz(writer->priv_size))) {
316  ret = AVERROR(ENOMEM);
317  goto fail;
318  }
319 
320  (*wctx)->class = &writer_class;
321  (*wctx)->writer = writer;
322  (*wctx)->level = -1;
323  (*wctx)->sections = sections;
324  (*wctx)->nb_sections = nb_sections;
325 
326  if (writer->priv_class) {
327  void *priv_ctx = (*wctx)->priv;
328  *((const AVClass **)priv_ctx) = writer->priv_class;
329  av_opt_set_defaults(priv_ctx);
330 
331  if (args &&
332  (ret = av_set_options_string(priv_ctx, args, "=", ":")) < 0)
333  goto fail;
334  }
335 
336  for (i = 0; i < SECTION_MAX_NB_LEVELS; i++)
337  av_bprint_init(&(*wctx)->section_pbuf[i], 1, AV_BPRINT_SIZE_UNLIMITED);
338 
339  if ((*wctx)->writer->init)
340  ret = (*wctx)->writer->init(*wctx);
341  if (ret < 0)
342  goto fail;
343 
344  return 0;
345 
346 fail:
347  writer_close(wctx);
348  return ret;
349 }
350 
352  int section_id)
353 {
354  int parent_section_id;
355  wctx->level++;
357  parent_section_id = wctx->level ?
358  (wctx->section[wctx->level-1])->id : SECTION_ID_NONE;
359 
360  wctx->nb_item[wctx->level] = 0;
361  wctx->section[wctx->level] = &wctx->sections[section_id];
362 
363  if (section_id == SECTION_ID_PACKETS_AND_FRAMES) {
364  wctx->nb_section_packet = wctx->nb_section_frame =
365  wctx->nb_section_packet_frame = 0;
366  } else if (parent_section_id == SECTION_ID_PACKETS_AND_FRAMES) {
367  wctx->nb_section_packet_frame = section_id == SECTION_ID_PACKET ?
368  wctx->nb_section_packet : wctx->nb_section_frame;
369  }
370 
371  if (wctx->writer->print_section_header)
372  wctx->writer->print_section_header(wctx);
373 }
374 
376 {
377  int section_id = wctx->section[wctx->level]->id;
378  int parent_section_id = wctx->level ?
379  wctx->section[wctx->level-1]->id : SECTION_ID_NONE;
380 
381  if (parent_section_id != SECTION_ID_NONE)
382  wctx->nb_item[wctx->level-1]++;
383  if (parent_section_id == SECTION_ID_PACKETS_AND_FRAMES) {
384  if (section_id == SECTION_ID_PACKET) wctx->nb_section_packet++;
385  else wctx->nb_section_frame++;
386  }
387  if (wctx->writer->print_section_footer)
388  wctx->writer->print_section_footer(wctx);
389  wctx->level--;
390 }
391 
392 static inline void writer_print_integer(WriterContext *wctx,
393  const char *key, long long int val)
394 {
395  const struct section *section = wctx->section[wctx->level];
396 
397  if (section->show_all_entries || av_dict_get(section->entries_to_show, key, NULL, 0)) {
398  wctx->writer->print_integer(wctx, key, val);
399  wctx->nb_item[wctx->level]++;
400  }
401 }
402 
403 static inline void writer_print_string(WriterContext *wctx,
404  const char *key, const char *val, int opt)
405 {
406  const struct section *section = wctx->section[wctx->level];
407 
408  if (opt && !(wctx->writer->flags & WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS))
409  return;
410 
411  if (section->show_all_entries || av_dict_get(section->entries_to_show, key, NULL, 0)) {
412  wctx->writer->print_string(wctx, key, val);
413  wctx->nb_item[wctx->level]++;
414  }
415 }
416 
417 static inline void writer_print_rational(WriterContext *wctx,
418  const char *key, AVRational q, char sep)
419 {
420  AVBPrint buf;
422  av_bprintf(&buf, "%d%c%d", q.num, sep, q.den);
423  writer_print_string(wctx, key, buf.str, 0);
424 }
425 
426 static void writer_print_time(WriterContext *wctx, const char *key,
427  int64_t ts, const AVRational *time_base, int is_duration)
428 {
429  char buf[128];
430 
431  if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0)) {
432  writer_print_string(wctx, key, "N/A", 1);
433  } else {
434  double d = ts * av_q2d(*time_base);
435  struct unit_value uv;
436  uv.val.d = d;
437  uv.unit = unit_second_str;
438  value_string(buf, sizeof(buf), uv);
439  writer_print_string(wctx, key, buf, 0);
440  }
441 }
442 
443 static void writer_print_ts(WriterContext *wctx, const char *key, int64_t ts, int is_duration)
444 {
445  if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0)) {
446  writer_print_string(wctx, key, "N/A", 1);
447  } else {
448  writer_print_integer(wctx, key, ts);
449  }
450 }
451 
452 static void writer_print_data(WriterContext *wctx, const char *name,
453  uint8_t *data, int size)
454 {
455  AVBPrint bp;
456  int offset = 0, l, i;
457 
459  av_bprintf(&bp, "\n");
460  while (size) {
461  av_bprintf(&bp, "%08x: ", offset);
462  l = FFMIN(size, 16);
463  for (i = 0; i < l; i++) {
464  av_bprintf(&bp, "%02x", data[i]);
465  if (i & 1)
466  av_bprintf(&bp, " ");
467  }
468  av_bprint_chars(&bp, ' ', 41 - 2 * i - i / 2);
469  for (i = 0; i < l; i++)
470  av_bprint_chars(&bp, data[i] - 32U < 95 ? data[i] : '.', 1);
471  av_bprintf(&bp, "\n");
472  offset += l;
473  data += l;
474  size -= l;
475  }
476  writer_print_string(wctx, name, bp.str, 0);
477  av_bprint_finalize(&bp, NULL);
478 }
479 
480 #define MAX_REGISTERED_WRITERS_NB 64
481 
483 
484 static int writer_register(const Writer *writer)
485 {
486  static int next_registered_writer_idx = 0;
487 
488  if (next_registered_writer_idx == MAX_REGISTERED_WRITERS_NB)
489  return AVERROR(ENOMEM);
490 
491  registered_writers[next_registered_writer_idx++] = writer;
492  return 0;
493 }
494 
495 static const Writer *writer_get_by_name(const char *name)
496 {
497  int i;
498 
499  for (i = 0; registered_writers[i]; i++)
500  if (!strcmp(registered_writers[i]->name, name))
501  return registered_writers[i];
502 
503  return NULL;
504 }
505 
506 
507 /* WRITERS */
508 
509 #define DEFINE_WRITER_CLASS(name) \
510 static const char *name##_get_name(void *ctx) \
511 { \
512  return #name ; \
513 } \
514 static const AVClass name##_class = { \
515  #name, \
516  name##_get_name, \
517  name##_options \
518 }
519 
520 /* Default output */
521 
522 typedef struct DefaultContext {
523  const AVClass *class;
524  int nokey;
528 
529 #define OFFSET(x) offsetof(DefaultContext, x)
530 
531 static const AVOption default_options[] = {
532  { "noprint_wrappers", "do not print headers and footers", OFFSET(noprint_wrappers), AV_OPT_TYPE_INT, {.i64=0}, 0, 1 },
533  { "nw", "do not print headers and footers", OFFSET(noprint_wrappers), AV_OPT_TYPE_INT, {.i64=0}, 0, 1 },
534  { "nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_INT, {.i64=0}, 0, 1 },
535  { "nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_INT, {.i64=0}, 0, 1 },
536  {NULL},
537 };
538 
539 DEFINE_WRITER_CLASS(default);
540 
541 /* lame uppercasing routine, assumes the string is lower case ASCII */
542 static inline char *upcase_string(char *dst, size_t dst_size, const char *src)
543 {
544  int i;
545  for (i = 0; src[i] && i < dst_size-1; i++)
546  dst[i] = av_toupper(src[i]);
547  dst[i] = 0;
548  return dst;
549 }
550 
552 {
553  DefaultContext *def = wctx->priv;
554  char buf[32];
555  const struct section *section = wctx->section[wctx->level];
556  const struct section *parent_section = wctx->level ?
557  wctx->section[wctx->level-1] : NULL;
558 
559  av_bprint_clear(&wctx->section_pbuf[wctx->level]);
560  if (parent_section &&
561  !(parent_section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))) {
562  def->nested_section[wctx->level] = 1;
563  av_bprintf(&wctx->section_pbuf[wctx->level], "%s%s:",
564  wctx->section_pbuf[wctx->level-1].str,
565  upcase_string(buf, sizeof(buf),
566  av_x_if_null(section->element_name, section->name)));
567  }
568 
569  if (def->noprint_wrappers || def->nested_section[wctx->level])
570  return;
571 
573  printf("[%s]\n", upcase_string(buf, sizeof(buf), section->name));
574 }
575 
577 {
578  DefaultContext *def = wctx->priv;
579  const struct section *section = wctx->section[wctx->level];
580  char buf[32];
581 
582  if (def->noprint_wrappers || def->nested_section[wctx->level])
583  return;
584 
586  printf("[/%s]\n", upcase_string(buf, sizeof(buf), section->name));
587 }
588 
589 static void default_print_str(WriterContext *wctx, const char *key, const char *value)
590 {
591  DefaultContext *def = wctx->priv;
592 
593  if (!def->nokey)
594  printf("%s%s=", wctx->section_pbuf[wctx->level].str, key);
595  printf("%s\n", value);
596 }
597 
598 static void default_print_int(WriterContext *wctx, const char *key, long long int value)
599 {
600  DefaultContext *def = wctx->priv;
601 
602  if (!def->nokey)
603  printf("%s%s=", wctx->section_pbuf[wctx->level].str, key);
604  printf("%lld\n", value);
605 }
606 
607 static const Writer default_writer = {
608  .name = "default",
609  .priv_size = sizeof(DefaultContext),
612  .print_integer = default_print_int,
613  .print_string = default_print_str,
615  .priv_class = &default_class,
616 };
617 
618 /* Compact output */
619 
620 /**
621  * Apply C-language-like string escaping.
622  */
623 static const char *c_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
624 {
625  const char *p;
626 
627  for (p = src; *p; p++) {
628  switch (*p) {
629  case '\b': av_bprintf(dst, "%s", "\\b"); break;
630  case '\f': av_bprintf(dst, "%s", "\\f"); break;
631  case '\n': av_bprintf(dst, "%s", "\\n"); break;
632  case '\r': av_bprintf(dst, "%s", "\\r"); break;
633  case '\\': av_bprintf(dst, "%s", "\\\\"); break;
634  default:
635  if (*p == sep)
636  av_bprint_chars(dst, '\\', 1);
637  av_bprint_chars(dst, *p, 1);
638  }
639  }
640  return dst->str;
641 }
642 
643 /**
644  * Quote fields containing special characters, check RFC4180.
645  */
646 static const char *csv_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
647 {
648  char meta_chars[] = { sep, '"', '\n', '\r', '\0' };
649  int needs_quoting = !!src[strcspn(src, meta_chars)];
650 
651  if (needs_quoting)
652  av_bprint_chars(dst, '"', 1);
653 
654  for (; *src; src++) {
655  if (*src == '"')
656  av_bprint_chars(dst, '"', 1);
657  av_bprint_chars(dst, *src, 1);
658  }
659  if (needs_quoting)
660  av_bprint_chars(dst, '"', 1);
661  return dst->str;
662 }
663 
664 static const char *none_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
665 {
666  return src;
667 }
668 
669 typedef struct CompactContext {
670  const AVClass *class;
672  char item_sep;
673  int nokey;
676  const char * (*escape_str)(AVBPrint *dst, const char *src, const char sep, void *log_ctx);
679 
680 #undef OFFSET
681 #define OFFSET(x) offsetof(CompactContext, x)
682 
683 static const AVOption compact_options[]= {
684  {"item_sep", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str="|"}, CHAR_MIN, CHAR_MAX },
685  {"s", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str="|"}, CHAR_MIN, CHAR_MAX },
686  {"nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_INT, {.i64=0}, 0, 1 },
687  {"nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_INT, {.i64=0}, 0, 1 },
688  {"escape", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="c"}, CHAR_MIN, CHAR_MAX },
689  {"e", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="c"}, CHAR_MIN, CHAR_MAX },
690  {"print_section", "print section name", OFFSET(print_section), AV_OPT_TYPE_INT, {.i64=1}, 0, 1 },
691  {"p", "print section name", OFFSET(print_section), AV_OPT_TYPE_INT, {.i64=1}, 0, 1 },
692  {NULL},
693 };
694 
695 DEFINE_WRITER_CLASS(compact);
696 
698 {
699  CompactContext *compact = wctx->priv;
700 
701  if (strlen(compact->item_sep_str) != 1) {
702  av_log(wctx, AV_LOG_ERROR, "Item separator '%s' specified, but must contain a single character\n",
703  compact->item_sep_str);
704  return AVERROR(EINVAL);
705  }
706  compact->item_sep = compact->item_sep_str[0];
707 
708  if (!strcmp(compact->escape_mode_str, "none")) compact->escape_str = none_escape_str;
709  else if (!strcmp(compact->escape_mode_str, "c" )) compact->escape_str = c_escape_str;
710  else if (!strcmp(compact->escape_mode_str, "csv" )) compact->escape_str = csv_escape_str;
711  else {
712  av_log(wctx, AV_LOG_ERROR, "Unknown escape mode '%s'\n", compact->escape_mode_str);
713  return AVERROR(EINVAL);
714  }
715 
716  return 0;
717 }
718 
720 {
721  CompactContext *compact = wctx->priv;
722  const struct section *section = wctx->section[wctx->level];
723  const struct section *parent_section = wctx->level ?
724  wctx->section[wctx->level-1] : NULL;
725 
726  av_bprint_clear(&wctx->section_pbuf[wctx->level]);
727  if (parent_section &&
728  !(parent_section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))) {
729  compact->nested_section[wctx->level] = 1;
730  av_bprintf(&wctx->section_pbuf[wctx->level], "%s%s:",
731  wctx->section_pbuf[wctx->level-1].str,
732  (char *)av_x_if_null(section->element_name, section->name));
733  wctx->nb_item[wctx->level] = wctx->nb_item[wctx->level-1];
734  } else if (compact->print_section &&
736  printf("%s%c", section->name, compact->item_sep);
737 }
738 
740 {
741  CompactContext *compact = wctx->priv;
742 
743  if (!compact->nested_section[wctx->level] &&
745  printf("\n");
746 }
747 
748 static void compact_print_str(WriterContext *wctx, const char *key, const char *value)
749 {
750  CompactContext *compact = wctx->priv;
751  AVBPrint buf;
752 
753  if (wctx->nb_item[wctx->level]) printf("%c", compact->item_sep);
754  if (!compact->nokey)
755  printf("%s%s=", wctx->section_pbuf[wctx->level].str, key);
757  printf("%s", compact->escape_str(&buf, value, compact->item_sep, wctx));
758  av_bprint_finalize(&buf, NULL);
759 }
760 
761 static void compact_print_int(WriterContext *wctx, const char *key, long long int value)
762 {
763  CompactContext *compact = wctx->priv;
764 
765  if (wctx->nb_item[wctx->level]) printf("%c", compact->item_sep);
766  if (!compact->nokey)
767  printf("%s%s=", wctx->section_pbuf[wctx->level].str, key);
768  printf("%lld", value);
769 }
770 
771 static const Writer compact_writer = {
772  .name = "compact",
773  .priv_size = sizeof(CompactContext),
774  .init = compact_init,
777  .print_integer = compact_print_int,
778  .print_string = compact_print_str,
780  .priv_class = &compact_class,
781 };
782 
783 /* CSV output */
784 
785 #undef OFFSET
786 #define OFFSET(x) offsetof(CompactContext, x)
787 
788 static const AVOption csv_options[] = {
789  {"item_sep", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str=","}, CHAR_MIN, CHAR_MAX },
790  {"s", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str=","}, CHAR_MIN, CHAR_MAX },
791  {"nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_INT, {.i64=1}, 0, 1 },
792  {"nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_INT, {.i64=1}, 0, 1 },
793  {"escape", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="csv"}, CHAR_MIN, CHAR_MAX },
794  {"e", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="csv"}, CHAR_MIN, CHAR_MAX },
795  {"print_section", "print section name", OFFSET(print_section), AV_OPT_TYPE_INT, {.i64=1}, 0, 1 },
796  {"p", "print section name", OFFSET(print_section), AV_OPT_TYPE_INT, {.i64=1}, 0, 1 },
797  {NULL},
798 };
799 
801 
802 static const Writer csv_writer = {
803  .name = "csv",
804  .priv_size = sizeof(CompactContext),
805  .init = compact_init,
808  .print_integer = compact_print_int,
809  .print_string = compact_print_str,
811  .priv_class = &csv_class,
812 };
813 
814 /* Flat output */
815 
816 typedef struct FlatContext {
817  const AVClass *class;
818  const char *sep_str;
819  char sep;
821 } FlatContext;
822 
823 #undef OFFSET
824 #define OFFSET(x) offsetof(FlatContext, x)
825 
826 static const AVOption flat_options[]= {
827  {"sep_char", "set separator", OFFSET(sep_str), AV_OPT_TYPE_STRING, {.str="."}, CHAR_MIN, CHAR_MAX },
828  {"s", "set separator", OFFSET(sep_str), AV_OPT_TYPE_STRING, {.str="."}, CHAR_MIN, CHAR_MAX },
829  {"hierarchical", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_INT, {.i64=1}, 0, 1 },
830  {"h", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_INT, {.i64=1}, 0, 1 },
831  {NULL},
832 };
833 
834 DEFINE_WRITER_CLASS(flat);
835 
836 static av_cold int flat_init(WriterContext *wctx)
837 {
838  FlatContext *flat = wctx->priv;
839 
840  if (strlen(flat->sep_str) != 1) {
841  av_log(wctx, AV_LOG_ERROR, "Item separator '%s' specified, but must contain a single character\n",
842  flat->sep_str);
843  return AVERROR(EINVAL);
844  }
845  flat->sep = flat->sep_str[0];
846 
847  return 0;
848 }
849 
850 static const char *flat_escape_key_str(AVBPrint *dst, const char *src, const char sep)
851 {
852  const char *p;
853 
854  for (p = src; *p; p++) {
855  if (!((*p >= '0' && *p <= '9') ||
856  (*p >= 'a' && *p <= 'z') ||
857  (*p >= 'A' && *p <= 'Z')))
858  av_bprint_chars(dst, '_', 1);
859  else
860  av_bprint_chars(dst, *p, 1);
861  }
862  return dst->str;
863 }
864 
865 static const char *flat_escape_value_str(AVBPrint *dst, const char *src)
866 {
867  const char *p;
868 
869  for (p = src; *p; p++) {
870  switch (*p) {
871  case '\n': av_bprintf(dst, "%s", "\\n"); break;
872  case '\r': av_bprintf(dst, "%s", "\\r"); break;
873  case '\\': av_bprintf(dst, "%s", "\\\\"); break;
874  case '"': av_bprintf(dst, "%s", "\\\""); break;
875  case '`': av_bprintf(dst, "%s", "\\`"); break;
876  case '$': av_bprintf(dst, "%s", "\\$"); break;
877  default: av_bprint_chars(dst, *p, 1); break;
878  }
879  }
880  return dst->str;
881 }
882 
884 {
885  FlatContext *flat = wctx->priv;
886  AVBPrint *buf = &wctx->section_pbuf[wctx->level];
887  const struct section *section = wctx->section[wctx->level];
888  const struct section *parent_section = wctx->level ?
889  wctx->section[wctx->level-1] : NULL;
890 
891  /* build section header */
892  av_bprint_clear(buf);
893  if (!parent_section)
894  return;
895  av_bprintf(buf, "%s", wctx->section_pbuf[wctx->level-1].str);
896 
897  if (flat->hierarchical ||
899  av_bprintf(buf, "%s%s", wctx->section[wctx->level]->name, flat->sep_str);
900 
901  if (parent_section->flags & SECTION_FLAG_IS_ARRAY) {
902  int n = parent_section->id == SECTION_ID_PACKETS_AND_FRAMES ?
903  wctx->nb_section_packet_frame : wctx->nb_item[wctx->level-1];
904  av_bprintf(buf, "%d%s", n, flat->sep_str);
905  }
906  }
907 }
908 
909 static void flat_print_int(WriterContext *wctx, const char *key, long long int value)
910 {
911  printf("%s%s=%lld\n", wctx->section_pbuf[wctx->level].str, key, value);
912 }
913 
914 static void flat_print_str(WriterContext *wctx, const char *key, const char *value)
915 {
916  FlatContext *flat = wctx->priv;
917  AVBPrint buf;
918 
919  printf("%s", wctx->section_pbuf[wctx->level].str);
921  printf("%s=", flat_escape_key_str(&buf, key, flat->sep));
922  av_bprint_clear(&buf);
923  printf("\"%s\"\n", flat_escape_value_str(&buf, value));
924  av_bprint_finalize(&buf, NULL);
925 }
926 
927 static const Writer flat_writer = {
928  .name = "flat",
929  .priv_size = sizeof(FlatContext),
930  .init = flat_init,
932  .print_integer = flat_print_int,
933  .print_string = flat_print_str,
935  .priv_class = &flat_class,
936 };
937 
938 /* INI format output */
939 
940 typedef struct {
941  const AVClass *class;
943 } INIContext;
944 
945 #undef OFFSET
946 #define OFFSET(x) offsetof(INIContext, x)
947 
948 static const AVOption ini_options[] = {
949  {"hierarchical", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_INT, {.i64=1}, 0, 1 },
950  {"h", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_INT, {.i64=1}, 0, 1 },
951  {NULL},
952 };
953 
955 
956 static char *ini_escape_str(AVBPrint *dst, const char *src)
957 {
958  int i = 0;
959  char c = 0;
960 
961  while (c = src[i++]) {
962  switch (c) {
963  case '\b': av_bprintf(dst, "%s", "\\b"); break;
964  case '\f': av_bprintf(dst, "%s", "\\f"); break;
965  case '\n': av_bprintf(dst, "%s", "\\n"); break;
966  case '\r': av_bprintf(dst, "%s", "\\r"); break;
967  case '\t': av_bprintf(dst, "%s", "\\t"); break;
968  case '\\':
969  case '#' :
970  case '=' :
971  case ':' : av_bprint_chars(dst, '\\', 1);
972  default:
973  if ((unsigned char)c < 32)
974  av_bprintf(dst, "\\x00%02x", c & 0xff);
975  else
976  av_bprint_chars(dst, c, 1);
977  break;
978  }
979  }
980  return dst->str;
981 }
982 
984 {
985  INIContext *ini = wctx->priv;
986  AVBPrint *buf = &wctx->section_pbuf[wctx->level];
987  const struct section *section = wctx->section[wctx->level];
988  const struct section *parent_section = wctx->level ?
989  wctx->section[wctx->level-1] : NULL;
990 
991  av_bprint_clear(buf);
992  if (!parent_section) {
993  printf("# ffprobe output\n\n");
994  return;
995  }
996 
997  if (wctx->nb_item[wctx->level-1])
998  printf("\n");
999 
1000  av_bprintf(buf, "%s", wctx->section_pbuf[wctx->level-1].str);
1001  if (ini->hierarchical ||
1003  av_bprintf(buf, "%s%s", buf->str[0] ? "." : "", wctx->section[wctx->level]->name);
1004 
1005  if (parent_section->flags & SECTION_FLAG_IS_ARRAY) {
1006  int n = parent_section->id == SECTION_ID_PACKETS_AND_FRAMES ?
1007  wctx->nb_section_packet_frame : wctx->nb_item[wctx->level-1];
1008  av_bprintf(buf, ".%d", n);
1009  }
1010  }
1011 
1013  printf("[%s]\n", buf->str);
1014 }
1015 
1016 static void ini_print_str(WriterContext *wctx, const char *key, const char *value)
1017 {
1018  AVBPrint buf;
1019 
1021  printf("%s=", ini_escape_str(&buf, key));
1022  av_bprint_clear(&buf);
1023  printf("%s\n", ini_escape_str(&buf, value));
1024  av_bprint_finalize(&buf, NULL);
1025 }
1026 
1027 static void ini_print_int(WriterContext *wctx, const char *key, long long int value)
1028 {
1029  printf("%s=%lld\n", key, value);
1030 }
1031 
1032 static const Writer ini_writer = {
1033  .name = "ini",
1034  .priv_size = sizeof(INIContext),
1036  .print_integer = ini_print_int,
1037  .print_string = ini_print_str,
1039  .priv_class = &ini_class,
1040 };
1041 
1042 /* JSON output */
1043 
1044 typedef struct {
1045  const AVClass *class;
1047  int compact;
1048  const char *item_sep, *item_start_end;
1049 } JSONContext;
1050 
1051 #undef OFFSET
1052 #define OFFSET(x) offsetof(JSONContext, x)
1053 
1054 static const AVOption json_options[]= {
1055  { "compact", "enable compact output", OFFSET(compact), AV_OPT_TYPE_INT, {.i64=0}, 0, 1 },
1056  { "c", "enable compact output", OFFSET(compact), AV_OPT_TYPE_INT, {.i64=0}, 0, 1 },
1057  { NULL }
1058 };
1059 
1060 DEFINE_WRITER_CLASS(json);
1061 
1063 {
1064  JSONContext *json = wctx->priv;
1065 
1066  json->item_sep = json->compact ? ", " : ",\n";
1067  json->item_start_end = json->compact ? " " : "\n";
1068 
1069  return 0;
1070 }
1071 
1072 static const char *json_escape_str(AVBPrint *dst, const char *src, void *log_ctx)
1073 {
1074  static const char json_escape[] = {'"', '\\', '\b', '\f', '\n', '\r', '\t', 0};
1075  static const char json_subst[] = {'"', '\\', 'b', 'f', 'n', 'r', 't', 0};
1076  const char *p;
1077 
1078  for (p = src; *p; p++) {
1079  char *s = strchr(json_escape, *p);
1080  if (s) {
1081  av_bprint_chars(dst, '\\', 1);
1082  av_bprint_chars(dst, json_subst[s - json_escape], 1);
1083  } else if ((unsigned char)*p < 32) {
1084  av_bprintf(dst, "\\u00%02x", *p & 0xff);
1085  } else {
1086  av_bprint_chars(dst, *p, 1);
1087  }
1088  }
1089  return dst->str;
1090 }
1091 
1092 #define JSON_INDENT() printf("%*c", json->indent_level * 4, ' ')
1093 
1095 {
1096  JSONContext *json = wctx->priv;
1097  AVBPrint buf;
1098  const struct section *section = wctx->section[wctx->level];
1099  const struct section *parent_section = wctx->level ?
1100  wctx->section[wctx->level-1] : NULL;
1101 
1102  if (wctx->level && wctx->nb_item[wctx->level-1])
1103  printf(",\n");
1104 
1105  if (section->flags & SECTION_FLAG_IS_WRAPPER) {
1106  printf("{\n");
1107  json->indent_level++;
1108  } else {
1110  json_escape_str(&buf, section->name, wctx);
1111  JSON_INDENT();
1112 
1113  json->indent_level++;
1114  if (section->flags & SECTION_FLAG_IS_ARRAY) {
1115  printf("\"%s\": [\n", buf.str);
1116  } else if (parent_section && !(parent_section->flags & SECTION_FLAG_IS_ARRAY)) {
1117  printf("\"%s\": {%s", buf.str, json->item_start_end);
1118  } else {
1119  printf("{%s", json->item_start_end);
1120 
1121  /* this is required so the parser can distinguish between packets and frames */
1122  if (parent_section && parent_section->id == SECTION_ID_PACKETS_AND_FRAMES) {
1123  if (!json->compact)
1124  JSON_INDENT();
1125  printf("\"type\": \"%s\"%s", section->name, json->item_sep);
1126  }
1127  }
1128  av_bprint_finalize(&buf, NULL);
1129  }
1130 }
1131 
1133 {
1134  JSONContext *json = wctx->priv;
1135  const struct section *section = wctx->section[wctx->level];
1136 
1137  if (wctx->level == 0) {
1138  json->indent_level--;
1139  printf("\n}\n");
1140  } else if (section->flags & SECTION_FLAG_IS_ARRAY) {
1141  printf("\n");
1142  json->indent_level--;
1143  JSON_INDENT();
1144  printf("]");
1145  } else {
1146  printf("%s", json->item_start_end);
1147  json->indent_level--;
1148  if (!json->compact)
1149  JSON_INDENT();
1150  printf("}");
1151  }
1152 }
1153 
1154 static inline void json_print_item_str(WriterContext *wctx,
1155  const char *key, const char *value)
1156 {
1157  AVBPrint buf;
1158 
1160  printf("\"%s\":", json_escape_str(&buf, key, wctx));
1161  av_bprint_clear(&buf);
1162  printf(" \"%s\"", json_escape_str(&buf, value, wctx));
1163  av_bprint_finalize(&buf, NULL);
1164 }
1165 
1166 static void json_print_str(WriterContext *wctx, const char *key, const char *value)
1167 {
1168  JSONContext *json = wctx->priv;
1169 
1170  if (wctx->nb_item[wctx->level])
1171  printf("%s", json->item_sep);
1172  if (!json->compact)
1173  JSON_INDENT();
1174  json_print_item_str(wctx, key, value);
1175 }
1176 
1177 static void json_print_int(WriterContext *wctx, const char *key, long long int value)
1178 {
1179  JSONContext *json = wctx->priv;
1180  AVBPrint buf;
1181 
1182  if (wctx->nb_item[wctx->level])
1183  printf("%s", json->item_sep);
1184  if (!json->compact)
1185  JSON_INDENT();
1186 
1188  printf("\"%s\": %lld", json_escape_str(&buf, key, wctx), value);
1189  av_bprint_finalize(&buf, NULL);
1190 }
1191 
1192 static const Writer json_writer = {
1193  .name = "json",
1194  .priv_size = sizeof(JSONContext),
1195  .init = json_init,
1198  .print_integer = json_print_int,
1199  .print_string = json_print_str,
1201  .priv_class = &json_class,
1202 };
1203 
1204 /* XML output */
1205 
1206 typedef struct {
1207  const AVClass *class;
1212 } XMLContext;
1213 
1214 #undef OFFSET
1215 #define OFFSET(x) offsetof(XMLContext, x)
1216 
1217 static const AVOption xml_options[] = {
1218  {"fully_qualified", "specify if the output should be fully qualified", OFFSET(fully_qualified), AV_OPT_TYPE_INT, {.i64=0}, 0, 1 },
1219  {"q", "specify if the output should be fully qualified", OFFSET(fully_qualified), AV_OPT_TYPE_INT, {.i64=0}, 0, 1 },
1220  {"xsd_strict", "ensure that the output is XSD compliant", OFFSET(xsd_strict), AV_OPT_TYPE_INT, {.i64=0}, 0, 1 },
1221  {"x", "ensure that the output is XSD compliant", OFFSET(xsd_strict), AV_OPT_TYPE_INT, {.i64=0}, 0, 1 },
1222  {NULL},
1223 };
1224 
1225 DEFINE_WRITER_CLASS(xml);
1226 
1227 static av_cold int xml_init(WriterContext *wctx)
1228 {
1229  XMLContext *xml = wctx->priv;
1230 
1231  if (xml->xsd_strict) {
1232  xml->fully_qualified = 1;
1233 #define CHECK_COMPLIANCE(opt, opt_name) \
1234  if (opt) { \
1235  av_log(wctx, AV_LOG_ERROR, \
1236  "XSD-compliant output selected but option '%s' was selected, XML output may be non-compliant.\n" \
1237  "You need to disable such option with '-no%s'\n", opt_name, opt_name); \
1238  return AVERROR(EINVAL); \
1239  }
1240  CHECK_COMPLIANCE(show_private_data, "private");
1243 
1245  av_log(wctx, AV_LOG_ERROR,
1246  "Interleaved frames and packets are not allowed in XSD. "
1247  "Select only one between the -show_frames and the -show_packets options.\n");
1248  return AVERROR(EINVAL);
1249  }
1250  }
1251 
1252  return 0;
1253 }
1254 
1255 static const char *xml_escape_str(AVBPrint *dst, const char *src, void *log_ctx)
1256 {
1257  const char *p;
1258 
1259  for (p = src; *p; p++) {
1260  switch (*p) {
1261  case '&' : av_bprintf(dst, "%s", "&amp;"); break;
1262  case '<' : av_bprintf(dst, "%s", "&lt;"); break;
1263  case '>' : av_bprintf(dst, "%s", "&gt;"); break;
1264  case '"' : av_bprintf(dst, "%s", "&quot;"); break;
1265  case '\'': av_bprintf(dst, "%s", "&apos;"); break;
1266  default: av_bprint_chars(dst, *p, 1);
1267  }
1268  }
1269 
1270  return dst->str;
1271 }
1272 
1273 #define XML_INDENT() printf("%*c", xml->indent_level * 4, ' ')
1274 
1276 {
1277  XMLContext *xml = wctx->priv;
1278  const struct section *section = wctx->section[wctx->level];
1279  const struct section *parent_section = wctx->level ?
1280  wctx->section[wctx->level-1] : NULL;
1281 
1282  if (wctx->level == 0) {
1283  const char *qual = " xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' "
1284  "xmlns:ffprobe='http://www.ffmpeg.org/schema/ffprobe' "
1285  "xsi:schemaLocation='http://www.ffmpeg.org/schema/ffprobe ffprobe.xsd'";
1286 
1287  printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1288  printf("<%sffprobe%s>\n",
1289  xml->fully_qualified ? "ffprobe:" : "",
1290  xml->fully_qualified ? qual : "");
1291  return;
1292  }
1293 
1294  if (xml->within_tag) {
1295  xml->within_tag = 0;
1296  printf(">\n");
1297  }
1298  if (section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS) {
1299  xml->indent_level++;
1300  } else {
1301  if (parent_section && (parent_section->flags & SECTION_FLAG_IS_WRAPPER) &&
1302  wctx->level && wctx->nb_item[wctx->level-1])
1303  printf("\n");
1304  xml->indent_level++;
1305 
1306  if (section->flags & SECTION_FLAG_IS_ARRAY) {
1307  XML_INDENT(); printf("<%s>\n", section->name);
1308  } else {
1309  XML_INDENT(); printf("<%s ", section->name);
1310  xml->within_tag = 1;
1311  }
1312  }
1313 }
1314 
1316 {
1317  XMLContext *xml = wctx->priv;
1318  const struct section *section = wctx->section[wctx->level];
1319 
1320  if (wctx->level == 0) {
1321  printf("</%sffprobe>\n", xml->fully_qualified ? "ffprobe:" : "");
1322  } else if (xml->within_tag) {
1323  xml->within_tag = 0;
1324  printf("/>\n");
1325  xml->indent_level--;
1326  } else if (section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS) {
1327  xml->indent_level--;
1328  } else {
1329  XML_INDENT(); printf("</%s>\n", section->name);
1330  xml->indent_level--;
1331  }
1332 }
1333 
1334 static void xml_print_str(WriterContext *wctx, const char *key, const char *value)
1335 {
1336  AVBPrint buf;
1337  XMLContext *xml = wctx->priv;
1338  const struct section *section = wctx->section[wctx->level];
1339 
1341 
1342  if (section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS) {
1343  XML_INDENT();
1344  printf("<%s key=\"%s\"",
1345  section->element_name, xml_escape_str(&buf, key, wctx));
1346  av_bprint_clear(&buf);
1347  printf(" value=\"%s\"/>\n", xml_escape_str(&buf, value, wctx));
1348  } else {
1349  if (wctx->nb_item[wctx->level])
1350  printf(" ");
1351  printf("%s=\"%s\"", key, xml_escape_str(&buf, value, wctx));
1352  }
1353 
1354  av_bprint_finalize(&buf, NULL);
1355 }
1356 
1357 static void xml_print_int(WriterContext *wctx, const char *key, long long int value)
1358 {
1359  if (wctx->nb_item[wctx->level])
1360  printf(" ");
1361  printf("%s=\"%lld\"", key, value);
1362 }
1363 
1364 static Writer xml_writer = {
1365  .name = "xml",
1366  .priv_size = sizeof(XMLContext),
1367  .init = xml_init,
1370  .print_integer = xml_print_int,
1371  .print_string = xml_print_str,
1373  .priv_class = &xml_class,
1374 };
1375 
1376 static void writer_register_all(void)
1377 {
1378  static int initialized;
1379 
1380  if (initialized)
1381  return;
1382  initialized = 1;
1383 
1384  writer_register(&default_writer);
1385  writer_register(&compact_writer);
1386  writer_register(&csv_writer);
1387  writer_register(&flat_writer);
1388  writer_register(&ini_writer);
1389  writer_register(&json_writer);
1390  writer_register(&xml_writer);
1391 }
1392 
1393 #define print_fmt(k, f, ...) do { \
1394  av_bprint_clear(&pbuf); \
1395  av_bprintf(&pbuf, f, __VA_ARGS__); \
1396  writer_print_string(w, k, pbuf.str, 0); \
1397 } while (0)
1398 
1399 #define print_int(k, v) writer_print_integer(w, k, v)
1400 #define print_q(k, v, s) writer_print_rational(w, k, v, s)
1401 #define print_str(k, v) writer_print_string(w, k, v, 0)
1402 #define print_str_opt(k, v) writer_print_string(w, k, v, 1)
1403 #define print_time(k, v, tb) writer_print_time(w, k, v, tb, 0)
1404 #define print_ts(k, v) writer_print_ts(w, k, v, 0)
1405 #define print_duration_time(k, v, tb) writer_print_time(w, k, v, tb, 1)
1406 #define print_duration_ts(k, v) writer_print_ts(w, k, v, 1)
1407 #define print_val(k, v, u) do { \
1408  struct unit_value uv; \
1409  uv.val.i = v; \
1410  uv.unit = u; \
1411  writer_print_string(w, k, value_string(val_str, sizeof(val_str), uv), 0); \
1412 } while (0)
1413 
1414 #define print_section_header(s) writer_print_section_header(w, s)
1415 #define print_section_footer(s) writer_print_section_footer(w, s)
1416 
1417 static inline void show_tags(WriterContext *wctx, AVDictionary *tags, int section_id)
1418 {
1419  AVDictionaryEntry *tag = NULL;
1420 
1421  if (!tags)
1422  return;
1423  writer_print_section_header(wctx, section_id);
1424  while ((tag = av_dict_get(tags, "", tag, AV_DICT_IGNORE_SUFFIX)))
1425  writer_print_string(wctx, tag->key, tag->value, 0);
1427 }
1428 
1429 static void show_packet(WriterContext *w, AVFormatContext *fmt_ctx, AVPacket *pkt, int packet_idx)
1430 {
1431  char val_str[128];
1432  AVStream *st = fmt_ctx->streams[pkt->stream_index];
1433  AVBPrint pbuf;
1434  const char *s;
1435 
1437 
1439 
1441  if (s) print_str ("codec_type", s);
1442  else print_str_opt("codec_type", "unknown");
1443  print_int("stream_index", pkt->stream_index);
1444  print_ts ("pts", pkt->pts);
1445  print_time("pts_time", pkt->pts, &st->time_base);
1446  print_ts ("dts", pkt->dts);
1447  print_time("dts_time", pkt->dts, &st->time_base);
1448  print_duration_ts("duration", pkt->duration);
1449  print_duration_time("duration_time", pkt->duration, &st->time_base);
1450  print_duration_ts("convergence_duration", pkt->convergence_duration);
1451  print_duration_time("convergence_duration_time", pkt->convergence_duration, &st->time_base);
1452  print_val("size", pkt->size, unit_byte_str);
1453  if (pkt->pos != -1) print_fmt ("pos", "%"PRId64, pkt->pos);
1454  else print_str_opt("pos", "N/A");
1455  print_fmt("flags", "%c", pkt->flags & AV_PKT_FLAG_KEY ? 'K' : '_');
1456  if (do_show_data)
1457  writer_print_data(w, "data", pkt->data, pkt->size);
1459 
1460  av_bprint_finalize(&pbuf, NULL);
1461  fflush(stdout);
1462 }
1463 
1464 static void show_frame(WriterContext *w, AVFrame *frame, AVStream *stream,
1466 {
1467  AVBPrint pbuf;
1468  const char *s;
1469 
1471 
1473 
1475  if (s) print_str ("media_type", s);
1476  else print_str_opt("media_type", "unknown");
1477  print_int("key_frame", frame->key_frame);
1478  print_ts ("pkt_pts", frame->pkt_pts);
1479  print_time("pkt_pts_time", frame->pkt_pts, &stream->time_base);
1480  print_ts ("pkt_dts", frame->pkt_dts);
1481  print_time("pkt_dts_time", frame->pkt_dts, &stream->time_base);
1482  print_duration_ts ("pkt_duration", av_frame_get_pkt_duration(frame));
1483  print_duration_time("pkt_duration_time", av_frame_get_pkt_duration(frame), &stream->time_base);
1484  if (av_frame_get_pkt_pos (frame) != -1) print_fmt ("pkt_pos", "%"PRId64, av_frame_get_pkt_pos(frame));
1485  else print_str_opt("pkt_pos", "N/A");
1486  if (av_frame_get_pkt_size(frame) != -1) print_fmt ("pkt_size", "%d", av_frame_get_pkt_size(frame));
1487  else print_str_opt("pkt_size", "N/A");
1488 
1489  switch (stream->codec->codec_type) {
1490  AVRational sar;
1491 
1492  case AVMEDIA_TYPE_VIDEO:
1493  print_int("width", frame->width);
1494  print_int("height", frame->height);
1495  s = av_get_pix_fmt_name(frame->format);
1496  if (s) print_str ("pix_fmt", s);
1497  else print_str_opt("pix_fmt", "unknown");
1498  sar = av_guess_sample_aspect_ratio(fmt_ctx, stream, frame);
1499  if (sar.num) {
1500  print_q("sample_aspect_ratio", sar, ':');
1501  } else {
1502  print_str_opt("sample_aspect_ratio", "N/A");
1503  }
1504  print_fmt("pict_type", "%c", av_get_picture_type_char(frame->pict_type));
1505  print_int("coded_picture_number", frame->coded_picture_number);
1506  print_int("display_picture_number", frame->display_picture_number);
1507  print_int("interlaced_frame", frame->interlaced_frame);
1508  print_int("top_field_first", frame->top_field_first);
1509  print_int("repeat_pict", frame->repeat_pict);
1510  break;
1511 
1512  case AVMEDIA_TYPE_AUDIO:
1513  s = av_get_sample_fmt_name(frame->format);
1514  if (s) print_str ("sample_fmt", s);
1515  else print_str_opt("sample_fmt", "unknown");
1516  print_int("nb_samples", frame->nb_samples);
1517  print_int("channels", av_frame_get_channels(frame));
1518  if (av_frame_get_channel_layout(frame)) {
1519  av_bprint_clear(&pbuf);
1522  print_str ("channel_layout", pbuf.str);
1523  } else
1524  print_str_opt("channel_layout", "unknown");
1525  break;
1526  }
1528 
1530 
1531  av_bprint_finalize(&pbuf, NULL);
1532  fflush(stdout);
1533 }
1534 
1538 {
1539  AVCodecContext *dec_ctx = fmt_ctx->streams[pkt->stream_index]->codec;
1540  int ret = 0, got_frame = 0;
1541 
1543  if (dec_ctx->codec) {
1544  switch (dec_ctx->codec_type) {
1545  case AVMEDIA_TYPE_VIDEO:
1546  ret = avcodec_decode_video2(dec_ctx, frame, &got_frame, pkt);
1547  break;
1548 
1549  case AVMEDIA_TYPE_AUDIO:
1550  ret = avcodec_decode_audio4(dec_ctx, frame, &got_frame, pkt);
1551  break;
1552  }
1553  }
1554 
1555  if (ret < 0)
1556  return ret;
1557  ret = FFMIN(ret, pkt->size); /* guard against bogus return values */
1558  pkt->data += ret;
1559  pkt->size -= ret;
1560  if (got_frame) {
1562  if (do_show_frames)
1563  show_frame(w, frame, fmt_ctx->streams[pkt->stream_index], fmt_ctx);
1564  }
1565  return got_frame;
1566 }
1567 
1569 {
1570  AVPacket pkt, pkt1;
1571  AVFrame frame;
1572  int i = 0;
1573 
1574  av_init_packet(&pkt);
1575 
1576  while (!av_read_frame(fmt_ctx, &pkt)) {
1577  if (selected_streams[pkt.stream_index]) {
1578  if (do_read_packets) {
1579  if (do_show_packets)
1580  show_packet(w, fmt_ctx, &pkt, i++);
1582  }
1583  if (do_read_frames) {
1584  pkt1 = pkt;
1585  while (pkt1.size && process_frame(w, fmt_ctx, &frame, &pkt1) > 0);
1586  }
1587  }
1588  av_free_packet(&pkt);
1589  }
1590  av_init_packet(&pkt);
1591  pkt.data = NULL;
1592  pkt.size = 0;
1593  //Flush remaining frames that are cached in the decoder
1594  for (i = 0; i < fmt_ctx->nb_streams; i++) {
1595  pkt.stream_index = i;
1596  if (do_read_frames)
1597  while (process_frame(w, fmt_ctx, &frame, &pkt) > 0);
1598  }
1599 }
1600 
1601 static void show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_idx)
1602 {
1603  AVStream *stream = fmt_ctx->streams[stream_idx];
1605  const AVCodec *dec;
1606  char val_str[128];
1607  const char *s;
1608  AVRational sar, dar;
1609  AVBPrint pbuf;
1610 
1612 
1614 
1615  print_int("index", stream->index);
1616 
1617  if ((dec_ctx = stream->codec)) {
1618  const char *profile = NULL;
1619  dec = dec_ctx->codec;
1620  if (dec) {
1621  print_str("codec_name", dec->name);
1622  if (!do_bitexact) {
1623  if (dec->long_name) print_str ("codec_long_name", dec->long_name);
1624  else print_str_opt("codec_long_name", "unknown");
1625  }
1626  } else {
1627  print_str_opt("codec_name", "unknown");
1628  if (!do_bitexact) {
1629  print_str_opt("codec_long_name", "unknown");
1630  }
1631  }
1632 
1633  if (dec && (profile = av_get_profile_name(dec, dec_ctx->profile)))
1634  print_str("profile", profile);
1635  else
1636  print_str_opt("profile", "unknown");
1637 
1638  s = av_get_media_type_string(dec_ctx->codec_type);
1639  if (s) print_str ("codec_type", s);
1640  else print_str_opt("codec_type", "unknown");
1641  print_q("codec_time_base", dec_ctx->time_base, '/');
1642 
1643  /* print AVI/FourCC tag */
1644  av_get_codec_tag_string(val_str, sizeof(val_str), dec_ctx->codec_tag);
1645  print_str("codec_tag_string", val_str);
1646  print_fmt("codec_tag", "0x%04x", dec_ctx->codec_tag);
1647 
1648  switch (dec_ctx->codec_type) {
1649  case AVMEDIA_TYPE_VIDEO:
1650  print_int("width", dec_ctx->width);
1651  print_int("height", dec_ctx->height);
1652  print_int("has_b_frames", dec_ctx->has_b_frames);
1653  sar = av_guess_sample_aspect_ratio(fmt_ctx, stream, NULL);
1654  if (sar.den) {
1655  print_q("sample_aspect_ratio", sar, ':');
1656  av_reduce(&dar.num, &dar.den,
1657  dec_ctx->width * sar.num,
1658  dec_ctx->height * sar.den,
1659  1024*1024);
1660  print_q("display_aspect_ratio", dar, ':');
1661  } else {
1662  print_str_opt("sample_aspect_ratio", "N/A");
1663  print_str_opt("display_aspect_ratio", "N/A");
1664  }
1665  s = av_get_pix_fmt_name(dec_ctx->pix_fmt);
1666  if (s) print_str ("pix_fmt", s);
1667  else print_str_opt("pix_fmt", "unknown");
1668  print_int("level", dec_ctx->level);
1669  if (dec_ctx->timecode_frame_start >= 0) {
1670  char tcbuf[AV_TIMECODE_STR_SIZE];
1672  print_str("timecode", tcbuf);
1673  } else {
1674  print_str_opt("timecode", "N/A");
1675  }
1676  break;
1677 
1678  case AVMEDIA_TYPE_AUDIO:
1679  s = av_get_sample_fmt_name(dec_ctx->sample_fmt);
1680  if (s) print_str ("sample_fmt", s);
1681  else print_str_opt("sample_fmt", "unknown");
1682  print_val("sample_rate", dec_ctx->sample_rate, unit_hertz_str);
1683  print_int("channels", dec_ctx->channels);
1684  print_int("bits_per_sample", av_get_bits_per_sample(dec_ctx->codec_id));
1685  break;
1686  }
1687  } else {
1688  print_str_opt("codec_type", "unknown");
1689  }
1690  if (dec_ctx->codec && dec_ctx->codec->priv_class && show_private_data) {
1691  const AVOption *opt = NULL;
1692  while (opt = av_opt_next(dec_ctx->priv_data,opt)) {
1693  uint8_t *str;
1694  if (opt->flags) continue;
1695  if (av_opt_get(dec_ctx->priv_data, opt->name, 0, &str) >= 0) {
1696  print_str(opt->name, str);
1697  av_free(str);
1698  }
1699  }
1700  }
1701 
1702  if (fmt_ctx->iformat->flags & AVFMT_SHOW_IDS) print_fmt ("id", "0x%x", stream->id);
1703  else print_str_opt("id", "N/A");
1704  print_q("r_frame_rate", stream->r_frame_rate, '/');
1705  print_q("avg_frame_rate", stream->avg_frame_rate, '/');
1706  print_q("time_base", stream->time_base, '/');
1707  print_ts ("start_pts", stream->start_time);
1708  print_time("start_time", stream->start_time, &stream->time_base);
1709  print_ts ("duration_ts", stream->duration);
1710  print_time("duration", stream->duration, &stream->time_base);
1711  if (dec_ctx->bit_rate > 0) print_val ("bit_rate", dec_ctx->bit_rate, unit_bit_per_second_str);
1712  else print_str_opt("bit_rate", "N/A");
1713  if (stream->nb_frames) print_fmt ("nb_frames", "%"PRId64, stream->nb_frames);
1714  else print_str_opt("nb_frames", "N/A");
1715  if (nb_streams_frames[stream_idx]) print_fmt ("nb_read_frames", "%"PRIu64, nb_streams_frames[stream_idx]);
1716  else print_str_opt("nb_read_frames", "N/A");
1717  if (nb_streams_packets[stream_idx]) print_fmt ("nb_read_packets", "%"PRIu64, nb_streams_packets[stream_idx]);
1718  else print_str_opt("nb_read_packets", "N/A");
1719  if (do_show_data)
1720  writer_print_data(w, "extradata", dec_ctx->extradata,
1721  dec_ctx->extradata_size);
1722 
1723  /* Print disposition information */
1724 #define PRINT_DISPOSITION(flagname, name) do { \
1725  print_int(name, !!(stream->disposition & AV_DISPOSITION_##flagname)); \
1726  } while (0)
1727 
1730  PRINT_DISPOSITION(DEFAULT, "default");
1731  PRINT_DISPOSITION(DUB, "dub");
1732  PRINT_DISPOSITION(ORIGINAL, "original");
1733  PRINT_DISPOSITION(COMMENT, "comment");
1734  PRINT_DISPOSITION(LYRICS, "lyrics");
1735  PRINT_DISPOSITION(KARAOKE, "karaoke");
1736  PRINT_DISPOSITION(FORCED, "forced");
1737  PRINT_DISPOSITION(HEARING_IMPAIRED, "hearing_impaired");
1738  PRINT_DISPOSITION(VISUAL_IMPAIRED, "visual_impaired");
1739  PRINT_DISPOSITION(CLEAN_EFFECTS, "clean_effects");
1740  PRINT_DISPOSITION(ATTACHED_PIC, "attached_pic");
1742  }
1743 
1745 
1747  av_bprint_finalize(&pbuf, NULL);
1748  fflush(stdout);
1749 }
1750 
1752 {
1753  int i;
1755  for (i = 0; i < fmt_ctx->nb_streams; i++)
1756  if (selected_streams[i])
1757  show_stream(w, fmt_ctx, i);
1759 }
1760 
1762 {
1763  int i;
1764 
1766  for (i = 0; i < fmt_ctx->nb_chapters; i++) {
1767  AVChapter *chapter = fmt_ctx->chapters[i];
1768 
1770  print_int("id", chapter->id);
1771  print_q ("time_base", chapter->time_base, '/');
1772  print_int("start", chapter->start);
1773  print_time("start_time", chapter->start, &chapter->time_base);
1774  print_int("end", chapter->end);
1775  print_time("end_time", chapter->end, &chapter->time_base);
1778  }
1780 }
1781 
1783 {
1784  char val_str[128];
1785  int64_t size = fmt_ctx->pb ? avio_size(fmt_ctx->pb) : -1;
1786 
1788  print_str("filename", fmt_ctx->filename);
1789  print_int("nb_streams", fmt_ctx->nb_streams);
1790  print_str("format_name", fmt_ctx->iformat->name);
1791  if (!do_bitexact) {
1792  if (fmt_ctx->iformat->long_name) print_str ("format_long_name", fmt_ctx->iformat->long_name);
1793  else print_str_opt("format_long_name", "unknown");
1794  }
1795  print_time("start_time", fmt_ctx->start_time, &AV_TIME_BASE_Q);
1796  print_time("duration", fmt_ctx->duration, &AV_TIME_BASE_Q);
1797  if (size >= 0) print_val ("size", size, unit_byte_str);
1798  else print_str_opt("size", "N/A");
1799  if (fmt_ctx->bit_rate > 0) print_val ("bit_rate", fmt_ctx->bit_rate, unit_bit_per_second_str);
1800  else print_str_opt("bit_rate", "N/A");
1802 
1804  fflush(stdout);
1805 }
1806 
1807 static void show_error(WriterContext *w, int err)
1808 {
1809  char errbuf[128];
1810  const char *errbuf_ptr = errbuf;
1811 
1812  if (av_strerror(err, errbuf, sizeof(errbuf)) < 0)
1813  errbuf_ptr = strerror(AVUNERROR(err));
1814 
1816  print_int("code", err);
1817  print_str("string", errbuf_ptr);
1819 }
1820 
1821 static int open_input_file(AVFormatContext **fmt_ctx_ptr, const char *filename)
1822 {
1823  int err, i, orig_nb_streams;
1824  AVFormatContext *fmt_ctx = NULL;
1826  AVDictionary **opts;
1827 
1828  if ((err = avformat_open_input(&fmt_ctx, filename,
1829  iformat, &format_opts)) < 0) {
1830  print_error(filename, err);
1831  return err;
1832  }
1833  if ((t = av_dict_get(format_opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
1834  av_log(NULL, AV_LOG_ERROR, "Option %s not found.\n", t->key);
1835  return AVERROR_OPTION_NOT_FOUND;
1836  }
1837 
1838  /* fill the streams in the format context */
1839  opts = setup_find_stream_info_opts(fmt_ctx, codec_opts);
1840  orig_nb_streams = fmt_ctx->nb_streams;
1841 
1842  if ((err = avformat_find_stream_info(fmt_ctx, opts)) < 0) {
1843  print_error(filename, err);
1844  return err;
1845  }
1846  for (i = 0; i < orig_nb_streams; i++)
1847  av_dict_free(&opts[i]);
1848  av_freep(&opts);
1849 
1850  av_dump_format(fmt_ctx, 0, filename, 0);
1851 
1852  /* bind a decoder to each input stream */
1853  for (i = 0; i < fmt_ctx->nb_streams; i++) {
1854  AVStream *stream = fmt_ctx->streams[i];
1855  AVCodec *codec;
1856 
1857  if (stream->codec->codec_id == AV_CODEC_ID_PROBE) {
1858  av_log(NULL, AV_LOG_ERROR,
1859  "Failed to probe codec for input stream %d\n",
1860  stream->index);
1861  } else if (!(codec = avcodec_find_decoder(stream->codec->codec_id))) {
1862  av_log(NULL, AV_LOG_ERROR,
1863  "Unsupported codec with id %d for input stream %d\n",
1864  stream->codec->codec_id, stream->index);
1865  } else {
1867  fmt_ctx, stream, codec);
1868  if (avcodec_open2(stream->codec, codec, &opts) < 0) {
1869  av_log(NULL, AV_LOG_ERROR, "Error while opening codec for input stream %d\n",
1870  stream->index);
1871  }
1872  if ((t = av_dict_get(opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
1873  av_log(NULL, AV_LOG_ERROR, "Option %s for input stream %d not found\n",
1874  t->key, stream->index);
1875  return AVERROR_OPTION_NOT_FOUND;
1876  }
1877  }
1878  }
1879 
1880  *fmt_ctx_ptr = fmt_ctx;
1881  return 0;
1882 }
1883 
1884 static void close_input_file(AVFormatContext **ctx_ptr)
1885 {
1886  int i;
1887  AVFormatContext *fmt_ctx = *ctx_ptr;
1888 
1889  /* close decoder for each stream */
1890  for (i = 0; i < fmt_ctx->nb_streams; i++)
1891  if (fmt_ctx->streams[i]->codec->codec_id != AV_CODEC_ID_NONE)
1892  avcodec_close(fmt_ctx->streams[i]->codec);
1893 
1894  avformat_close_input(ctx_ptr);
1895 }
1896 
1897 static int probe_file(WriterContext *wctx, const char *filename)
1898 {
1900  int ret, i;
1901  int section_id;
1902 
1905 
1906  ret = open_input_file(&fmt_ctx, filename);
1907  if (ret < 0)
1908  return ret;
1909 
1912  selected_streams = av_calloc(fmt_ctx->nb_streams, sizeof(*selected_streams));
1913 
1914  for (i = 0; i < fmt_ctx->nb_streams; i++) {
1915  if (stream_specifier) {
1916  ret = avformat_match_stream_specifier(fmt_ctx,
1917  fmt_ctx->streams[i],
1919  if (ret < 0)
1920  goto end;
1921  else
1922  selected_streams[i] = ret;
1923  ret = 0;
1924  } else {
1925  selected_streams[i] = 1;
1926  }
1927  }
1928 
1932  section_id = SECTION_ID_PACKETS_AND_FRAMES;
1933  else if (do_show_packets && !do_show_frames)
1934  section_id = SECTION_ID_PACKETS;
1935  else // (!do_show_packets && do_show_frames)
1936  section_id = SECTION_ID_FRAMES;
1938  writer_print_section_header(wctx, section_id);
1939  read_packets(wctx, fmt_ctx);
1942  }
1943  if (do_show_streams)
1944  show_streams(wctx, fmt_ctx);
1945  if (do_show_chapters)
1946  show_chapters(wctx, fmt_ctx);
1947  if (do_show_format)
1948  show_format(wctx, fmt_ctx);
1949 
1950 end:
1951  close_input_file(&fmt_ctx);
1955 
1956  return ret;
1957 }
1958 
1959 static void show_usage(void)
1960 {
1961  av_log(NULL, AV_LOG_INFO, "Simple multimedia streams analyzer\n");
1962  av_log(NULL, AV_LOG_INFO, "usage: %s [OPTIONS] [INPUT_FILE]\n", program_name);
1963  av_log(NULL, AV_LOG_INFO, "\n");
1964 }
1965 
1967 {
1968  AVBPrint pbuf;
1970 
1972  print_str("version", FFMPEG_VERSION);
1973  print_fmt("copyright", "Copyright (c) %d-%d the FFmpeg developers",
1975  print_str("build_date", __DATE__);
1976  print_str("build_time", __TIME__);
1977  print_str("compiler_ident", CC_IDENT);
1978  print_str("configuration", FFMPEG_CONFIGURATION);
1980 
1981  av_bprint_finalize(&pbuf, NULL);
1982 }
1983 
1984 #define SHOW_LIB_VERSION(libname, LIBNAME) \
1985  do { \
1986  if (CONFIG_##LIBNAME) { \
1987  unsigned int version = libname##_version(); \
1988  writer_print_section_header(w, SECTION_ID_LIBRARY_VERSION); \
1989  print_str("name", "lib" #libname); \
1990  print_int("major", LIB##LIBNAME##_VERSION_MAJOR); \
1991  print_int("minor", LIB##LIBNAME##_VERSION_MINOR); \
1992  print_int("micro", LIB##LIBNAME##_VERSION_MICRO); \
1993  print_int("version", version); \
1994  print_str("ident", LIB##LIBNAME##_IDENT); \
1995  writer_print_section_footer(w); \
1996  } \
1997  } while (0)
1998 
2000 {
2002  SHOW_LIB_VERSION(avutil, AVUTIL);
2003  SHOW_LIB_VERSION(avcodec, AVCODEC);
2004  SHOW_LIB_VERSION(avformat, AVFORMAT);
2005  SHOW_LIB_VERSION(avdevice, AVDEVICE);
2006  SHOW_LIB_VERSION(avfilter, AVFILTER);
2007  SHOW_LIB_VERSION(swscale, SWSCALE);
2008  SHOW_LIB_VERSION(swresample, SWRESAMPLE);
2009  SHOW_LIB_VERSION(postproc, POSTPROC);
2011 }
2012 
2013 static int opt_format(void *optctx, const char *opt, const char *arg)
2014 {
2015  iformat = av_find_input_format(arg);
2016  if (!iformat) {
2017  av_log(NULL, AV_LOG_ERROR, "Unknown input format: %s\n", arg);
2018  return AVERROR(EINVAL);
2019  }
2020  return 0;
2021 }
2022 
2023 static inline void mark_section_show_entries(SectionID section_id,
2024  int show_all_entries, AVDictionary *entries)
2025 {
2026  struct section *section = &sections[section_id];
2027 
2029  if (show_all_entries) {
2030  SectionID *id;
2031  for (id = section->children_ids; *id != -1; id++)
2032  mark_section_show_entries(*id, show_all_entries, entries);
2033  } else {
2034  av_dict_copy(&section->entries_to_show, entries, 0);
2035  }
2036 }
2037 
2038 static int match_section(const char *section_name,
2039  int show_all_entries, AVDictionary *entries)
2040 {
2041  int i, ret = 0;
2042 
2043  for (i = 0; i < FF_ARRAY_ELEMS(sections); i++) {
2044  const struct section *section = &sections[i];
2045  if (!strcmp(section_name, section->name) ||
2046  (section->unique_name && !strcmp(section_name, section->unique_name))) {
2047  av_log(NULL, AV_LOG_DEBUG,
2048  "'%s' matches section with unique name '%s'\n", section_name,
2049  (char *)av_x_if_null(section->unique_name, section->name));
2050  ret++;
2051  mark_section_show_entries(section->id, show_all_entries, entries);
2052  }
2053  }
2054  return ret;
2055 }
2056 
2057 static int opt_show_entries(void *optctx, const char *opt, const char *arg)
2058 {
2059  const char *p = arg;
2060  int ret = 0;
2061 
2062  while (*p) {
2063  AVDictionary *entries = NULL;
2064  char *section_name = av_get_token(&p, "=:");
2065  int show_all_entries = 0;
2066 
2067  if (!section_name) {
2068  av_log(NULL, AV_LOG_ERROR,
2069  "Missing section name for option '%s'\n", opt);
2070  return AVERROR(EINVAL);
2071  }
2072 
2073  if (*p == '=') {
2074  p++;
2075  while (*p && *p != ':') {
2076  char *entry = av_get_token(&p, ",:");
2077  if (!entry)
2078  break;
2079  av_log(NULL, AV_LOG_VERBOSE,
2080  "Adding '%s' to the entries to show in section '%s'\n",
2081  entry, section_name);
2082  av_dict_set(&entries, entry, "", AV_DICT_DONT_STRDUP_KEY);
2083  if (*p == ',')
2084  p++;
2085  }
2086  } else {
2087  show_all_entries = 1;
2088  }
2089 
2090  ret = match_section(section_name, show_all_entries, entries);
2091  if (ret == 0) {
2092  av_log(NULL, AV_LOG_ERROR, "No match for section '%s'\n", section_name);
2093  ret = AVERROR(EINVAL);
2094  }
2095  av_dict_free(&entries);
2096  av_free(section_name);
2097 
2098  if (ret <= 0)
2099  break;
2100  if (*p)
2101  p++;
2102  }
2103 
2104  return ret;
2105 }
2106 
2107 static int opt_show_format_entry(void *optctx, const char *opt, const char *arg)
2108 {
2109  char *buf = av_asprintf("format=%s", arg);
2110  int ret;
2111 
2112  av_log(NULL, AV_LOG_WARNING,
2113  "Option '%s' is deprecated, use '-show_entries format=%s' instead\n",
2114  opt, arg);
2115  ret = opt_show_entries(optctx, opt, buf);
2116  av_free(buf);
2117  return ret;
2118 }
2119 
2120 static void opt_input_file(void *optctx, const char *arg)
2121 {
2122  if (input_filename) {
2123  av_log(NULL, AV_LOG_ERROR,
2124  "Argument '%s' provided as input filename, but '%s' was already specified.\n",
2125  arg, input_filename);
2126  exit_program(1);
2127  }
2128  if (!strcmp(arg, "-"))
2129  arg = "pipe:";
2130  input_filename = arg;
2131 }
2132 
2133 static int opt_input_file_i(void *optctx, const char *opt, const char *arg)
2134 {
2135  opt_input_file(optctx, arg);
2136  return 0;
2137 }
2138 
2139 void show_help_default(const char *opt, const char *arg)
2140 {
2142  show_usage();
2143  show_help_options(options, "Main options:", 0, 0, 0);
2144  printf("\n");
2145 
2147 }
2148 
2149 static int opt_pretty(void *optctx, const char *opt, const char *arg)
2150 {
2151  show_value_unit = 1;
2152  use_value_prefix = 1;
2155  return 0;
2156 }
2157 
2158 static void print_section(SectionID id, int level)
2159 {
2160  const SectionID *pid;
2161  const struct section *section = &sections[id];
2162  printf("%c%c%c",
2163  section->flags & SECTION_FLAG_IS_WRAPPER ? 'W' : '.',
2164  section->flags & SECTION_FLAG_IS_ARRAY ? 'A' : '.',
2165  section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS ? 'V' : '.');
2166  printf("%*c %s", level * 4, ' ', section->name);
2167  if (section->unique_name)
2168  printf("/%s", section->unique_name);
2169  printf("\n");
2170 
2171  for (pid = section->children_ids; *pid != -1; pid++)
2172  print_section(*pid, level+1);
2173 }
2174 
2175 static int opt_sections(void *optctx, const char *opt, const char *arg)
2176 {
2177  printf("Sections:\n"
2178  "W.. = Section is a wrapper (contains other sections, no local entries)\n"
2179  ".A. = Section contains an array of elements of the same type\n"
2180  "..V = Section may contain a variable number of fields with variable keys\n"
2181  "FLAGS NAME/UNIQUE_NAME\n"
2182  "---\n");
2184  return 0;
2185 }
2186 
2187 static int opt_show_versions(const char *opt, const char *arg)
2188 {
2191  return 0;
2192 }
2193 
2194 #define DEFINE_OPT_SHOW_SECTION(section, target_section_id) \
2195  static int opt_show_##section(const char *opt, const char *arg) \
2196  { \
2197  mark_section_show_entries(SECTION_ID_##target_section_id, 1, NULL); \
2198  return 0; \
2199  }
2200 
2201 DEFINE_OPT_SHOW_SECTION(chapters, CHAPTERS);
2202 DEFINE_OPT_SHOW_SECTION(error, ERROR);
2203 DEFINE_OPT_SHOW_SECTION(format, FORMAT);
2204 DEFINE_OPT_SHOW_SECTION(frames, FRAMES);
2205 DEFINE_OPT_SHOW_SECTION(library_versions, LIBRARY_VERSIONS);
2206 DEFINE_OPT_SHOW_SECTION(packets, PACKETS);
2207 DEFINE_OPT_SHOW_SECTION(program_version, PROGRAM_VERSION);
2208 DEFINE_OPT_SHOW_SECTION(streams, STREAMS);
2209 
2210 static const OptionDef real_options[] = {
2211 #include "cmdutils_common_opts.h"
2212  { "f", HAS_ARG, {.func_arg = opt_format}, "force format", "format" },
2213  { "unit", OPT_BOOL, {&show_value_unit}, "show unit of the displayed values" },
2214  { "prefix", OPT_BOOL, {&use_value_prefix}, "use SI prefixes for the displayed values" },
2215  { "byte_binary_prefix", OPT_BOOL, {&use_byte_value_binary_prefix},
2216  "use binary prefixes for byte units" },
2217  { "sexagesimal", OPT_BOOL, {&use_value_sexagesimal_format},
2218  "use sexagesimal format HOURS:MM:SS.MICROSECONDS for time units" },
2219  { "pretty", 0, {.func_arg = opt_pretty},
2220  "prettify the format of displayed values, make it more human readable" },
2221  { "print_format", OPT_STRING | HAS_ARG, {(void*)&print_format},
2222  "set the output printing format (available formats are: default, compact, csv, flat, ini, json, xml)", "format" },
2223  { "of", OPT_STRING | HAS_ARG, {(void*)&print_format}, "alias for -print_format", "format" },
2224  { "select_streams", OPT_STRING | HAS_ARG, {(void*)&stream_specifier}, "select the specified streams", "stream_specifier" },
2225  { "sections", OPT_EXIT, {.func_arg = opt_sections}, "print sections structure and section information, and exit" },
2226  { "show_data", OPT_BOOL, {(void*)&do_show_data}, "show packets data" },
2227  { "show_error", 0, {(void*)&opt_show_error}, "show probing error" },
2228  { "show_format", 0, {(void*)&opt_show_format}, "show format/container info" },
2229  { "show_frames", 0, {(void*)&opt_show_frames}, "show frames info" },
2230  { "show_format_entry", HAS_ARG, {.func_arg = opt_show_format_entry},
2231  "show a particular entry from the format/container info", "entry" },
2232  { "show_entries", HAS_ARG, {.func_arg = opt_show_entries},
2233  "show a set of specified entries", "entry_list" },
2234  { "show_packets", 0, {(void*)&opt_show_packets}, "show packets info" },
2235  { "show_streams", 0, {(void*)&opt_show_streams}, "show streams info" },
2236  { "show_chapters", 0, {(void*)&opt_show_chapters}, "show chapters info" },
2237  { "count_frames", OPT_BOOL, {(void*)&do_count_frames}, "count the number of frames per stream" },
2238  { "count_packets", OPT_BOOL, {(void*)&do_count_packets}, "count the number of packets per stream" },
2239  { "show_program_version", 0, {(void*)&opt_show_program_version}, "show ffprobe version" },
2240  { "show_library_versions", 0, {(void*)&opt_show_library_versions}, "show library versions" },
2241  { "show_versions", 0, {(void*)&opt_show_versions}, "show program and library versions" },
2242  { "show_private_data", OPT_BOOL, {(void*)&show_private_data}, "show private data" },
2243  { "private", OPT_BOOL, {(void*)&show_private_data}, "same as show_private_data" },
2244  { "bitexact", OPT_BOOL, {&do_bitexact}, "force bitexact output" },
2245  { "default", HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, {.func_arg = opt_default}, "generic catch all option", "" },
2246  { "i", HAS_ARG, {.func_arg = opt_input_file_i}, "read specified file", "input_file"},
2247  { NULL, },
2248 };
2249 
2250 static inline int check_section_show_entries(int section_id)
2251 {
2252  int *id;
2253  struct section *section = &sections[section_id];
2254  if (sections[section_id].show_all_entries || sections[section_id].entries_to_show)
2255  return 1;
2256  for (id = section->children_ids; *id != -1; id++)
2257  if (check_section_show_entries(*id))
2258  return 1;
2259  return 0;
2260 }
2261 
2262 #define SET_DO_SHOW(id, varname) do { \
2263  if (check_section_show_entries(SECTION_ID_##id)) \
2264  do_show_##varname = 1; \
2265  } while (0)
2266 
2267 int main(int argc, char **argv)
2268 {
2269  const Writer *w;
2270  WriterContext *wctx;
2271  char *buf;
2272  char *w_name = NULL, *w_args = NULL;
2273  int ret, i;
2274 
2277 
2278  options = real_options;
2279  parse_loglevel(argc, argv, options);
2280  av_register_all();
2282  init_opts();
2283 #if CONFIG_AVDEVICE
2285 #endif
2286 
2287  show_banner(argc, argv, options);
2288  parse_options(NULL, argc, argv, options, opt_input_file);
2289 
2290  /* mark things to show, based on -show_entries */
2291  SET_DO_SHOW(CHAPTERS, chapters);
2292  SET_DO_SHOW(ERROR, error);
2293  SET_DO_SHOW(FORMAT, format);
2294  SET_DO_SHOW(FRAMES, frames);
2295  SET_DO_SHOW(LIBRARY_VERSIONS, library_versions);
2296  SET_DO_SHOW(PACKETS, packets);
2297  SET_DO_SHOW(PROGRAM_VERSION, program_version);
2298  SET_DO_SHOW(STREAMS, streams);
2299  SET_DO_SHOW(STREAM_DISPOSITION, stream_disposition);
2300 
2302  av_log(NULL, AV_LOG_ERROR,
2303  "-bitexact and -show_program_version or -show_library_versions "
2304  "options are incompatible\n");
2305  ret = AVERROR(EINVAL);
2306  goto end;
2307  }
2308 
2310 
2311  if (!print_format)
2312  print_format = av_strdup("default");
2313  if (!print_format) {
2314  ret = AVERROR(ENOMEM);
2315  goto end;
2316  }
2317  w_name = av_strtok(print_format, "=", &buf);
2318  w_args = buf;
2319 
2320  w = writer_get_by_name(w_name);
2321  if (!w) {
2322  av_log(NULL, AV_LOG_ERROR, "Unknown output format with name '%s'\n", w_name);
2323  ret = AVERROR(EINVAL);
2324  goto end;
2325  }
2326 
2327  if ((ret = writer_open(&wctx, w, w_args,
2328  sections, FF_ARRAY_ELEMS(sections))) >= 0) {
2330 
2335 
2336  if (!input_filename &&
2339  show_usage();
2340  av_log(NULL, AV_LOG_ERROR, "You have to specify one input file.\n");
2341  av_log(NULL, AV_LOG_ERROR, "Use -h to get full help or, even better, run 'man %s'.\n", program_name);
2342  ret = AVERROR(EINVAL);
2343  } else if (input_filename) {
2344  ret = probe_file(wctx, input_filename);
2345  if (ret < 0 && do_show_error)
2346  show_error(wctx, ret);
2347  }
2348 
2350  writer_close(&wctx);
2351  }
2352 
2353 end:
2355 
2356  uninit_opts();
2357  for (i = 0; i < FF_ARRAY_ELEMS(sections); i++)
2358  av_dict_free(&(sections[i].entries_to_show));
2359 
2361 
2362  return ret < 0;
2363 }