Newer
Older
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
INIContext *ini = wctx->priv;
AVDictionaryEntry *tag = NULL;
int is_first = 1;
while ((tag = av_dict_get(dict, "", tag, AV_DICT_IGNORE_SUFFIX))) {
if (is_first) {
printf("\n[%s.tags]\n", ini->section_name.str);
is_first = 0;
}
writer_print_string(wctx, tag->key, tag->value, 0);
}
}
static const Writer ini_writer = {
.name = "ini",
.priv_size = sizeof(INIContext),
.init = ini_init,
.uninit = ini_uninit,
.print_header = ini_print_header,
.print_chapter_header = ini_print_chapter_header,
.print_section_header = ini_print_section_header,
.print_integer = ini_print_int,
.print_string = ini_print_str,
.show_tags = ini_show_tags,
.flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS|WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER,
Stefano Sabatini
committed
.priv_class = &ini_class,
/* JSON output */
typedef struct {
int indent_level;
int compact;
const char *item_sep, *item_start_end;
} JSONContext;
#undef OFFSET
#define OFFSET(x) offsetof(JSONContext, x)
static const AVOption json_options[]= {
{ "compact", "enable compact output", OFFSET(compact), AV_OPT_TYPE_INT, {.i64=0}, 0, 1 },
{ "c", "enable compact output", OFFSET(compact), AV_OPT_TYPE_INT, {.i64=0}, 0, 1 },
DEFINE_WRITER_CLASS(json);
static av_cold int json_init(WriterContext *wctx, const char *args, void *opaque)
{
JSONContext *json = wctx->priv;
json->item_sep = json->compact ? ", " : ",\n";
json->item_start_end = json->compact ? " " : "\n";
return 0;
}
static const char *json_escape_str(AVBPrint *dst, const char *src, void *log_ctx)
{
static const char json_escape[] = {'"', '\\', '\b', '\f', '\n', '\r', '\t', 0};
static const char json_subst[] = {'"', '\\', 'b', 'f', 'n', 'r', 't', 0};
const char *p;
for (p = src; *p; p++) {
char *s = strchr(json_escape, *p);
if (s) {
av_bprint_chars(dst, '\\', 1);
av_bprint_chars(dst, json_subst[s - json_escape], 1);
} else if ((unsigned char)*p < 32) {
} else {
}
}
}
static void json_print_header(WriterContext *wctx)
{
JSONContext *json = wctx->priv;
printf("{");
json->indent_level++;
}
static void json_print_footer(WriterContext *wctx)
{
JSONContext *json = wctx->priv;
json->indent_level--;
printf("\n}\n");
}
#define JSON_INDENT() printf("%*c", json->indent_level * 4, ' ')
static void json_print_chapter_header(WriterContext *wctx, const char *chapter)
{
JSONContext *json = wctx->priv;
if (wctx->nb_chapter)
printf(",");
if (wctx->multiple_sections) {
av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
printf("\"%s\": [\n", json_escape_str(&buf, chapter, wctx));
av_bprint_finalize(&buf, NULL);
json->indent_level++;
}
static void json_print_chapter_footer(WriterContext *wctx, const char *chapter)
{
JSONContext *json = wctx->priv;
if (wctx->multiple_sections) {
json->indent_level--;
JSON_INDENT();
printf("]");
}
static void json_print_section_header(WriterContext *wctx, const char *section)
{
JSONContext *json = wctx->priv;
if (wctx->nb_section)
printf(",\n");
JSON_INDENT();
if (!wctx->multiple_sections)
printf("\"%s\": ", section);
printf("{%s", json->item_start_end);
json->indent_level++;
/* this is required so the parser can distinguish between packets and frames */
if (wctx->is_packets_and_frames) {
if (!json->compact)
JSON_INDENT();
printf("\"type\": \"%s\"%s", section, json->item_sep);
}
static void json_print_section_footer(WriterContext *wctx, const char *section)
{
JSONContext *json = wctx->priv;
printf("%s", json->item_start_end);
json->indent_level--;
if (!json->compact)
JSON_INDENT();
printf("}");
}
static inline void json_print_item_str(WriterContext *wctx,
const char *key, const char *value)
av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
printf("\"%s\":", json_escape_str(&buf, key, wctx));
printf(" \"%s\"", json_escape_str(&buf, value, wctx));
av_bprint_finalize(&buf, NULL);
}
static void json_print_str(WriterContext *wctx, const char *key, const char *value)
{
JSONContext *json = wctx->priv;
if (wctx->nb_item) printf("%s", json->item_sep);
if (!json->compact)
JSON_INDENT();
json_print_item_str(wctx, key, value);
}
static void json_print_int(WriterContext *wctx, const char *key, long long int value)
JSONContext *json = wctx->priv;
if (wctx->nb_item) printf("%s", json->item_sep);
if (!json->compact)
JSON_INDENT();
av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
printf("\"%s\": %lld", json_escape_str(&buf, key, wctx), value);
av_bprint_finalize(&buf, NULL);
static void json_show_tags(WriterContext *wctx, AVDictionary *dict)
{
JSONContext *json = wctx->priv;
AVDictionaryEntry *tag = NULL;
int is_first = 1;
if (!dict)
return;
printf("%s", json->item_sep);
if (!json->compact)
JSON_INDENT();
printf("\"tags\": {%s", json->item_start_end);
json->indent_level++;
while ((tag = av_dict_get(dict, "", tag, AV_DICT_IGNORE_SUFFIX))) {
if (is_first) is_first = 0;
else printf("%s", json->item_sep);
if (!json->compact)
JSON_INDENT();
json_print_item_str(wctx, tag->key, tag->value);
json->indent_level--;
printf("%s", json->item_start_end);
if (!json->compact)
JSON_INDENT();
printf("}");
}
.name = "json",
.priv_size = sizeof(JSONContext),
.init = json_init,
.print_header = json_print_header,
.print_footer = json_print_footer,
.print_chapter_header = json_print_chapter_header,
.print_chapter_footer = json_print_chapter_footer,
.print_section_header = json_print_section_header,
.print_section_footer = json_print_section_footer,
.print_integer = json_print_int,
.print_string = json_print_str,
.show_tags = json_show_tags,
.flags = WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER,
Stefano Sabatini
committed
.priv_class = &json_class,
};
/* XML output */
typedef struct {
const AVClass *class;
int within_tag;
int indent_level;
int fully_qualified;
int xsd_strict;
} XMLContext;
#undef OFFSET
#define OFFSET(x) offsetof(XMLContext, x)
static const AVOption xml_options[] = {
{"fully_qualified", "specify if the output should be fully qualified", OFFSET(fully_qualified), AV_OPT_TYPE_INT, {.i64=0}, 0, 1 },
{"q", "specify if the output should be fully qualified", OFFSET(fully_qualified), AV_OPT_TYPE_INT, {.i64=0}, 0, 1 },
{"xsd_strict", "ensure that the output is XSD compliant", OFFSET(xsd_strict), AV_OPT_TYPE_INT, {.i64=0}, 0, 1 },
{"x", "ensure that the output is XSD compliant", OFFSET(xsd_strict), AV_OPT_TYPE_INT, {.i64=0}, 0, 1 },
DEFINE_WRITER_CLASS(xml);
static av_cold int xml_init(WriterContext *wctx, const char *args, void *opaque)
{
XMLContext *xml = wctx->priv;
if (xml->xsd_strict) {
xml->fully_qualified = 1;
#define CHECK_COMPLIANCE(opt, opt_name) \
if (opt) { \
av_log(wctx, AV_LOG_ERROR, \
"XSD-compliant output selected but option '%s' was selected, XML output may be non-compliant.\n" \
"You need to disable such option with '-no%s'\n", opt_name, opt_name); \
Stefano Sabatini
committed
return AVERROR(EINVAL); \
}
CHECK_COMPLIANCE(show_private_data, "private");
CHECK_COMPLIANCE(show_value_unit, "unit");
CHECK_COMPLIANCE(use_value_prefix, "prefix");
if (do_show_frames && do_show_packets) {
av_log(wctx, AV_LOG_ERROR,
"Interleaved frames and packets are not allowed in XSD. "
"Select only one between the -show_frames and the -show_packets options.\n");
return AVERROR(EINVAL);
}
static const char *xml_escape_str(AVBPrint *dst, const char *src, void *log_ctx)
case '&' : av_bprintf(dst, "%s", "&"); break;
case '<' : av_bprintf(dst, "%s", "<"); break;
case '>' : av_bprintf(dst, "%s", ">"); break;
case '\"': av_bprintf(dst, "%s", """); break;
case '\'': av_bprintf(dst, "%s", "'"); break;
default: av_bprint_chars(dst, *p, 1);
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
}
static void xml_print_header(WriterContext *wctx)
{
XMLContext *xml = wctx->priv;
const char *qual = " xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' "
"xmlns:ffprobe='http://www.ffmpeg.org/schema/ffprobe' "
"xsi:schemaLocation='http://www.ffmpeg.org/schema/ffprobe ffprobe.xsd'";
printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
printf("<%sffprobe%s>\n",
xml->fully_qualified ? "ffprobe:" : "",
xml->fully_qualified ? qual : "");
xml->indent_level++;
}
static void xml_print_footer(WriterContext *wctx)
{
XMLContext *xml = wctx->priv;
xml->indent_level--;
printf("</%sffprobe>\n", xml->fully_qualified ? "ffprobe:" : "");
}
#define XML_INDENT() printf("%*c", xml->indent_level * 4, ' ')
static void xml_print_chapter_header(WriterContext *wctx, const char *chapter)
{
XMLContext *xml = wctx->priv;
if (wctx->nb_chapter)
printf("\n");
Clément Bœsch
committed
if (wctx->multiple_sections) {
XML_INDENT(); printf("<%s>\n", chapter);
xml->indent_level++;
}
}
static void xml_print_chapter_footer(WriterContext *wctx, const char *chapter)
{
XMLContext *xml = wctx->priv;
Clément Bœsch
committed
if (wctx->multiple_sections) {
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
xml->indent_level--;
XML_INDENT(); printf("</%s>\n", chapter);
}
}
static void xml_print_section_header(WriterContext *wctx, const char *section)
{
XMLContext *xml = wctx->priv;
XML_INDENT(); printf("<%s ", section);
xml->within_tag = 1;
}
static void xml_print_section_footer(WriterContext *wctx, const char *section)
{
XMLContext *xml = wctx->priv;
if (xml->within_tag)
printf("/>\n");
else {
XML_INDENT(); printf("</%s>\n", section);
}
}
static void xml_print_str(WriterContext *wctx, const char *key, const char *value)
{
av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
printf("%s=\"%s\"", key, xml_escape_str(&buf, value, wctx));
av_bprint_finalize(&buf, NULL);
}
static void xml_print_int(WriterContext *wctx, const char *key, long long int value)
{
if (wctx->nb_item)
printf(" ");
printf("%s=\"%lld\"", key, value);
}
static void xml_show_tags(WriterContext *wctx, AVDictionary *dict)
{
XMLContext *xml = wctx->priv;
AVDictionaryEntry *tag = NULL;
int is_first = 1;
av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
xml->indent_level++;
while ((tag = av_dict_get(dict, "", tag, AV_DICT_IGNORE_SUFFIX))) {
if (is_first) {
/* close section tag */
printf(">\n");
xml->within_tag = 0;
is_first = 0;
}
XML_INDENT();
printf("<tag key=\"%s\"", xml_escape_str(&buf, tag->key, wctx));
printf(" value=\"%s\"/>\n", xml_escape_str(&buf, tag->value, wctx));
av_bprint_finalize(&buf, NULL);
xml->indent_level--;
}
static Writer xml_writer = {
.name = "xml",
.priv_size = sizeof(XMLContext),
.init = xml_init,
.print_header = xml_print_header,
.print_footer = xml_print_footer,
.print_chapter_header = xml_print_chapter_header,
.print_chapter_footer = xml_print_chapter_footer,
.print_section_header = xml_print_section_header,
.print_section_footer = xml_print_section_footer,
.print_integer = xml_print_int,
.print_string = xml_print_str,
.show_tags = xml_show_tags,
.flags = WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER,
Stefano Sabatini
committed
.priv_class = &xml_class,
static void writer_register_all(void)
{
static int initialized;
if (initialized)
return;
initialized = 1;
writer_register(&default_writer);
writer_register(&json_writer);
}
#define print_fmt(k, f, ...) do { \
av_bprint_clear(&pbuf); \
av_bprintf(&pbuf, f, __VA_ARGS__); \
writer_print_string(w, k, pbuf.str, 0); \
} while (0)
#define print_int(k, v) writer_print_integer(w, k, v)
#define print_q(k, v, s) writer_print_rational(w, k, v, s)
#define print_str(k, v) writer_print_string(w, k, v, 0)
#define print_str_opt(k, v) writer_print_string(w, k, v, 1)
#define print_time(k, v, tb) writer_print_time(w, k, v, tb, 0)
#define print_ts(k, v) writer_print_ts(w, k, v, 0)
#define print_duration_time(k, v, tb) writer_print_time(w, k, v, tb, 1)
#define print_duration_ts(k, v) writer_print_ts(w, k, v, 1)
#define print_val(k, v, u) do { \
struct unit_value uv; \
uv.val.i = v; \
uv.unit = u; \
writer_print_string(w, k, value_string(val_str, sizeof(val_str), uv), 0); \
} while (0)
#define print_section_header(s) writer_print_section_header(w, s)
#define print_section_footer(s) writer_print_section_footer(w, s)
#define show_tags(metadata) writer_show_tags(w, metadata)
static void show_packet(WriterContext *w, AVFormatContext *fmt_ctx, AVPacket *pkt, int packet_idx)
{
char val_str[128];
AVStream *st = fmt_ctx->streams[pkt->stream_index];
const char *s;
av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
print_section_header("packet");
s = av_get_media_type_string(st->codec->codec_type);
if (s) print_str ("codec_type", s);
else print_str_opt("codec_type", "unknown");
print_int("stream_index", pkt->stream_index);
print_ts ("pts", pkt->pts);
print_time("pts_time", pkt->pts, &st->time_base);
print_ts ("dts", pkt->dts);
print_time("dts_time", pkt->dts, &st->time_base);
print_duration_ts("duration", pkt->duration);
print_duration_time("duration_time", pkt->duration, &st->time_base);
print_duration_ts("convergence_duration", pkt->convergence_duration);
print_duration_time("convergence_duration_time", pkt->convergence_duration, &st->time_base);
print_val("size", pkt->size, unit_byte_str);
if (pkt->pos != -1) print_fmt ("pos", "%"PRId64, pkt->pos);
else print_str_opt("pos", "N/A");
print_fmt("flags", "%c", pkt->flags & AV_PKT_FLAG_KEY ? 'K' : '_');
if (do_show_data)
writer_print_data(w, "data", pkt->data, pkt->size);
print_section_footer("packet");
av_bprint_finalize(&pbuf, NULL);
Stefano Sabatini
committed
static void show_frame(WriterContext *w, AVFrame *frame, AVStream *stream,
AVFormatContext *fmt_ctx)
const char *s;
av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
print_section_header("frame");
s = av_get_media_type_string(stream->codec->codec_type);
if (s) print_str ("media_type", s);
else print_str_opt("media_type", "unknown");
print_int("key_frame", frame->key_frame);
print_ts ("pkt_pts", frame->pkt_pts);
print_time("pkt_pts_time", frame->pkt_pts, &stream->time_base);
print_ts ("pkt_dts", frame->pkt_dts);
print_time("pkt_dts_time", frame->pkt_dts, &stream->time_base);
print_duration_ts ("pkt_duration", frame->pkt_duration);
print_duration_time("pkt_duration_time", frame->pkt_duration, &stream->time_base);
if (frame->pkt_pos != -1) print_fmt ("pkt_pos", "%"PRId64, frame->pkt_pos);
else print_str_opt("pkt_pos", "N/A");
switch (stream->codec->codec_type) {
Stefano Sabatini
committed
AVRational sar;
case AVMEDIA_TYPE_VIDEO:
print_int("width", frame->width);
print_int("height", frame->height);
s = av_get_pix_fmt_name(frame->format);
if (s) print_str ("pix_fmt", s);
else print_str_opt("pix_fmt", "unknown");
Stefano Sabatini
committed
sar = av_guess_sample_aspect_ratio(fmt_ctx, stream, frame);
if (sar.num) {
print_q("sample_aspect_ratio", sar, ':');
} else {
print_str_opt("sample_aspect_ratio", "N/A");
}
print_fmt("pict_type", "%c", av_get_picture_type_char(frame->pict_type));
print_int("coded_picture_number", frame->coded_picture_number);
print_int("display_picture_number", frame->display_picture_number);
print_int("interlaced_frame", frame->interlaced_frame);
print_int("top_field_first", frame->top_field_first);
print_int("repeat_pict", frame->repeat_pict);
print_int("reference", frame->reference);
break;
case AVMEDIA_TYPE_AUDIO:
s = av_get_sample_fmt_name(frame->format);
if (s) print_str ("sample_fmt", s);
else print_str_opt("sample_fmt", "unknown");
print_int("nb_samples", frame->nb_samples);
print_int("channels", av_frame_get_channels(frame));
if (av_frame_get_channel_layout(frame)) {
av_bprint_clear(&pbuf);
av_bprint_channel_layout(&pbuf, av_frame_get_channels(frame),
av_frame_get_channel_layout(frame));
print_str ("channel_layout", pbuf.str);
} else
print_str_opt("channel_layout", "unknown");
break;
}
show_tags(av_frame_get_metadata(frame));
print_section_footer("frame");
av_bprint_finalize(&pbuf, NULL);
fflush(stdout);
}
static av_always_inline int process_frame(WriterContext *w,
AVFormatContext *fmt_ctx,
AVFrame *frame, AVPacket *pkt)
{
AVCodecContext *dec_ctx = fmt_ctx->streams[pkt->stream_index]->codec;
if (dec_ctx->codec) {
switch (dec_ctx->codec_type) {
case AVMEDIA_TYPE_VIDEO:
ret = avcodec_decode_video2(dec_ctx, frame, &got_frame, pkt);
case AVMEDIA_TYPE_AUDIO:
ret = avcodec_decode_audio4(dec_ctx, frame, &got_frame, pkt);
if (ret < 0)
return ret;
ret = FFMIN(ret, pkt->size); /* guard against bogus return values */
pkt->data += ret;
pkt->size -= ret;
if (got_frame) {
nb_streams_frames[pkt->stream_index]++;
if (do_show_frames)
show_frame(w, frame, fmt_ctx->streams[pkt->stream_index], fmt_ctx);
}
return got_frame;
static void read_packets(WriterContext *w, AVFormatContext *fmt_ctx)
AVPacket pkt, pkt1;
AVFrame frame;
while (!av_read_frame(fmt_ctx, &pkt)) {
if (do_read_packets) {
if (do_show_packets)
show_packet(w, fmt_ctx, &pkt, i++);
nb_streams_packets[pkt.stream_index]++;
}
if (do_read_frames) {
pkt1 = pkt;
while (pkt1.size && process_frame(w, fmt_ctx, &frame, &pkt1) > 0);
}
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
//Flush remaining frames that are cached in the decoder
for (i = 0; i < fmt_ctx->nb_streams; i++) {
pkt.stream_index = i;
if (do_read_frames)
while (process_frame(w, fmt_ctx, &frame, &pkt) > 0);
static void show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_idx)
{
AVStream *stream = fmt_ctx->streams[stream_idx];
AVCodecContext *dec_ctx;
const char *s;
Stefano Sabatini
committed
AVRational sar, dar;
AVBPrint pbuf;
av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
print_section_header("stream");
print_int("index", stream->index);
const char *profile = NULL;
dec = dec_ctx->codec;
if (dec) {
print_str("codec_name", dec->name);
if (!do_bitexact) {
if (dec->long_name) print_str ("codec_long_name", dec->long_name);
else print_str_opt("codec_long_name", "unknown");
print_str_opt("codec_name", "unknown");
print_str_opt("codec_long_name", "unknown");
if (dec && (profile = av_get_profile_name(dec, dec_ctx->profile)))
print_str("profile", profile);
else
print_str_opt("profile", "unknown");
s = av_get_media_type_string(dec_ctx->codec_type);
if (s) print_str ("codec_type", s);
else print_str_opt("codec_type", "unknown");
print_q("codec_time_base", dec_ctx->time_base, '/');
av_get_codec_tag_string(val_str, sizeof(val_str), dec_ctx->codec_tag);
print_str("codec_tag_string", val_str);
print_fmt("codec_tag", "0x%04x", dec_ctx->codec_tag);
/* Print useful disposition */
print_int("default", !!(stream->disposition & AV_DISPOSITION_DEFAULT));
print_int("forced", !!(stream->disposition & AV_DISPOSITION_FORCED));
case AVMEDIA_TYPE_VIDEO:
print_int("width", dec_ctx->width);
print_int("height", dec_ctx->height);
print_int("has_b_frames", dec_ctx->has_b_frames);
Stefano Sabatini
committed
sar = av_guess_sample_aspect_ratio(fmt_ctx, stream, NULL);
if (sar.den) {
print_q("sample_aspect_ratio", sar, ':');
av_reduce(&dar.num, &dar.den,
dec_ctx->width * sar.num,
dec_ctx->height * sar.den,
Stefano Sabatini
committed
print_q("display_aspect_ratio", dar, ':');
} else {
print_str_opt("sample_aspect_ratio", "N/A");
print_str_opt("display_aspect_ratio", "N/A");
}
s = av_get_pix_fmt_name(dec_ctx->pix_fmt);
if (s) print_str ("pix_fmt", s);
else print_str_opt("pix_fmt", "unknown");
print_int("level", dec_ctx->level);
if (dec_ctx->timecode_frame_start >= 0) {
char tcbuf[AV_TIMECODE_STR_SIZE];
av_timecode_make_mpeg_tc_string(tcbuf, dec_ctx->timecode_frame_start);
print_str("timecode", tcbuf);
} else {
print_str_opt("timecode", "N/A");
}
print_int("attached_pic",
!!(stream->disposition & AV_DISPOSITION_ATTACHED_PIC));
case AVMEDIA_TYPE_AUDIO:
s = av_get_sample_fmt_name(dec_ctx->sample_fmt);
if (s) print_str ("sample_fmt", s);
else print_str_opt("sample_fmt", "unknown");
print_val("sample_rate", dec_ctx->sample_rate, unit_hertz_str);
print_int("channels", dec_ctx->channels);
print_int("bits_per_sample", av_get_bits_per_sample(dec_ctx->codec_id));
print_str_opt("codec_type", "unknown");
if (dec_ctx->codec && dec_ctx->codec->priv_class && show_private_data) {
while (opt = av_opt_next(dec_ctx->priv_data,opt)) {
uint8_t *str;
if (opt->flags) continue;
if (av_opt_get(dec_ctx->priv_data, opt->name, 0, &str) >= 0) {
print_str(opt->name, str);
av_free(str);
}
}
}
if (fmt_ctx->iformat->flags & AVFMT_SHOW_IDS) print_fmt ("id", "0x%x", stream->id);
else print_str_opt("id", "N/A");
print_q("r_frame_rate", stream->r_frame_rate, '/');
print_q("avg_frame_rate", stream->avg_frame_rate, '/');
print_q("time_base", stream->time_base, '/');
print_ts ("start_pts", stream->start_time);
print_time("start_time", stream->start_time, &stream->time_base);
print_ts ("duration_ts", stream->duration);
print_time("duration", stream->duration, &stream->time_base);
if (dec_ctx->bit_rate > 0) print_val ("bit_rate", dec_ctx->bit_rate, unit_bit_per_second_str);
else print_str_opt("bit_rate", "N/A");
if (stream->nb_frames) print_fmt ("nb_frames", "%"PRId64, stream->nb_frames);
else print_str_opt("nb_frames", "N/A");
if (nb_streams_frames[stream_idx]) print_fmt ("nb_read_frames", "%"PRIu64, nb_streams_frames[stream_idx]);
else print_str_opt("nb_read_frames", "N/A");
if (nb_streams_packets[stream_idx]) print_fmt ("nb_read_packets", "%"PRIu64, nb_streams_packets[stream_idx]);
else print_str_opt("nb_read_packets", "N/A");
if (do_show_data)
writer_print_data(w, "extradata", dec_ctx->extradata,
dec_ctx->extradata_size);
show_tags(stream->metadata);
print_section_footer("stream");
av_bprint_finalize(&pbuf, NULL);
static void show_streams(WriterContext *w, AVFormatContext *fmt_ctx)
{
int i;
for (i = 0; i < fmt_ctx->nb_streams; i++)
show_stream(w, fmt_ctx, i);
}
static void show_format(WriterContext *w, AVFormatContext *fmt_ctx)
int64_t size = fmt_ctx->pb ? avio_size(fmt_ctx->pb) : -1;
print_section_header("format");
print_str("filename", fmt_ctx->filename);
print_int("nb_streams", fmt_ctx->nb_streams);
print_str("format_name", fmt_ctx->iformat->name);
if (fmt_ctx->iformat->long_name) print_str ("format_long_name", fmt_ctx->iformat->long_name);
else print_str_opt("format_long_name", "unknown");
print_time("start_time", fmt_ctx->start_time, &AV_TIME_BASE_Q);
print_time("duration", fmt_ctx->duration, &AV_TIME_BASE_Q);
if (size >= 0) print_val ("size", size, unit_byte_str);
else print_str_opt("size", "N/A");
if (fmt_ctx->bit_rate > 0) print_val ("bit_rate", fmt_ctx->bit_rate, unit_bit_per_second_str);
else print_str_opt("bit_rate", "N/A");
show_tags(fmt_ctx->metadata);
print_section_footer("format");
static void show_error(WriterContext *w, int err)
{
char errbuf[128];
const char *errbuf_ptr = errbuf;
if (av_strerror(err, errbuf, sizeof(errbuf)) < 0)
errbuf_ptr = strerror(AVUNERROR(err));
writer_print_chapter_header(w, "error");
print_section_header("error");
print_int("code", err);
print_str("string", errbuf_ptr);
print_section_footer("error");
writer_print_chapter_footer(w, "error");
}
static int open_input_file(AVFormatContext **fmt_ctx_ptr, const char *filename)
{
int err, i;
AVFormatContext *fmt_ctx = NULL;
AVDictionaryEntry *t;
if ((err = avformat_open_input(&fmt_ctx, filename,
iformat, &format_opts)) < 0) {
print_error(filename, err);
return err;
}
if ((t = av_dict_get(format_opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
av_log(NULL, AV_LOG_ERROR, "Option %s not found.\n", t->key);
return AVERROR_OPTION_NOT_FOUND;
}
if ((err = avformat_find_stream_info(fmt_ctx, NULL)) < 0) {
print_error(filename, err);
return err;
}
av_dump_format(fmt_ctx, 0, filename, 0);
/* bind a decoder to each input stream */
for (i = 0; i < fmt_ctx->nb_streams; i++) {
AVStream *stream = fmt_ctx->streams[i];
AVCodec *codec;
if (stream->codec->codec_id == AV_CODEC_ID_PROBE) {
av_log(NULL, AV_LOG_ERROR,
"Failed to probe codec for input stream %d\n",
stream->index);
} else if (!(codec = avcodec_find_decoder(stream->codec->codec_id))) {
av_log(NULL, AV_LOG_ERROR,
"Unsupported codec with id %d for input stream %d\n",
stream->codec->codec_id, stream->index);
} else if (avcodec_open2(stream->codec, codec, NULL) < 0) {
av_log(NULL, AV_LOG_ERROR, "Error while opening codec for input stream %d\n",
stream->index);
}
}
*fmt_ctx_ptr = fmt_ctx;
return 0;
}
static void close_input_file(AVFormatContext **ctx_ptr)
{
int i;
AVFormatContext *fmt_ctx = *ctx_ptr;
/* close decoder for each stream */
for (i = 0; i < fmt_ctx->nb_streams; i++)
if (fmt_ctx->streams[i]->codec->codec_id != AV_CODEC_ID_NONE)
avcodec_close(fmt_ctx->streams[i]->codec);
avformat_close_input(ctx_ptr);
}
#define PRINT_CHAPTER(name) do { \
if (do_show_ ## name) { \
writer_print_chapter_header(wctx, #name); \
show_ ## name (wctx, fmt_ctx); \
writer_print_chapter_footer(wctx, #name); \
} \
static int probe_file(WriterContext *wctx, const char *filename)
do_read_frames = do_show_frames || do_count_frames;
do_read_packets = do_show_packets || do_count_packets;
ret = open_input_file(&fmt_ctx, filename);
if (ret >= 0) {
nb_streams_frames = av_calloc(fmt_ctx->nb_streams, sizeof(*nb_streams_frames));
nb_streams_packets = av_calloc(fmt_ctx->nb_streams, sizeof(*nb_streams_packets));
if (do_read_frames || do_read_packets) {
const char *chapter;
if (do_show_frames && do_show_packets &&
wctx->writer->flags & WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER)
chapter = "packets_and_frames";
else if (do_show_packets && !do_show_frames)
chapter = "packets";
else // (!do_show_packets && do_show_frames)
chapter = "frames";
if (do_show_frames || do_show_packets)
writer_print_chapter_header(wctx, chapter);
read_packets(wctx, fmt_ctx);
if (do_show_frames || do_show_packets)
writer_print_chapter_footer(wctx, chapter);
PRINT_CHAPTER(streams);
PRINT_CHAPTER(format);
close_input_file(&fmt_ctx);
av_freep(&nb_streams_frames);
av_freep(&nb_streams_packets);
av_log(NULL, AV_LOG_INFO, "Simple multimedia streams analyzer\n");
av_log(NULL, AV_LOG_INFO, "usage: %s [OPTIONS] [INPUT_FILE]\n", program_name);
av_log(NULL, AV_LOG_INFO, "\n");
static void ffprobe_show_program_version(WriterContext *w)
{
AVBPrint pbuf;
av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
writer_print_chapter_header(w, "program_version");
print_section_header("program_version");
print_str("version", FFMPEG_VERSION);
print_fmt("copyright", "Copyright (c) %d-%d the FFmpeg developers",
program_birth_year, this_year);
print_str("build_date", __DATE__);
print_str("build_time", __TIME__);
print_str("compiler_ident", CC_IDENT);
print_str("configuration", FFMPEG_CONFIGURATION);
print_section_footer("program_version");
writer_print_chapter_footer(w, "program_version");
av_bprint_finalize(&pbuf, NULL);
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
}
#define SHOW_LIB_VERSION(libname, LIBNAME) \
do { \
if (CONFIG_##LIBNAME) { \
unsigned int version = libname##_version(); \
print_section_header("library_version"); \
print_str("name", "lib" #libname); \
print_int("major", LIB##LIBNAME##_VERSION_MAJOR); \
print_int("minor", LIB##LIBNAME##_VERSION_MINOR); \
print_int("micro", LIB##LIBNAME##_VERSION_MICRO); \
print_int("version", version); \
print_section_footer("library_version"); \
} \
} while (0)
static void ffprobe_show_library_versions(WriterContext *w)
{
writer_print_chapter_header(w, "library_versions");
SHOW_LIB_VERSION(avutil, AVUTIL);
SHOW_LIB_VERSION(avcodec, AVCODEC);
SHOW_LIB_VERSION(avformat, AVFORMAT);
SHOW_LIB_VERSION(avdevice, AVDEVICE);
SHOW_LIB_VERSION(avfilter, AVFILTER);
SHOW_LIB_VERSION(swscale, SWSCALE);
SHOW_LIB_VERSION(swresample, SWRESAMPLE);
SHOW_LIB_VERSION(postproc, POSTPROC);
writer_print_chapter_footer(w, "library_versions");
}
static int opt_format(void *optctx, const char *opt, const char *arg)
{
iformat = av_find_input_format(arg);
if (!iformat) {
av_log(NULL, AV_LOG_ERROR, "Unknown input format: %s\n", arg);
}
}
static int opt_show_format_entry(void *optctx, const char *opt, const char *arg)
{
do_show_format = 1;
av_dict_set(&fmt_entries_to_show, arg, "", 0);
return 0;
}
static void opt_input_file(void *optctx, const char *arg)