ffprobe.c 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270
  1. /*
  2. * ffprobe : Simple Media Prober based on the FFmpeg libraries
  3. * Copyright (c) 2007-2010 Stefano Sabatini
  4. *
  5. * This file is part of FFmpeg.
  6. *
  7. * FFmpeg is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * FFmpeg is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with FFmpeg; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. */
  21. #include "config.h"
  22. #include "libavformat/avformat.h"
  23. #include "libavcodec/avcodec.h"
  24. #include "libavutil/avstring.h"
  25. #include "libavutil/opt.h"
  26. #include "libavutil/pixdesc.h"
  27. #include "libavutil/dict.h"
  28. #include "libavdevice/avdevice.h"
  29. #include "cmdutils.h"
  30. const char program_name[] = "ffprobe";
  31. const int program_birth_year = 2007;
  32. static int do_show_format = 0;
  33. static int do_show_packets = 0;
  34. static int do_show_streams = 0;
  35. static int show_value_unit = 0;
  36. static int use_value_prefix = 0;
  37. static int use_byte_value_binary_prefix = 0;
  38. static int use_value_sexagesimal_format = 0;
  39. static char *print_format;
  40. static const OptionDef options[];
  41. /* FFprobe context */
  42. static const char *input_filename;
  43. static AVInputFormat *iformat = NULL;
  44. static const char *binary_unit_prefixes [] = { "", "Ki", "Mi", "Gi", "Ti", "Pi" };
  45. static const char *decimal_unit_prefixes[] = { "", "K" , "M" , "G" , "T" , "P" };
  46. static const char *unit_second_str = "s" ;
  47. static const char *unit_hertz_str = "Hz" ;
  48. static const char *unit_byte_str = "byte" ;
  49. static const char *unit_bit_per_second_str = "bit/s";
  50. void av_noreturn exit_program(int ret)
  51. {
  52. exit(ret);
  53. }
  54. struct unit_value {
  55. union { double d; int i; } val;
  56. const char *unit;
  57. };
  58. static char *value_string(char *buf, int buf_size, struct unit_value uv)
  59. {
  60. double vald;
  61. int show_float = 0;
  62. if (uv.unit == unit_second_str) {
  63. vald = uv.val.d;
  64. show_float = 1;
  65. } else {
  66. vald = uv.val.i;
  67. }
  68. if (uv.unit == unit_second_str && use_value_sexagesimal_format) {
  69. double secs;
  70. int hours, mins;
  71. secs = vald;
  72. mins = (int)secs / 60;
  73. secs = secs - mins * 60;
  74. hours = mins / 60;
  75. mins %= 60;
  76. snprintf(buf, buf_size, "%d:%02d:%09.6f", hours, mins, secs);
  77. } else if (use_value_prefix) {
  78. const char *prefix_string;
  79. int index, l;
  80. if (uv.unit == unit_byte_str && use_byte_value_binary_prefix) {
  81. index = (int) (log(vald)/log(2)) / 10;
  82. index = av_clip(index, 0, FF_ARRAY_ELEMS(binary_unit_prefixes) -1);
  83. vald /= pow(2, index*10);
  84. prefix_string = binary_unit_prefixes[index];
  85. } else {
  86. index = (int) (log10(vald)) / 3;
  87. index = av_clip(index, 0, FF_ARRAY_ELEMS(decimal_unit_prefixes) -1);
  88. vald /= pow(10, index*3);
  89. prefix_string = decimal_unit_prefixes[index];
  90. }
  91. if (show_float || vald != (int)vald) l = snprintf(buf, buf_size, "%.3f", vald);
  92. else l = snprintf(buf, buf_size, "%d", (int)vald);
  93. snprintf(buf+l, buf_size-l, "%s%s%s", prefix_string || show_value_unit ? " " : "",
  94. prefix_string, show_value_unit ? uv.unit : "");
  95. } else {
  96. int l;
  97. if (show_float) l = snprintf(buf, buf_size, "%.3f", vald);
  98. else l = snprintf(buf, buf_size, "%d", (int)vald);
  99. snprintf(buf+l, buf_size-l, "%s%s", show_value_unit ? " " : "",
  100. show_value_unit ? uv.unit : "");
  101. }
  102. return buf;
  103. }
  104. /* WRITERS API */
  105. typedef struct WriterContext WriterContext;
  106. #define WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS 1
  107. typedef struct Writer {
  108. int priv_size; ///< private size for the writer context
  109. const char *name;
  110. int (*init) (WriterContext *wctx, const char *args, void *opaque);
  111. void (*uninit)(WriterContext *wctx);
  112. void (*print_header)(WriterContext *ctx);
  113. void (*print_footer)(WriterContext *ctx);
  114. void (*print_chapter_header)(WriterContext *wctx, const char *);
  115. void (*print_chapter_footer)(WriterContext *wctx, const char *);
  116. void (*print_section_header)(WriterContext *wctx, const char *);
  117. void (*print_section_footer)(WriterContext *wctx, const char *);
  118. void (*print_integer) (WriterContext *wctx, const char *, long long int);
  119. void (*print_string) (WriterContext *wctx, const char *, const char *);
  120. void (*show_tags) (WriterContext *wctx, AVDictionary *dict);
  121. int flags; ///< a combination or WRITER_FLAG_*
  122. } Writer;
  123. struct WriterContext {
  124. const AVClass *class; ///< class of the writer
  125. const Writer *writer; ///< the Writer of which this is an instance
  126. char *name; ///< name of this writer instance
  127. void *priv; ///< private data for use by the filter
  128. unsigned int nb_item; ///< number of the item printed in the given section, starting at 0
  129. unsigned int nb_section; ///< number of the section printed in the given section sequence, starting at 0
  130. unsigned int nb_chapter; ///< number of the chapter, starting at 0
  131. };
  132. static const char *writer_get_name(void *p)
  133. {
  134. WriterContext *wctx = p;
  135. return wctx->writer->name;
  136. }
  137. static const AVClass writer_class = {
  138. "Writer",
  139. writer_get_name,
  140. NULL,
  141. LIBAVUTIL_VERSION_INT,
  142. };
  143. static void writer_close(WriterContext **wctx)
  144. {
  145. if (*wctx && (*wctx)->writer->uninit)
  146. (*wctx)->writer->uninit(*wctx);
  147. av_freep(&((*wctx)->priv));
  148. av_freep(wctx);
  149. }
  150. static int writer_open(WriterContext **wctx, const Writer *writer,
  151. const char *args, void *opaque)
  152. {
  153. int ret = 0;
  154. if (!(*wctx = av_malloc(sizeof(WriterContext)))) {
  155. ret = AVERROR(ENOMEM);
  156. goto fail;
  157. }
  158. if (!((*wctx)->priv = av_mallocz(writer->priv_size))) {
  159. ret = AVERROR(ENOMEM);
  160. goto fail;
  161. }
  162. (*wctx)->class = &writer_class;
  163. (*wctx)->writer = writer;
  164. if ((*wctx)->writer->init)
  165. ret = (*wctx)->writer->init(*wctx, args, opaque);
  166. if (ret < 0)
  167. goto fail;
  168. return 0;
  169. fail:
  170. writer_close(wctx);
  171. return ret;
  172. }
  173. static inline void writer_print_header(WriterContext *wctx)
  174. {
  175. if (wctx->writer->print_header)
  176. wctx->writer->print_header(wctx);
  177. wctx->nb_chapter = 0;
  178. }
  179. static inline void writer_print_footer(WriterContext *wctx)
  180. {
  181. if (wctx->writer->print_footer)
  182. wctx->writer->print_footer(wctx);
  183. }
  184. static inline void writer_print_chapter_header(WriterContext *wctx,
  185. const char *header)
  186. {
  187. if (wctx->writer->print_chapter_header)
  188. wctx->writer->print_chapter_header(wctx, header);
  189. wctx->nb_section = 0;
  190. }
  191. static inline void writer_print_chapter_footer(WriterContext *wctx,
  192. const char *footer)
  193. {
  194. if (wctx->writer->print_chapter_footer)
  195. wctx->writer->print_chapter_footer(wctx, footer);
  196. wctx->nb_chapter++;
  197. }
  198. static inline void writer_print_section_header(WriterContext *wctx,
  199. const char *header)
  200. {
  201. if (wctx->writer->print_section_header)
  202. wctx->writer->print_section_header(wctx, header);
  203. wctx->nb_item = 0;
  204. }
  205. static inline void writer_print_section_footer(WriterContext *wctx,
  206. const char *footer)
  207. {
  208. if (wctx->writer->print_section_footer)
  209. wctx->writer->print_section_footer(wctx, footer);
  210. wctx->nb_section++;
  211. }
  212. static inline void writer_print_integer(WriterContext *wctx,
  213. const char *key, long long int val)
  214. {
  215. wctx->writer->print_integer(wctx, key, val);
  216. wctx->nb_item++;
  217. }
  218. static inline void writer_print_string(WriterContext *wctx,
  219. const char *key, const char *val, int opt)
  220. {
  221. if (opt && !(wctx->writer->flags & WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS))
  222. return;
  223. wctx->writer->print_string(wctx, key, val);
  224. wctx->nb_item++;
  225. }
  226. static void writer_print_time(WriterContext *wctx, const char *key,
  227. int64_t ts, const AVRational *time_base)
  228. {
  229. char buf[128];
  230. if (ts == AV_NOPTS_VALUE) {
  231. writer_print_string(wctx, key, "N/A", 1);
  232. } else {
  233. double d = ts * av_q2d(*time_base);
  234. value_string(buf, sizeof(buf), (struct unit_value){.val.d=d, .unit=unit_second_str});
  235. writer_print_string(wctx, key, buf, 0);
  236. }
  237. }
  238. static void writer_print_ts(WriterContext *wctx, const char *key, int64_t ts)
  239. {
  240. if (ts == AV_NOPTS_VALUE) {
  241. writer_print_string(wctx, key, "N/A", 1);
  242. } else {
  243. writer_print_integer(wctx, key, ts);
  244. }
  245. }
  246. static inline void writer_show_tags(WriterContext *wctx, AVDictionary *dict)
  247. {
  248. wctx->writer->show_tags(wctx, dict);
  249. }
  250. #define MAX_REGISTERED_WRITERS_NB 64
  251. static const Writer *registered_writers[MAX_REGISTERED_WRITERS_NB + 1];
  252. static int writer_register(const Writer *writer)
  253. {
  254. static int next_registered_writer_idx = 0;
  255. if (next_registered_writer_idx == MAX_REGISTERED_WRITERS_NB)
  256. return AVERROR(ENOMEM);
  257. registered_writers[next_registered_writer_idx++] = writer;
  258. return 0;
  259. }
  260. static const Writer *writer_get_by_name(const char *name)
  261. {
  262. int i;
  263. for (i = 0; registered_writers[i]; i++)
  264. if (!strcmp(registered_writers[i]->name, name))
  265. return registered_writers[i];
  266. return NULL;
  267. }
  268. /* Print helpers */
  269. struct print_buf {
  270. char *s;
  271. int len;
  272. };
  273. static char *fast_asprintf(struct print_buf *pbuf, const char *fmt, ...)
  274. {
  275. va_list va;
  276. int len;
  277. va_start(va, fmt);
  278. len = vsnprintf(NULL, 0, fmt, va);
  279. va_end(va);
  280. if (len < 0)
  281. goto fail;
  282. if (pbuf->len < len) {
  283. char *p = av_realloc(pbuf->s, len + 1);
  284. if (!p)
  285. goto fail;
  286. pbuf->s = p;
  287. pbuf->len = len;
  288. }
  289. va_start(va, fmt);
  290. len = vsnprintf(pbuf->s, len + 1, fmt, va);
  291. va_end(va);
  292. if (len < 0)
  293. goto fail;
  294. return pbuf->s;
  295. fail:
  296. av_freep(&pbuf->s);
  297. pbuf->len = 0;
  298. return NULL;
  299. }
  300. #define ESCAPE_INIT_BUF_SIZE 256
  301. #define ESCAPE_CHECK_SIZE(src, size, max_size) \
  302. if (size > max_size) { \
  303. char buf[64]; \
  304. snprintf(buf, sizeof(buf), "%s", src); \
  305. av_log(log_ctx, AV_LOG_WARNING, \
  306. "String '%s...' with is too big\n", buf); \
  307. return "FFPROBE_TOO_BIG_STRING"; \
  308. }
  309. #define ESCAPE_REALLOC_BUF(dst_size_p, dst_p, src, size) \
  310. if (*dst_size_p < size) { \
  311. char *q = av_realloc(*dst_p, size); \
  312. if (!q) { \
  313. char buf[64]; \
  314. snprintf(buf, sizeof(buf), "%s", src); \
  315. av_log(log_ctx, AV_LOG_WARNING, \
  316. "String '%s...' could not be escaped\n", buf); \
  317. return "FFPROBE_THIS_STRING_COULD_NOT_BE_ESCAPED"; \
  318. } \
  319. *dst_size_p = size; \
  320. *dst = q; \
  321. }
  322. /* WRITERS */
  323. /* Default output */
  324. static void default_print_footer(WriterContext *wctx)
  325. {
  326. printf("\n");
  327. }
  328. static void default_print_chapter_header(WriterContext *wctx, const char *chapter)
  329. {
  330. if (wctx->nb_chapter)
  331. printf("\n");
  332. }
  333. /* lame uppercasing routine, assumes the string is lower case ASCII */
  334. static inline char *upcase_string(char *dst, size_t dst_size, const char *src)
  335. {
  336. int i;
  337. for (i = 0; src[i] && i < dst_size-1; i++)
  338. dst[i] = src[i]-32;
  339. dst[i] = 0;
  340. return dst;
  341. }
  342. static void default_print_section_header(WriterContext *wctx, const char *section)
  343. {
  344. char buf[32];
  345. if (wctx->nb_section)
  346. printf("\n");
  347. printf("[%s]\n", upcase_string(buf, sizeof(buf), section));
  348. }
  349. static void default_print_section_footer(WriterContext *wctx, const char *section)
  350. {
  351. char buf[32];
  352. printf("[/%s]", upcase_string(buf, sizeof(buf), section));
  353. }
  354. static void default_print_str(WriterContext *wctx, const char *key, const char *value)
  355. {
  356. printf("%s=%s\n", key, value);
  357. }
  358. static void default_print_int(WriterContext *wctx, const char *key, long long int value)
  359. {
  360. printf("%s=%lld\n", key, value);
  361. }
  362. static void default_show_tags(WriterContext *wctx, AVDictionary *dict)
  363. {
  364. AVDictionaryEntry *tag = NULL;
  365. while ((tag = av_dict_get(dict, "", tag, AV_DICT_IGNORE_SUFFIX))) {
  366. printf("TAG:");
  367. writer_print_string(wctx, tag->key, tag->value, 0);
  368. }
  369. }
  370. static const Writer default_writer = {
  371. .name = "default",
  372. .print_footer = default_print_footer,
  373. .print_chapter_header = default_print_chapter_header,
  374. .print_section_header = default_print_section_header,
  375. .print_section_footer = default_print_section_footer,
  376. .print_integer = default_print_int,
  377. .print_string = default_print_str,
  378. .show_tags = default_show_tags,
  379. .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS,
  380. };
  381. /* Compact output */
  382. /**
  383. * Escape \n, \r, \\ and sep characters contained in s, and print the
  384. * resulting string.
  385. */
  386. static const char *c_escape_str(char **dst, size_t *dst_size,
  387. const char *src, const char sep, void *log_ctx)
  388. {
  389. const char *p;
  390. char *q;
  391. size_t size = 1;
  392. /* precompute size */
  393. for (p = src; *p; p++, size++) {
  394. ESCAPE_CHECK_SIZE(src, size, SIZE_MAX-2);
  395. if (*p == '\n' || *p == '\r' || *p == '\\')
  396. size++;
  397. }
  398. ESCAPE_REALLOC_BUF(dst_size, dst, src, size);
  399. q = *dst;
  400. for (p = src; *p; p++) {
  401. switch (*src) {
  402. case '\n': *q++ = '\\'; *q++ = 'n'; break;
  403. case '\r': *q++ = '\\'; *q++ = 'r'; break;
  404. case '\\': *q++ = '\\'; *q++ = '\\'; break;
  405. default:
  406. if (*p == sep)
  407. *q++ = '\\';
  408. *q++ = *p;
  409. }
  410. }
  411. *q = 0;
  412. return *dst;
  413. }
  414. /**
  415. * Quote fields containing special characters, check RFC4180.
  416. */
  417. static const char *csv_escape_str(char **dst, size_t *dst_size,
  418. const char *src, const char sep, void *log_ctx)
  419. {
  420. const char *p;
  421. char *q;
  422. size_t size = 1;
  423. int quote = 0;
  424. /* precompute size */
  425. for (p = src; *p; p++, size++) {
  426. ESCAPE_CHECK_SIZE(src, size, SIZE_MAX-4);
  427. if (*p == '"' || *p == sep || *p == '\n' || *p == '\r')
  428. if (!quote) {
  429. quote = 1;
  430. size += 2;
  431. }
  432. if (*p == '"')
  433. size++;
  434. }
  435. ESCAPE_REALLOC_BUF(dst_size, dst, src, size);
  436. q = *dst;
  437. p = src;
  438. if (quote)
  439. *q++ = '\"';
  440. while (*p) {
  441. if (*p == '"')
  442. *q++ = '\"';
  443. *q++ = *p++;
  444. }
  445. if (quote)
  446. *q++ = '\"';
  447. *q = 0;
  448. return *dst;
  449. }
  450. static const char *none_escape_str(char **dst, size_t *dst_size,
  451. const char *src, const char sep, void *log_ctx)
  452. {
  453. return src;
  454. }
  455. typedef struct CompactContext {
  456. const AVClass *class;
  457. char *item_sep_str;
  458. char item_sep;
  459. int nokey;
  460. char *buf;
  461. size_t buf_size;
  462. char *escape_mode_str;
  463. const char * (*escape_str)(char **dst, size_t *dst_size,
  464. const char *src, const char sep, void *log_ctx);
  465. } CompactContext;
  466. #define OFFSET(x) offsetof(CompactContext, x)
  467. static const AVOption compact_options[]= {
  468. {"item_sep", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str="|"}, CHAR_MIN, CHAR_MAX },
  469. {"s", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str="|"}, CHAR_MIN, CHAR_MAX },
  470. {"nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_INT, {.dbl=0}, 0, 1 },
  471. {"nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_INT, {.dbl=0}, 0, 1 },
  472. {"escape", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="c"}, CHAR_MIN, CHAR_MAX },
  473. {"e", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="c"}, CHAR_MIN, CHAR_MAX },
  474. {NULL},
  475. };
  476. static const char *compact_get_name(void *ctx)
  477. {
  478. return "compact";
  479. }
  480. static const AVClass compact_class = {
  481. "CompactContext",
  482. compact_get_name,
  483. compact_options
  484. };
  485. static av_cold int compact_init(WriterContext *wctx, const char *args, void *opaque)
  486. {
  487. CompactContext *compact = wctx->priv;
  488. int err;
  489. compact->class = &compact_class;
  490. av_opt_set_defaults(compact);
  491. if (args &&
  492. (err = (av_set_options_string(compact, args, "=", ":"))) < 0) {
  493. av_log(wctx, AV_LOG_ERROR, "Error parsing options string: '%s'\n", args);
  494. return err;
  495. }
  496. if (strlen(compact->item_sep_str) != 1) {
  497. av_log(wctx, AV_LOG_ERROR, "Item separator '%s' specified, but must contain a single character\n",
  498. compact->item_sep_str);
  499. return AVERROR(EINVAL);
  500. }
  501. compact->item_sep = compact->item_sep_str[0];
  502. compact->buf_size = ESCAPE_INIT_BUF_SIZE;
  503. if (!(compact->buf = av_malloc(compact->buf_size)))
  504. return AVERROR(ENOMEM);
  505. if (!strcmp(compact->escape_mode_str, "none")) compact->escape_str = none_escape_str;
  506. else if (!strcmp(compact->escape_mode_str, "c" )) compact->escape_str = c_escape_str;
  507. else if (!strcmp(compact->escape_mode_str, "csv" )) compact->escape_str = csv_escape_str;
  508. else {
  509. av_log(wctx, AV_LOG_ERROR, "Unknown escape mode '%s'\n", compact->escape_mode_str);
  510. return AVERROR(EINVAL);
  511. }
  512. return 0;
  513. }
  514. static av_cold void compact_uninit(WriterContext *wctx)
  515. {
  516. CompactContext *compact = wctx->priv;
  517. av_freep(&compact->item_sep_str);
  518. av_freep(&compact->buf);
  519. av_freep(&compact->escape_mode_str);
  520. }
  521. static void compact_print_section_header(WriterContext *wctx, const char *section)
  522. {
  523. CompactContext *compact = wctx->priv;
  524. printf("%s%c", section, compact->item_sep);
  525. }
  526. static void compact_print_section_footer(WriterContext *wctx, const char *section)
  527. {
  528. printf("\n");
  529. }
  530. static void compact_print_str(WriterContext *wctx, const char *key, const char *value)
  531. {
  532. CompactContext *compact = wctx->priv;
  533. if (wctx->nb_item) printf("%c", compact->item_sep);
  534. if (!compact->nokey)
  535. printf("%s=", key);
  536. printf("%s", compact->escape_str(&compact->buf, &compact->buf_size,
  537. value, compact->item_sep, wctx));
  538. }
  539. static void compact_print_int(WriterContext *wctx, const char *key, long long int value)
  540. {
  541. CompactContext *compact = wctx->priv;
  542. if (wctx->nb_item) printf("%c", compact->item_sep);
  543. if (!compact->nokey)
  544. printf("%s=", key);
  545. printf("%lld", value);
  546. }
  547. static void compact_show_tags(WriterContext *wctx, AVDictionary *dict)
  548. {
  549. CompactContext *compact = wctx->priv;
  550. AVDictionaryEntry *tag = NULL;
  551. while ((tag = av_dict_get(dict, "", tag, AV_DICT_IGNORE_SUFFIX))) {
  552. if (wctx->nb_item) printf("%c", compact->item_sep);
  553. if (!compact->nokey)
  554. printf("tag:%s=", compact->escape_str(&compact->buf, &compact->buf_size,
  555. tag->key, compact->item_sep, wctx));
  556. printf("%s", compact->escape_str(&compact->buf, &compact->buf_size,
  557. tag->value, compact->item_sep, wctx));
  558. }
  559. }
  560. static const Writer compact_writer = {
  561. .name = "compact",
  562. .priv_size = sizeof(CompactContext),
  563. .init = compact_init,
  564. .uninit = compact_uninit,
  565. .print_section_header = compact_print_section_header,
  566. .print_section_footer = compact_print_section_footer,
  567. .print_integer = compact_print_int,
  568. .print_string = compact_print_str,
  569. .show_tags = compact_show_tags,
  570. .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS,
  571. };
  572. /* CSV output */
  573. static av_cold int csv_init(WriterContext *wctx, const char *args, void *opaque)
  574. {
  575. return compact_init(wctx, "item_sep=,:nokey=1:escape=csv", opaque);
  576. }
  577. static const Writer csv_writer = {
  578. .name = "csv",
  579. .priv_size = sizeof(CompactContext),
  580. .init = csv_init,
  581. .uninit = compact_uninit,
  582. .print_section_header = compact_print_section_header,
  583. .print_section_footer = compact_print_section_footer,
  584. .print_integer = compact_print_int,
  585. .print_string = compact_print_str,
  586. .show_tags = compact_show_tags,
  587. .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS,
  588. };
  589. /* JSON output */
  590. typedef struct {
  591. int multiple_entries; ///< tells if the given chapter requires multiple entries
  592. char *buf;
  593. size_t buf_size;
  594. } JSONContext;
  595. static av_cold int json_init(WriterContext *wctx, const char *args, void *opaque)
  596. {
  597. JSONContext *json = wctx->priv;
  598. json->buf_size = ESCAPE_INIT_BUF_SIZE;
  599. if (!(json->buf = av_malloc(json->buf_size)))
  600. return AVERROR(ENOMEM);
  601. return 0;
  602. }
  603. static av_cold void json_uninit(WriterContext *wctx)
  604. {
  605. JSONContext *json = wctx->priv;
  606. av_freep(&json->buf);
  607. }
  608. static const char *json_escape_str(char **dst, size_t *dst_size, const char *src,
  609. void *log_ctx)
  610. {
  611. static const char json_escape[] = {'"', '\\', '\b', '\f', '\n', '\r', '\t', 0};
  612. static const char json_subst[] = {'"', '\\', 'b', 'f', 'n', 'r', 't', 0};
  613. const char *p;
  614. char *q;
  615. size_t size = 1;
  616. // compute the length of the escaped string
  617. for (p = src; *p; p++) {
  618. ESCAPE_CHECK_SIZE(src, size, SIZE_MAX-6);
  619. if (strchr(json_escape, *p)) size += 2; // simple escape
  620. else if ((unsigned char)*p < 32) size += 6; // handle non-printable chars
  621. else size += 1; // char copy
  622. }
  623. ESCAPE_REALLOC_BUF(dst_size, dst, src, size);
  624. q = *dst;
  625. for (p = src; *p; p++) {
  626. char *s = strchr(json_escape, *p);
  627. if (s) {
  628. *q++ = '\\';
  629. *q++ = json_subst[s - json_escape];
  630. } else if ((unsigned char)*p < 32) {
  631. snprintf(q, 7, "\\u00%02x", *p & 0xff);
  632. q += 6;
  633. } else {
  634. *q++ = *p;
  635. }
  636. }
  637. *q = 0;
  638. return *dst;
  639. }
  640. static void json_print_header(WriterContext *wctx)
  641. {
  642. printf("{");
  643. }
  644. static void json_print_footer(WriterContext *wctx)
  645. {
  646. printf("\n}\n");
  647. }
  648. static void json_print_chapter_header(WriterContext *wctx, const char *chapter)
  649. {
  650. JSONContext *json = wctx->priv;
  651. if (wctx->nb_chapter)
  652. printf(",");
  653. json->multiple_entries = !strcmp(chapter, "packets") || !strcmp(chapter, "streams");
  654. printf("\n \"%s\":%s", json_escape_str(&json->buf, &json->buf_size, chapter, wctx),
  655. json->multiple_entries ? " [" : " ");
  656. }
  657. static void json_print_chapter_footer(WriterContext *wctx, const char *chapter)
  658. {
  659. JSONContext *json = wctx->priv;
  660. if (json->multiple_entries)
  661. printf("]");
  662. }
  663. static void json_print_section_header(WriterContext *wctx, const char *section)
  664. {
  665. if (wctx->nb_section) printf(",");
  666. printf("{\n");
  667. }
  668. static void json_print_section_footer(WriterContext *wctx, const char *section)
  669. {
  670. printf("\n }");
  671. }
  672. static inline void json_print_item_str(WriterContext *wctx,
  673. const char *key, const char *value,
  674. const char *indent)
  675. {
  676. JSONContext *json = wctx->priv;
  677. printf("%s\"%s\":", indent, json_escape_str(&json->buf, &json->buf_size, key, wctx));
  678. printf(" \"%s\"", json_escape_str(&json->buf, &json->buf_size, value, wctx));
  679. }
  680. #define INDENT " "
  681. static void json_print_str(WriterContext *wctx, const char *key, const char *value)
  682. {
  683. if (wctx->nb_item) printf(",\n");
  684. json_print_item_str(wctx, key, value, INDENT);
  685. }
  686. static void json_print_int(WriterContext *wctx, const char *key, long long int value)
  687. {
  688. JSONContext *json = wctx->priv;
  689. if (wctx->nb_item) printf(",\n");
  690. printf(INDENT "\"%s\": %lld",
  691. json_escape_str(&json->buf, &json->buf_size, key, wctx), value);
  692. }
  693. static void json_show_tags(WriterContext *wctx, AVDictionary *dict)
  694. {
  695. AVDictionaryEntry *tag = NULL;
  696. int is_first = 1;
  697. if (!dict)
  698. return;
  699. printf(",\n" INDENT "\"tags\": {\n");
  700. while ((tag = av_dict_get(dict, "", tag, AV_DICT_IGNORE_SUFFIX))) {
  701. if (is_first) is_first = 0;
  702. else printf(",\n");
  703. json_print_item_str(wctx, tag->key, tag->value, INDENT INDENT);
  704. }
  705. printf("\n }");
  706. }
  707. static const Writer json_writer = {
  708. .name = "json",
  709. .priv_size = sizeof(JSONContext),
  710. .init = json_init,
  711. .uninit = json_uninit,
  712. .print_header = json_print_header,
  713. .print_footer = json_print_footer,
  714. .print_chapter_header = json_print_chapter_header,
  715. .print_chapter_footer = json_print_chapter_footer,
  716. .print_section_header = json_print_section_header,
  717. .print_section_footer = json_print_section_footer,
  718. .print_integer = json_print_int,
  719. .print_string = json_print_str,
  720. .show_tags = json_show_tags,
  721. };
  722. static void writer_register_all(void)
  723. {
  724. static int initialized;
  725. if (initialized)
  726. return;
  727. initialized = 1;
  728. writer_register(&default_writer);
  729. writer_register(&compact_writer);
  730. writer_register(&csv_writer);
  731. writer_register(&json_writer);
  732. }
  733. #define print_fmt(k, f, ...) do { \
  734. if (fast_asprintf(&pbuf, f, __VA_ARGS__)) \
  735. writer_print_string(w, k, pbuf.s, 0); \
  736. } while (0)
  737. #define print_fmt_opt(k, f, ...) do { \
  738. if (fast_asprintf(&pbuf, f, __VA_ARGS__)) \
  739. writer_print_string(w, k, pbuf.s, 1); \
  740. } while (0)
  741. #define print_int(k, v) writer_print_integer(w, k, v)
  742. #define print_str(k, v) writer_print_string(w, k, v, 0)
  743. #define print_str_opt(k, v) writer_print_string(w, k, v, 1)
  744. #define print_time(k, v, tb) writer_print_time(w, k, v, tb)
  745. #define print_ts(k, v) writer_print_ts(w, k, v)
  746. #define print_val(k, v, u) writer_print_string(w, k, \
  747. value_string(val_str, sizeof(val_str), (struct unit_value){.val.i = v, .unit=u}), 0)
  748. #define print_section_header(s) writer_print_section_header(w, s)
  749. #define print_section_footer(s) writer_print_section_footer(w, s)
  750. #define show_tags(metadata) writer_show_tags(w, metadata)
  751. static void show_packet(WriterContext *w, AVFormatContext *fmt_ctx, AVPacket *pkt, int packet_idx)
  752. {
  753. char val_str[128];
  754. AVStream *st = fmt_ctx->streams[pkt->stream_index];
  755. struct print_buf pbuf = {.s = NULL};
  756. const char *s;
  757. print_section_header("packet");
  758. s = av_get_media_type_string(st->codec->codec_type);
  759. if (s) print_str ("codec_type", s);
  760. else print_str_opt("codec_type", "unknown");
  761. print_int("stream_index", pkt->stream_index);
  762. print_ts ("pts", pkt->pts);
  763. print_time("pts_time", pkt->pts, &st->time_base);
  764. print_ts ("dts", pkt->dts);
  765. print_time("dts_time", pkt->dts, &st->time_base);
  766. print_ts ("duration", pkt->duration);
  767. print_time("duration_time", pkt->duration, &st->time_base);
  768. print_val("size", pkt->size, unit_byte_str);
  769. if (pkt->pos != -1) print_fmt ("pos", "%"PRId64, pkt->pos);
  770. else print_str_opt("pos", "N/A");
  771. print_fmt("flags", "%c", pkt->flags & AV_PKT_FLAG_KEY ? 'K' : '_');
  772. print_section_footer("packet");
  773. av_free(pbuf.s);
  774. fflush(stdout);
  775. }
  776. static void show_packets(WriterContext *w, AVFormatContext *fmt_ctx)
  777. {
  778. AVPacket pkt;
  779. int i = 0;
  780. av_init_packet(&pkt);
  781. while (!av_read_frame(fmt_ctx, &pkt))
  782. show_packet(w, fmt_ctx, &pkt, i++);
  783. }
  784. static void show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_idx)
  785. {
  786. AVStream *stream = fmt_ctx->streams[stream_idx];
  787. AVCodecContext *dec_ctx;
  788. AVCodec *dec;
  789. char val_str[128];
  790. const char *s;
  791. AVRational display_aspect_ratio;
  792. struct print_buf pbuf = {.s = NULL};
  793. print_section_header("stream");
  794. print_int("index", stream->index);
  795. if ((dec_ctx = stream->codec)) {
  796. if ((dec = dec_ctx->codec)) {
  797. print_str("codec_name", dec->name);
  798. print_str("codec_long_name", dec->long_name);
  799. } else {
  800. print_str_opt("codec_name", "unknown");
  801. print_str_opt("codec_long_name", "unknown");
  802. }
  803. s = av_get_media_type_string(dec_ctx->codec_type);
  804. if (s) print_str ("codec_type", s);
  805. else print_str_opt("codec_type", "unknown");
  806. print_fmt("codec_time_base", "%d/%d", dec_ctx->time_base.num, dec_ctx->time_base.den);
  807. /* print AVI/FourCC tag */
  808. av_get_codec_tag_string(val_str, sizeof(val_str), dec_ctx->codec_tag);
  809. print_str("codec_tag_string", val_str);
  810. print_fmt("codec_tag", "0x%04x", dec_ctx->codec_tag);
  811. switch (dec_ctx->codec_type) {
  812. case AVMEDIA_TYPE_VIDEO:
  813. print_int("width", dec_ctx->width);
  814. print_int("height", dec_ctx->height);
  815. print_int("has_b_frames", dec_ctx->has_b_frames);
  816. if (dec_ctx->sample_aspect_ratio.num) {
  817. print_fmt("sample_aspect_ratio", "%d:%d",
  818. dec_ctx->sample_aspect_ratio.num,
  819. dec_ctx->sample_aspect_ratio.den);
  820. av_reduce(&display_aspect_ratio.num, &display_aspect_ratio.den,
  821. dec_ctx->width * dec_ctx->sample_aspect_ratio.num,
  822. dec_ctx->height * dec_ctx->sample_aspect_ratio.den,
  823. 1024*1024);
  824. print_fmt("display_aspect_ratio", "%d:%d",
  825. display_aspect_ratio.num,
  826. display_aspect_ratio.den);
  827. } else {
  828. print_str_opt("sample_aspect_ratio", "N/A");
  829. print_str_opt("display_aspect_ratio", "N/A");
  830. }
  831. s = av_get_pix_fmt_name(dec_ctx->pix_fmt);
  832. if (s) print_str ("pix_fmt", s);
  833. else print_str_opt("pix_fmt", "unknown");
  834. print_int("level", dec_ctx->level);
  835. if (dec_ctx->timecode_frame_start >= 0) {
  836. uint32_t tc = dec_ctx->timecode_frame_start;
  837. print_fmt("timecode", "%02d:%02d:%02d%c%02d",
  838. tc>>19 & 0x1f, // hours
  839. tc>>13 & 0x3f, // minutes
  840. tc>>6 & 0x3f, // seconds
  841. tc & 1<<24 ? ';' : ':', // drop
  842. tc & 0x3f); // frames
  843. } else {
  844. print_str_opt("timecode", "N/A");
  845. }
  846. break;
  847. case AVMEDIA_TYPE_AUDIO:
  848. s = av_get_sample_fmt_name(dec_ctx->sample_fmt);
  849. if (s) print_str ("sample_fmt", s);
  850. else print_str_opt("sample_fmt", "unknown");
  851. print_val("sample_rate", dec_ctx->sample_rate, unit_hertz_str);
  852. print_int("channels", dec_ctx->channels);
  853. print_int("bits_per_sample", av_get_bits_per_sample(dec_ctx->codec_id));
  854. break;
  855. }
  856. } else {
  857. print_str_opt("codec_type", "unknown");
  858. }
  859. if (dec_ctx->codec && dec_ctx->codec->priv_class) {
  860. const AVOption *opt = NULL;
  861. while (opt = av_opt_next(dec_ctx->priv_data,opt)) {
  862. uint8_t *str;
  863. if (opt->flags) continue;
  864. if (av_opt_get(dec_ctx->priv_data, opt->name, 0, &str) >= 0) {
  865. print_str(opt->name, str);
  866. av_free(str);
  867. }
  868. }
  869. }
  870. if (fmt_ctx->iformat->flags & AVFMT_SHOW_IDS) print_fmt ("id", "0x%x", stream->id);
  871. else print_str_opt("id", "N/A");
  872. print_fmt("r_frame_rate", "%d/%d", stream->r_frame_rate.num, stream->r_frame_rate.den);
  873. print_fmt("avg_frame_rate", "%d/%d", stream->avg_frame_rate.num, stream->avg_frame_rate.den);
  874. print_fmt("time_base", "%d/%d", stream->time_base.num, stream->time_base.den);
  875. print_time("start_time", stream->start_time, &stream->time_base);
  876. print_time("duration", stream->duration, &stream->time_base);
  877. if (stream->nb_frames) print_fmt ("nb_frames", "%"PRId64, stream->nb_frames);
  878. else print_str_opt("nb_frames", "N/A");
  879. show_tags(stream->metadata);
  880. print_section_footer("stream");
  881. av_free(pbuf.s);
  882. fflush(stdout);
  883. }
  884. static void show_streams(WriterContext *w, AVFormatContext *fmt_ctx)
  885. {
  886. int i;
  887. for (i = 0; i < fmt_ctx->nb_streams; i++)
  888. show_stream(w, fmt_ctx, i);
  889. }
  890. static void show_format(WriterContext *w, AVFormatContext *fmt_ctx)
  891. {
  892. char val_str[128];
  893. int64_t size = avio_size(fmt_ctx->pb);
  894. struct print_buf pbuf = {.s = NULL};
  895. print_section_header("format");
  896. print_str("filename", fmt_ctx->filename);
  897. print_int("nb_streams", fmt_ctx->nb_streams);
  898. print_str("format_name", fmt_ctx->iformat->name);
  899. print_str("format_long_name", fmt_ctx->iformat->long_name);
  900. print_time("start_time", fmt_ctx->start_time, &AV_TIME_BASE_Q);
  901. print_time("duration", fmt_ctx->duration, &AV_TIME_BASE_Q);
  902. if (size >= 0) print_val ("size", size, unit_byte_str);
  903. else print_str_opt("size", "N/A");
  904. if (fmt_ctx->bit_rate > 0) print_val ("bit_rate", fmt_ctx->bit_rate, unit_bit_per_second_str);
  905. else print_str_opt("bit_rate", "N/A");
  906. show_tags(fmt_ctx->metadata);
  907. print_section_footer("format");
  908. av_free(pbuf.s);
  909. fflush(stdout);
  910. }
  911. static int open_input_file(AVFormatContext **fmt_ctx_ptr, const char *filename)
  912. {
  913. int err, i;
  914. AVFormatContext *fmt_ctx = NULL;
  915. AVDictionaryEntry *t;
  916. if ((err = avformat_open_input(&fmt_ctx, filename, iformat, &format_opts)) < 0) {
  917. print_error(filename, err);
  918. return err;
  919. }
  920. if ((t = av_dict_get(format_opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
  921. av_log(NULL, AV_LOG_ERROR, "Option %s not found.\n", t->key);
  922. return AVERROR_OPTION_NOT_FOUND;
  923. }
  924. /* fill the streams in the format context */
  925. if ((err = avformat_find_stream_info(fmt_ctx, NULL)) < 0) {
  926. print_error(filename, err);
  927. return err;
  928. }
  929. av_dump_format(fmt_ctx, 0, filename, 0);
  930. /* bind a decoder to each input stream */
  931. for (i = 0; i < fmt_ctx->nb_streams; i++) {
  932. AVStream *stream = fmt_ctx->streams[i];
  933. AVCodec *codec;
  934. if (!(codec = avcodec_find_decoder(stream->codec->codec_id))) {
  935. fprintf(stderr, "Unsupported codec with id %d for input stream %d\n",
  936. stream->codec->codec_id, stream->index);
  937. } else if (avcodec_open2(stream->codec, codec, NULL) < 0) {
  938. fprintf(stderr, "Error while opening codec for input stream %d\n",
  939. stream->index);
  940. }
  941. }
  942. *fmt_ctx_ptr = fmt_ctx;
  943. return 0;
  944. }
  945. #define PRINT_CHAPTER(name) do { \
  946. if (do_show_ ## name) { \
  947. writer_print_chapter_header(wctx, #name); \
  948. show_ ## name (wctx, fmt_ctx); \
  949. writer_print_chapter_footer(wctx, #name); \
  950. } \
  951. } while (0)
  952. static int probe_file(const char *filename)
  953. {
  954. AVFormatContext *fmt_ctx;
  955. int ret;
  956. const Writer *w;
  957. char *buf;
  958. char *w_name = NULL, *w_args = NULL;
  959. WriterContext *wctx;
  960. writer_register_all();
  961. if (!print_format)
  962. print_format = av_strdup("default");
  963. w_name = av_strtok(print_format, "=", &buf);
  964. w_args = buf;
  965. w = writer_get_by_name(w_name);
  966. if (!w) {
  967. av_log(NULL, AV_LOG_ERROR, "Unknown output format with name '%s'\n", w_name);
  968. ret = AVERROR(EINVAL);
  969. goto end;
  970. }
  971. if ((ret = writer_open(&wctx, w, w_args, NULL)) < 0)
  972. goto end;
  973. if ((ret = open_input_file(&fmt_ctx, filename)))
  974. goto end;
  975. writer_print_header(wctx);
  976. PRINT_CHAPTER(packets);
  977. PRINT_CHAPTER(streams);
  978. PRINT_CHAPTER(format);
  979. writer_print_footer(wctx);
  980. av_close_input_file(fmt_ctx);
  981. writer_close(&wctx);
  982. end:
  983. av_freep(&print_format);
  984. return ret;
  985. }
  986. static void show_usage(void)
  987. {
  988. printf("Simple multimedia streams analyzer\n");
  989. printf("usage: %s [OPTIONS] [INPUT_FILE]\n", program_name);
  990. printf("\n");
  991. }
  992. static int opt_format(const char *opt, const char *arg)
  993. {
  994. iformat = av_find_input_format(arg);
  995. if (!iformat) {
  996. fprintf(stderr, "Unknown input format: %s\n", arg);
  997. return AVERROR(EINVAL);
  998. }
  999. return 0;
  1000. }
  1001. static void opt_input_file(void *optctx, const char *arg)
  1002. {
  1003. if (input_filename) {
  1004. fprintf(stderr, "Argument '%s' provided as input filename, but '%s' was already specified.\n",
  1005. arg, input_filename);
  1006. exit(1);
  1007. }
  1008. if (!strcmp(arg, "-"))
  1009. arg = "pipe:";
  1010. input_filename = arg;
  1011. }
  1012. static int opt_help(const char *opt, const char *arg)
  1013. {
  1014. av_log_set_callback(log_callback_help);
  1015. show_usage();
  1016. show_help_options(options, "Main options:\n", 0, 0);
  1017. printf("\n");
  1018. show_help_children(avformat_get_class(), AV_OPT_FLAG_DECODING_PARAM);
  1019. return 0;
  1020. }
  1021. static int opt_pretty(const char *opt, const char *arg)
  1022. {
  1023. show_value_unit = 1;
  1024. use_value_prefix = 1;
  1025. use_byte_value_binary_prefix = 1;
  1026. use_value_sexagesimal_format = 1;
  1027. return 0;
  1028. }
  1029. static const OptionDef options[] = {
  1030. #include "cmdutils_common_opts.h"
  1031. { "f", HAS_ARG, {(void*)opt_format}, "force format", "format" },
  1032. { "unit", OPT_BOOL, {(void*)&show_value_unit}, "show unit of the displayed values" },
  1033. { "prefix", OPT_BOOL, {(void*)&use_value_prefix}, "use SI prefixes for the displayed values" },
  1034. { "byte_binary_prefix", OPT_BOOL, {(void*)&use_byte_value_binary_prefix},
  1035. "use binary prefixes for byte units" },
  1036. { "sexagesimal", OPT_BOOL, {(void*)&use_value_sexagesimal_format},
  1037. "use sexagesimal format HOURS:MM:SS.MICROSECONDS for time units" },
  1038. { "pretty", 0, {(void*)&opt_pretty},
  1039. "prettify the format of displayed values, make it more human readable" },
  1040. { "print_format", OPT_STRING | HAS_ARG, {(void*)&print_format},
  1041. "set the output printing format (available formats are: default, compact, csv, json)", "format" },
  1042. { "show_format", OPT_BOOL, {(void*)&do_show_format} , "show format/container info" },
  1043. { "show_packets", OPT_BOOL, {(void*)&do_show_packets}, "show packets info" },
  1044. { "show_streams", OPT_BOOL, {(void*)&do_show_streams}, "show streams info" },
  1045. { "default", HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, {(void*)opt_default}, "generic catch all option", "" },
  1046. { "i", HAS_ARG, {(void *)opt_input_file}, "read specified file", "input_file"},
  1047. { NULL, },
  1048. };
  1049. int main(int argc, char **argv)
  1050. {
  1051. int ret;
  1052. parse_loglevel(argc, argv, options);
  1053. av_register_all();
  1054. avformat_network_init();
  1055. init_opts();
  1056. #if CONFIG_AVDEVICE
  1057. avdevice_register_all();
  1058. #endif
  1059. show_banner(argc, argv, options);
  1060. parse_options(NULL, argc, argv, options, opt_input_file);
  1061. if (!input_filename) {
  1062. show_usage();
  1063. fprintf(stderr, "You have to specify one input file.\n");
  1064. fprintf(stderr, "Use -h to get full help or, even better, run 'man %s'.\n", program_name);
  1065. exit(1);
  1066. }
  1067. ret = probe_file(input_filename);
  1068. avformat_network_deinit();
  1069. return ret;
  1070. }