You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

987 lines
31KB

  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 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. static char *time_value_string(char *buf, int buf_size, int64_t val, const AVRational *time_base)
  105. {
  106. if (val == AV_NOPTS_VALUE) {
  107. snprintf(buf, buf_size, "N/A");
  108. } else {
  109. double d = val * av_q2d(*time_base);
  110. value_string(buf, buf_size, (struct unit_value){.val.d=d, .unit=unit_second_str});
  111. }
  112. return buf;
  113. }
  114. static char *ts_value_string (char *buf, int buf_size, int64_t ts)
  115. {
  116. if (ts == AV_NOPTS_VALUE) {
  117. snprintf(buf, buf_size, "N/A");
  118. } else {
  119. snprintf(buf, buf_size, "%"PRId64, ts);
  120. }
  121. return buf;
  122. }
  123. /* WRITERS API */
  124. typedef struct WriterContext WriterContext;
  125. typedef struct Writer {
  126. int priv_size; ///< private size for the writer context
  127. const char *name;
  128. int (*init) (WriterContext *wctx, const char *args, void *opaque);
  129. void (*uninit)(WriterContext *wctx);
  130. void (*print_header)(WriterContext *ctx);
  131. void (*print_footer)(WriterContext *ctx);
  132. void (*print_chapter_header)(WriterContext *wctx, const char *);
  133. void (*print_chapter_footer)(WriterContext *wctx, const char *);
  134. void (*print_section_header)(WriterContext *wctx, const char *);
  135. void (*print_section_footer)(WriterContext *wctx, const char *);
  136. void (*print_integer) (WriterContext *wctx, const char *, int);
  137. void (*print_string) (WriterContext *wctx, const char *, const char *);
  138. void (*show_tags) (WriterContext *wctx, AVDictionary *dict);
  139. } Writer;
  140. struct WriterContext {
  141. const AVClass *class; ///< class of the writer
  142. const Writer *writer; ///< the Writer of which this is an instance
  143. char *name; ///< name of this writer instance
  144. void *priv; ///< private data for use by the filter
  145. unsigned int nb_item; ///< number of the item printed in the given section, starting at 0
  146. unsigned int nb_section; ///< number of the section printed in the given section sequence, starting at 0
  147. unsigned int nb_chapter; ///< number of the chapter, starting at 0
  148. };
  149. static const char *writer_get_name(void *p)
  150. {
  151. WriterContext *wctx = p;
  152. return wctx->writer->name;
  153. }
  154. static const AVClass writer_class = {
  155. "Writer",
  156. writer_get_name,
  157. NULL,
  158. LIBAVUTIL_VERSION_INT,
  159. };
  160. static void writer_close(WriterContext **wctx)
  161. {
  162. if (*wctx && (*wctx)->writer->uninit)
  163. (*wctx)->writer->uninit(*wctx);
  164. av_freep(&((*wctx)->priv));
  165. av_freep(wctx);
  166. }
  167. static int writer_open(WriterContext **wctx, const Writer *writer,
  168. const char *args, void *opaque)
  169. {
  170. int ret = 0;
  171. if (!(*wctx = av_malloc(sizeof(WriterContext)))) {
  172. ret = AVERROR(ENOMEM);
  173. goto fail;
  174. }
  175. if (!((*wctx)->priv = av_mallocz(writer->priv_size))) {
  176. ret = AVERROR(ENOMEM);
  177. goto fail;
  178. }
  179. (*wctx)->class = &writer_class;
  180. (*wctx)->writer = writer;
  181. if ((*wctx)->writer->init)
  182. ret = (*wctx)->writer->init(*wctx, args, opaque);
  183. if (ret < 0)
  184. goto fail;
  185. return 0;
  186. fail:
  187. writer_close(wctx);
  188. return ret;
  189. }
  190. static inline void writer_print_header(WriterContext *wctx)
  191. {
  192. if (wctx->writer->print_header)
  193. wctx->writer->print_header(wctx);
  194. wctx->nb_chapter = 0;
  195. }
  196. static inline void writer_print_footer(WriterContext *wctx)
  197. {
  198. if (wctx->writer->print_footer)
  199. wctx->writer->print_footer(wctx);
  200. }
  201. static inline void writer_print_chapter_header(WriterContext *wctx,
  202. const char *header)
  203. {
  204. if (wctx->writer->print_chapter_header)
  205. wctx->writer->print_chapter_header(wctx, header);
  206. wctx->nb_section = 0;
  207. }
  208. static inline void writer_print_chapter_footer(WriterContext *wctx,
  209. const char *footer)
  210. {
  211. if (wctx->writer->print_chapter_footer)
  212. wctx->writer->print_chapter_footer(wctx, footer);
  213. wctx->nb_chapter++;
  214. }
  215. static inline void writer_print_section_header(WriterContext *wctx,
  216. const char *header)
  217. {
  218. if (wctx->writer->print_section_header)
  219. wctx->writer->print_section_header(wctx, header);
  220. wctx->nb_item = 0;
  221. }
  222. static inline void writer_print_section_footer(WriterContext *wctx,
  223. const char *footer)
  224. {
  225. if (wctx->writer->print_section_footer)
  226. wctx->writer->print_section_footer(wctx, footer);
  227. wctx->nb_section++;
  228. }
  229. static inline void writer_print_integer(WriterContext *wctx,
  230. const char *key, int val)
  231. {
  232. wctx->writer->print_integer(wctx, key, val);
  233. wctx->nb_item++;
  234. }
  235. static inline void writer_print_string(WriterContext *wctx,
  236. const char *key, const char *val)
  237. {
  238. wctx->writer->print_string(wctx, key, val);
  239. wctx->nb_item++;
  240. }
  241. static inline void writer_show_tags(WriterContext *wctx, AVDictionary *dict)
  242. {
  243. wctx->writer->show_tags(wctx, dict);
  244. }
  245. #define MAX_REGISTERED_WRITERS_NB 64
  246. static Writer *registered_writers[MAX_REGISTERED_WRITERS_NB + 1];
  247. static int writer_register(Writer *writer)
  248. {
  249. static int next_registered_writer_idx = 0;
  250. if (next_registered_writer_idx == MAX_REGISTERED_WRITERS_NB)
  251. return AVERROR(ENOMEM);
  252. registered_writers[next_registered_writer_idx++] = writer;
  253. return 0;
  254. }
  255. static Writer *writer_get_by_name(const char *name)
  256. {
  257. int i;
  258. for (i = 0; registered_writers[i]; i++)
  259. if (!strcmp(registered_writers[i]->name, name))
  260. return registered_writers[i];
  261. return NULL;
  262. }
  263. /* Print helpers */
  264. struct print_buf {
  265. char *s;
  266. int len;
  267. };
  268. static char *fast_asprintf(struct print_buf *pbuf, const char *fmt, ...)
  269. {
  270. va_list va;
  271. int len;
  272. va_start(va, fmt);
  273. len = vsnprintf(NULL, 0, fmt, va);
  274. va_end(va);
  275. if (len < 0)
  276. goto fail;
  277. if (pbuf->len < len) {
  278. char *p = av_realloc(pbuf->s, len + 1);
  279. if (!p)
  280. goto fail;
  281. pbuf->s = p;
  282. pbuf->len = len;
  283. }
  284. va_start(va, fmt);
  285. len = vsnprintf(pbuf->s, len + 1, fmt, va);
  286. va_end(va);
  287. if (len < 0)
  288. goto fail;
  289. return pbuf->s;
  290. fail:
  291. av_freep(&pbuf->s);
  292. pbuf->len = 0;
  293. return NULL;
  294. }
  295. #define ESCAPE_INIT_BUF_SIZE 256
  296. #define ESCAPE_CHECK_SIZE(src, size, max_size) \
  297. if (size > max_size) { \
  298. char buf[64]; \
  299. snprintf(buf, sizeof(buf), "%s", src); \
  300. av_log(log_ctx, AV_LOG_WARNING, \
  301. "String '%s...' with is too big\n", buf); \
  302. return "FFPROBE_TOO_BIG_STRING"; \
  303. }
  304. #define ESCAPE_REALLOC_BUF(dst_size_p, dst_p, src, size) \
  305. if (*dst_size_p < size) { \
  306. char *q = av_realloc(*dst_p, size); \
  307. if (!q) { \
  308. char buf[64]; \
  309. snprintf(buf, sizeof(buf), "%s", src); \
  310. av_log(log_ctx, AV_LOG_WARNING, \
  311. "String '%s...' could not be escaped\n", buf); \
  312. return "FFPROBE_THIS_STRING_COULD_NOT_BE_ESCAPED"; \
  313. } \
  314. *dst_size_p = size; \
  315. *dst = q; \
  316. }
  317. /* WRITERS */
  318. /* Default output */
  319. static void default_print_footer(WriterContext *wctx)
  320. {
  321. printf("\n");
  322. }
  323. static void default_print_chapter_header(WriterContext *wctx, const char *chapter)
  324. {
  325. if (wctx->nb_chapter)
  326. printf("\n");
  327. }
  328. /* lame uppercasing routine, assumes the string is lower case ASCII */
  329. static inline char *upcase_string(char *dst, size_t dst_size, const char *src)
  330. {
  331. int i;
  332. for (i = 0; src[i] && i < dst_size-1; i++)
  333. dst[i] = src[i]-32;
  334. dst[i] = 0;
  335. return dst;
  336. }
  337. static void default_print_section_header(WriterContext *wctx, const char *section)
  338. {
  339. char buf[32];
  340. if (wctx->nb_section)
  341. printf("\n");
  342. printf("[%s]\n", upcase_string(buf, sizeof(buf), section));
  343. }
  344. static void default_print_section_footer(WriterContext *wctx, const char *section)
  345. {
  346. char buf[32];
  347. printf("[/%s]", upcase_string(buf, sizeof(buf), section));
  348. }
  349. static void default_print_str(WriterContext *wctx, const char *key, const char *value)
  350. {
  351. printf("%s=%s\n", key, value);
  352. }
  353. static void default_print_int(WriterContext *wctx, const char *key, int value)
  354. {
  355. printf("%s=%d\n", key, value);
  356. }
  357. static void default_show_tags(WriterContext *wctx, AVDictionary *dict)
  358. {
  359. AVDictionaryEntry *tag = NULL;
  360. while ((tag = av_dict_get(dict, "", tag, AV_DICT_IGNORE_SUFFIX))) {
  361. printf("TAG:");
  362. writer_print_string(wctx, tag->key, tag->value);
  363. }
  364. }
  365. static Writer default_writer = {
  366. .name = "default",
  367. .print_footer = default_print_footer,
  368. .print_chapter_header = default_print_chapter_header,
  369. .print_section_header = default_print_section_header,
  370. .print_section_footer = default_print_section_footer,
  371. .print_integer = default_print_int,
  372. .print_string = default_print_str,
  373. .show_tags = default_show_tags
  374. };
  375. /* JSON output */
  376. typedef struct {
  377. int multiple_entries; ///< tells if the given chapter requires multiple entries
  378. char *buf;
  379. size_t buf_size;
  380. } JSONContext;
  381. static av_cold int json_init(WriterContext *wctx, const char *args, void *opaque)
  382. {
  383. JSONContext *json = wctx->priv;
  384. json->buf_size = ESCAPE_INIT_BUF_SIZE;
  385. if (!(json->buf = av_malloc(json->buf_size)))
  386. return AVERROR(ENOMEM);
  387. return 0;
  388. }
  389. static av_cold void json_uninit(WriterContext *wctx)
  390. {
  391. JSONContext *json = wctx->priv;
  392. av_freep(&json->buf);
  393. }
  394. static const char *json_escape_str(char **dst, size_t *dst_size, const char *src,
  395. void *log_ctx)
  396. {
  397. static const char json_escape[] = {'"', '\\', '\b', '\f', '\n', '\r', '\t', 0};
  398. static const char json_subst[] = {'"', '\\', 'b', 'f', 'n', 'r', 't', 0};
  399. const char *p;
  400. char *q;
  401. size_t size = 1;
  402. // compute the length of the escaped string
  403. for (p = src; *p; p++) {
  404. ESCAPE_CHECK_SIZE(src, size, SIZE_MAX-6);
  405. if (strchr(json_escape, *p)) size += 2; // simple escape
  406. else if ((unsigned char)*p < 32) size += 6; // handle non-printable chars
  407. else size += 1; // char copy
  408. }
  409. ESCAPE_REALLOC_BUF(dst_size, dst, src, size);
  410. q = *dst;
  411. for (p = src; *p; p++) {
  412. char *s = strchr(json_escape, *p);
  413. if (s) {
  414. *q++ = '\\';
  415. *q++ = json_subst[s - json_escape];
  416. } else if ((unsigned char)*p < 32) {
  417. snprintf(q, 7, "\\u00%02x", *p & 0xff);
  418. q += 6;
  419. } else {
  420. *q++ = *p;
  421. }
  422. }
  423. *q = 0;
  424. return *dst;
  425. }
  426. static void json_print_header(WriterContext *wctx)
  427. {
  428. printf("{");
  429. }
  430. static void json_print_footer(WriterContext *wctx)
  431. {
  432. printf("\n}\n");
  433. }
  434. static void json_print_chapter_header(WriterContext *wctx, const char *chapter)
  435. {
  436. JSONContext *json = wctx->priv;
  437. if (wctx->nb_chapter)
  438. printf(",");
  439. json->multiple_entries = !strcmp(chapter, "packets") || !strcmp(chapter, "streams");
  440. printf("\n \"%s\":%s", json_escape_str(&json->buf, &json->buf_size, chapter, wctx),
  441. json->multiple_entries ? " [" : " ");
  442. }
  443. static void json_print_chapter_footer(WriterContext *wctx, const char *chapter)
  444. {
  445. JSONContext *json = wctx->priv;
  446. if (json->multiple_entries)
  447. printf("]");
  448. }
  449. static void json_print_section_header(WriterContext *wctx, const char *section)
  450. {
  451. if (wctx->nb_section) printf(",");
  452. printf("{\n");
  453. }
  454. static void json_print_section_footer(WriterContext *wctx, const char *section)
  455. {
  456. printf("\n }");
  457. }
  458. static inline void json_print_item_str(WriterContext *wctx,
  459. const char *key, const char *value,
  460. const char *indent)
  461. {
  462. JSONContext *json = wctx->priv;
  463. printf("%s\"%s\":", indent, json_escape_str(&json->buf, &json->buf_size, key, wctx));
  464. printf(" \"%s\"", json_escape_str(&json->buf, &json->buf_size, value, wctx));
  465. }
  466. #define INDENT " "
  467. static void json_print_str(WriterContext *wctx, const char *key, const char *value)
  468. {
  469. if (wctx->nb_item) printf(",\n");
  470. json_print_item_str(wctx, key, value, INDENT);
  471. }
  472. static void json_print_int(WriterContext *wctx, const char *key, int value)
  473. {
  474. JSONContext *json = wctx->priv;
  475. if (wctx->nb_item) printf(",\n");
  476. printf(INDENT "\"%s\": %d",
  477. json_escape_str(&json->buf, &json->buf_size, key, wctx), value);
  478. }
  479. static void json_show_tags(WriterContext *wctx, AVDictionary *dict)
  480. {
  481. AVDictionaryEntry *tag = NULL;
  482. int is_first = 1;
  483. if (!dict)
  484. return;
  485. printf(",\n" INDENT "\"tags\": {\n");
  486. while ((tag = av_dict_get(dict, "", tag, AV_DICT_IGNORE_SUFFIX))) {
  487. if (is_first) is_first = 0;
  488. else printf(",\n");
  489. json_print_item_str(wctx, tag->key, tag->value, INDENT INDENT);
  490. }
  491. printf("\n }");
  492. }
  493. static Writer json_writer = {
  494. .name = "json",
  495. .priv_size = sizeof(JSONContext),
  496. .init = json_init,
  497. .uninit = json_uninit,
  498. .print_header = json_print_header,
  499. .print_footer = json_print_footer,
  500. .print_chapter_header = json_print_chapter_header,
  501. .print_chapter_footer = json_print_chapter_footer,
  502. .print_section_header = json_print_section_header,
  503. .print_section_footer = json_print_section_footer,
  504. .print_integer = json_print_int,
  505. .print_string = json_print_str,
  506. .show_tags = json_show_tags,
  507. };
  508. static void writer_register_all(void)
  509. {
  510. static int initialized;
  511. if (initialized)
  512. return;
  513. initialized = 1;
  514. writer_register(&default_writer);
  515. writer_register(&json_writer);
  516. }
  517. #define print_fmt(k, f, ...) do { \
  518. if (fast_asprintf(&pbuf, f, __VA_ARGS__)) \
  519. writer_print_string(w, k, pbuf.s); \
  520. } while (0)
  521. #define print_int(k, v) writer_print_integer(w, k, v)
  522. #define print_str(k, v) writer_print_string(w, k, v)
  523. #define print_ts(k, v) writer_print_string(w, k, ts_value_string (val_str, sizeof(val_str), v))
  524. #define print_time(k, v, tb) writer_print_string(w, k, time_value_string(val_str, sizeof(val_str), v, tb))
  525. #define print_val(k, v, u) writer_print_string(w, k, value_string (val_str, sizeof(val_str), \
  526. (struct unit_value){.val.i = v, .unit=u}))
  527. #define print_section_header(s) writer_print_section_header(w, s)
  528. #define print_section_footer(s) writer_print_section_footer(w, s)
  529. #define show_tags(metadata) writer_show_tags(w, metadata)
  530. static void show_packet(WriterContext *w, AVFormatContext *fmt_ctx, AVPacket *pkt, int packet_idx)
  531. {
  532. char val_str[128];
  533. AVStream *st = fmt_ctx->streams[pkt->stream_index];
  534. struct print_buf pbuf = {.s = NULL};
  535. print_section_header("packet");
  536. print_str("codec_type", av_x_if_null(av_get_media_type_string(st->codec->codec_type), "unknown"));
  537. print_int("stream_index", pkt->stream_index);
  538. print_ts ("pts", pkt->pts);
  539. print_time("pts_time", pkt->pts, &st->time_base);
  540. print_ts ("dts", pkt->dts);
  541. print_time("dts_time", pkt->dts, &st->time_base);
  542. print_ts ("duration", pkt->duration);
  543. print_time("duration_time", pkt->duration, &st->time_base);
  544. print_val("size", pkt->size, unit_byte_str);
  545. print_fmt("pos", "%"PRId64, pkt->pos);
  546. print_fmt("flags", "%c", pkt->flags & AV_PKT_FLAG_KEY ? 'K' : '_');
  547. print_section_footer("packet");
  548. av_free(pbuf.s);
  549. fflush(stdout);
  550. }
  551. static void show_packets(WriterContext *w, AVFormatContext *fmt_ctx)
  552. {
  553. AVPacket pkt;
  554. int i = 0;
  555. av_init_packet(&pkt);
  556. while (!av_read_frame(fmt_ctx, &pkt))
  557. show_packet(w, fmt_ctx, &pkt, i++);
  558. }
  559. static void show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_idx)
  560. {
  561. AVStream *stream = fmt_ctx->streams[stream_idx];
  562. AVCodecContext *dec_ctx;
  563. AVCodec *dec;
  564. char val_str[128];
  565. AVRational display_aspect_ratio;
  566. struct print_buf pbuf = {.s = NULL};
  567. print_section_header("stream");
  568. print_int("index", stream->index);
  569. if ((dec_ctx = stream->codec)) {
  570. if ((dec = dec_ctx->codec)) {
  571. print_str("codec_name", dec->name);
  572. print_str("codec_long_name", dec->long_name);
  573. } else {
  574. print_str("codec_name", "unknown");
  575. }
  576. print_str("codec_type", av_x_if_null(av_get_media_type_string(dec_ctx->codec_type), "unknown"));
  577. print_fmt("codec_time_base", "%d/%d", dec_ctx->time_base.num, dec_ctx->time_base.den);
  578. /* print AVI/FourCC tag */
  579. av_get_codec_tag_string(val_str, sizeof(val_str), dec_ctx->codec_tag);
  580. print_str("codec_tag_string", val_str);
  581. print_fmt("codec_tag", "0x%04x", dec_ctx->codec_tag);
  582. switch (dec_ctx->codec_type) {
  583. case AVMEDIA_TYPE_VIDEO:
  584. print_int("width", dec_ctx->width);
  585. print_int("height", dec_ctx->height);
  586. print_int("has_b_frames", dec_ctx->has_b_frames);
  587. if (dec_ctx->sample_aspect_ratio.num) {
  588. print_fmt("sample_aspect_ratio", "%d:%d",
  589. dec_ctx->sample_aspect_ratio.num,
  590. dec_ctx->sample_aspect_ratio.den);
  591. av_reduce(&display_aspect_ratio.num, &display_aspect_ratio.den,
  592. dec_ctx->width * dec_ctx->sample_aspect_ratio.num,
  593. dec_ctx->height * dec_ctx->sample_aspect_ratio.den,
  594. 1024*1024);
  595. print_fmt("display_aspect_ratio", "%d:%d",
  596. display_aspect_ratio.num,
  597. display_aspect_ratio.den);
  598. }
  599. print_str("pix_fmt", av_x_if_null(av_get_pix_fmt_name(dec_ctx->pix_fmt), "unknown"));
  600. print_int("level", dec_ctx->level);
  601. break;
  602. case AVMEDIA_TYPE_AUDIO:
  603. print_str("sample_fmt",
  604. av_x_if_null(av_get_sample_fmt_name(dec_ctx->sample_fmt), "unknown"));
  605. print_val("sample_rate", dec_ctx->sample_rate, unit_hertz_str);
  606. print_int("channels", dec_ctx->channels);
  607. print_int("bits_per_sample", av_get_bits_per_sample(dec_ctx->codec_id));
  608. break;
  609. }
  610. } else {
  611. print_str("codec_type", "unknown");
  612. }
  613. if (dec_ctx->codec && dec_ctx->codec->priv_class) {
  614. const AVOption *opt = NULL;
  615. while (opt = av_opt_next(dec_ctx->priv_data,opt)) {
  616. uint8_t *str;
  617. if (opt->flags) continue;
  618. if (av_opt_get(dec_ctx->priv_data, opt->name, 0, &str) >= 0) {
  619. print_str(opt->name, str);
  620. av_free(str);
  621. }
  622. }
  623. }
  624. if (fmt_ctx->iformat->flags & AVFMT_SHOW_IDS)
  625. print_fmt("id", "0x%x", stream->id);
  626. print_fmt("r_frame_rate", "%d/%d", stream->r_frame_rate.num, stream->r_frame_rate.den);
  627. print_fmt("avg_frame_rate", "%d/%d", stream->avg_frame_rate.num, stream->avg_frame_rate.den);
  628. print_fmt("time_base", "%d/%d", stream->time_base.num, stream->time_base.den);
  629. print_time("start_time", stream->start_time, &stream->time_base);
  630. print_time("duration", stream->duration, &stream->time_base);
  631. if (stream->nb_frames)
  632. print_fmt("nb_frames", "%"PRId64, stream->nb_frames);
  633. show_tags(stream->metadata);
  634. print_section_footer("stream");
  635. av_free(pbuf.s);
  636. fflush(stdout);
  637. }
  638. static void show_streams(WriterContext *w, AVFormatContext *fmt_ctx)
  639. {
  640. int i;
  641. for (i = 0; i < fmt_ctx->nb_streams; i++)
  642. show_stream(w, fmt_ctx, i);
  643. }
  644. static void show_format(WriterContext *w, AVFormatContext *fmt_ctx)
  645. {
  646. char val_str[128];
  647. int64_t size = avio_size(fmt_ctx->pb);
  648. struct print_buf pbuf = {.s = NULL};
  649. print_section_header("format");
  650. print_str("filename", fmt_ctx->filename);
  651. print_int("nb_streams", fmt_ctx->nb_streams);
  652. print_str("format_name", fmt_ctx->iformat->name);
  653. print_str("format_long_name", fmt_ctx->iformat->long_name);
  654. print_time("start_time", fmt_ctx->start_time, &AV_TIME_BASE_Q);
  655. print_time("duration", fmt_ctx->duration, &AV_TIME_BASE_Q);
  656. if (size >= 0)
  657. print_val("size", size, unit_byte_str);
  658. print_val("bit_rate", fmt_ctx->bit_rate, unit_bit_per_second_str);
  659. show_tags(fmt_ctx->metadata);
  660. print_section_footer("format");
  661. av_free(pbuf.s);
  662. fflush(stdout);
  663. }
  664. static int open_input_file(AVFormatContext **fmt_ctx_ptr, const char *filename)
  665. {
  666. int err, i;
  667. AVFormatContext *fmt_ctx = NULL;
  668. AVDictionaryEntry *t;
  669. if ((err = avformat_open_input(&fmt_ctx, filename, iformat, &format_opts)) < 0) {
  670. print_error(filename, err);
  671. return err;
  672. }
  673. if ((t = av_dict_get(format_opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
  674. av_log(NULL, AV_LOG_ERROR, "Option %s not found.\n", t->key);
  675. return AVERROR_OPTION_NOT_FOUND;
  676. }
  677. /* fill the streams in the format context */
  678. if ((err = avformat_find_stream_info(fmt_ctx, NULL)) < 0) {
  679. print_error(filename, err);
  680. return err;
  681. }
  682. av_dump_format(fmt_ctx, 0, filename, 0);
  683. /* bind a decoder to each input stream */
  684. for (i = 0; i < fmt_ctx->nb_streams; i++) {
  685. AVStream *stream = fmt_ctx->streams[i];
  686. AVCodec *codec;
  687. if (!(codec = avcodec_find_decoder(stream->codec->codec_id))) {
  688. fprintf(stderr, "Unsupported codec with id %d for input stream %d\n",
  689. stream->codec->codec_id, stream->index);
  690. } else if (avcodec_open2(stream->codec, codec, NULL) < 0) {
  691. fprintf(stderr, "Error while opening codec for input stream %d\n",
  692. stream->index);
  693. }
  694. }
  695. *fmt_ctx_ptr = fmt_ctx;
  696. return 0;
  697. }
  698. #define PRINT_CHAPTER(name) do { \
  699. if (do_show_ ## name) { \
  700. writer_print_chapter_header(wctx, #name); \
  701. show_ ## name (wctx, fmt_ctx); \
  702. writer_print_chapter_footer(wctx, #name); \
  703. } \
  704. } while (0)
  705. static int probe_file(const char *filename)
  706. {
  707. AVFormatContext *fmt_ctx;
  708. int ret;
  709. Writer *w;
  710. char *buf;
  711. char *w_name = NULL, *w_args = NULL;
  712. WriterContext *wctx;
  713. writer_register_all();
  714. if (!print_format)
  715. print_format = av_strdup("default");
  716. w_name = av_strtok(print_format, "=", &buf);
  717. w_args = buf;
  718. w = writer_get_by_name(w_name);
  719. if (!w) {
  720. av_log(NULL, AV_LOG_ERROR, "Unknown output format with name '%s'\n", w_name);
  721. ret = AVERROR(EINVAL);
  722. goto end;
  723. }
  724. if ((ret = writer_open(&wctx, w, w_args, NULL)) < 0)
  725. goto end;
  726. if ((ret = open_input_file(&fmt_ctx, filename)))
  727. goto end;
  728. writer_print_header(wctx);
  729. PRINT_CHAPTER(packets);
  730. PRINT_CHAPTER(streams);
  731. PRINT_CHAPTER(format);
  732. writer_print_footer(wctx);
  733. av_close_input_file(fmt_ctx);
  734. writer_close(&wctx);
  735. end:
  736. av_freep(&print_format);
  737. return ret;
  738. }
  739. static void show_usage(void)
  740. {
  741. printf("Simple multimedia streams analyzer\n");
  742. printf("usage: %s [OPTIONS] [INPUT_FILE]\n", program_name);
  743. printf("\n");
  744. }
  745. static int opt_format(const char *opt, const char *arg)
  746. {
  747. iformat = av_find_input_format(arg);
  748. if (!iformat) {
  749. fprintf(stderr, "Unknown input format: %s\n", arg);
  750. return AVERROR(EINVAL);
  751. }
  752. return 0;
  753. }
  754. static void opt_input_file(void *optctx, const char *arg)
  755. {
  756. if (input_filename) {
  757. fprintf(stderr, "Argument '%s' provided as input filename, but '%s' was already specified.\n",
  758. arg, input_filename);
  759. exit(1);
  760. }
  761. if (!strcmp(arg, "-"))
  762. arg = "pipe:";
  763. input_filename = arg;
  764. }
  765. static int opt_help(const char *opt, const char *arg)
  766. {
  767. av_log_set_callback(log_callback_help);
  768. show_usage();
  769. show_help_options(options, "Main options:\n", 0, 0);
  770. printf("\n");
  771. show_help_children(avformat_get_class(), AV_OPT_FLAG_DECODING_PARAM);
  772. return 0;
  773. }
  774. static int opt_pretty(const char *opt, const char *arg)
  775. {
  776. show_value_unit = 1;
  777. use_value_prefix = 1;
  778. use_byte_value_binary_prefix = 1;
  779. use_value_sexagesimal_format = 1;
  780. return 0;
  781. }
  782. static const OptionDef options[] = {
  783. #include "cmdutils_common_opts.h"
  784. { "f", HAS_ARG, {(void*)opt_format}, "force format", "format" },
  785. { "unit", OPT_BOOL, {(void*)&show_value_unit}, "show unit of the displayed values" },
  786. { "prefix", OPT_BOOL, {(void*)&use_value_prefix}, "use SI prefixes for the displayed values" },
  787. { "byte_binary_prefix", OPT_BOOL, {(void*)&use_byte_value_binary_prefix},
  788. "use binary prefixes for byte units" },
  789. { "sexagesimal", OPT_BOOL, {(void*)&use_value_sexagesimal_format},
  790. "use sexagesimal format HOURS:MM:SS.MICROSECONDS for time units" },
  791. { "pretty", 0, {(void*)&opt_pretty},
  792. "prettify the format of displayed values, make it more human readable" },
  793. { "print_format", OPT_STRING | HAS_ARG, {(void*)&print_format}, "set the output printing format (available formats are: default, json)", "format" },
  794. { "show_format", OPT_BOOL, {(void*)&do_show_format} , "show format/container info" },
  795. { "show_packets", OPT_BOOL, {(void*)&do_show_packets}, "show packets info" },
  796. { "show_streams", OPT_BOOL, {(void*)&do_show_streams}, "show streams info" },
  797. { "default", HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, {(void*)opt_default}, "generic catch all option", "" },
  798. { "i", HAS_ARG, {(void *)opt_input_file}, "read specified file", "input_file"},
  799. { NULL, },
  800. };
  801. int main(int argc, char **argv)
  802. {
  803. int ret;
  804. parse_loglevel(argc, argv, options);
  805. av_register_all();
  806. avformat_network_init();
  807. init_opts();
  808. #if CONFIG_AVDEVICE
  809. avdevice_register_all();
  810. #endif
  811. show_banner();
  812. parse_options(NULL, argc, argv, options, opt_input_file);
  813. if (!input_filename) {
  814. show_usage();
  815. fprintf(stderr, "You have to specify one input file.\n");
  816. fprintf(stderr, "Use -h to get full help or, even better, run 'man %s'.\n", program_name);
  817. exit(1);
  818. }
  819. ret = probe_file(input_filename);
  820. avformat_network_deinit();
  821. return ret;
  822. }