Newer
Older
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
else
av_bprint_chars(dst, c, 1);
break;
}
}
return dst->str;
}
static void ini_print_chapter_header(WriterContext *wctx, const char *chapter)
{
INIContext *ini = wctx->priv;
av_bprint_clear(&ini->chapter_name);
av_bprintf(&ini->chapter_name, "%s", chapter);
if (wctx->nb_chapter)
printf("\n");
}
static void ini_print_section_header(WriterContext *wctx, const char *section)
{
INIContext *ini = wctx->priv;
int n = wctx->is_packets_and_frames ? wctx->nb_section_packet_frame
: wctx->nb_section;
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
if (wctx->nb_section)
printf("\n");
av_bprint_clear(&ini->section_name);
if (ini->hierarchical && wctx->multiple_sections)
av_bprintf(&ini->section_name, "%s.", ini->chapter_name.str);
av_bprintf(&ini->section_name, "%s", section);
if (wctx->multiple_sections)
av_bprintf(&ini->section_name, ".%d", n);
printf("[%s]\n", ini->section_name.str);
}
static void ini_print_str(WriterContext *wctx, const char *key, const char *value)
{
AVBPrint buf;
av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
printf("%s=", ini_escape_str(&buf, key));
av_bprint_clear(&buf);
printf("%s\n", ini_escape_str(&buf, value));
av_bprint_finalize(&buf, NULL);
}
static void ini_print_int(WriterContext *wctx, const char *key, long long int value)
{
printf("%s=%lld\n", key, value);
}
static void ini_show_tags(WriterContext *wctx, AVDictionary *dict)
{
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,
};
/* 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, {.dbl=0}, 0, 1 },
{ "c", "enable compact output", OFFSET(compact), AV_OPT_TYPE_INT, {.dbl=0}, 0, 1 },
{ NULL }
};
static const char *json_get_name(void *ctx)
{
return "json";
}
static const AVClass json_class = {
"JSONContext",
json_get_name,
json_options
};
static av_cold int json_init(WriterContext *wctx, const char *args, void *opaque)
{
JSONContext *json = wctx->priv;
int err;
json->class = &json_class;
av_opt_set_defaults(json);
if (args &&
(err = (av_set_options_string(json, args, "=", ":"))) < 0)
return err;
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,
};
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
/* 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, {.dbl=0}, 0, 1 },
{"q", "specify if the output should be fully qualified", OFFSET(fully_qualified), AV_OPT_TYPE_INT, {.dbl=0}, 0, 1 },
{"xsd_strict", "ensure that the output is XSD compliant", OFFSET(xsd_strict), AV_OPT_TYPE_INT, {.dbl=0}, 0, 1 },
{"x", "ensure that the output is XSD compliant", OFFSET(xsd_strict), AV_OPT_TYPE_INT, {.dbl=0}, 0, 1 },
{NULL},
};
static const char *xml_get_name(void *ctx)
{
return "xml";
}
static const AVClass xml_class = {
"XMLContext",
xml_get_name,
xml_options
};
static av_cold int xml_init(WriterContext *wctx, const char *args, void *opaque)
{
XMLContext *xml = wctx->priv;
int err;
xml->class = &xml_class;
av_opt_set_defaults(xml);
if (args &&
(err = (av_set_options_string(xml, args, "=", ":"))) < 0)
return err;
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);
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
}
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) {
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
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,
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) writer_print_string(w, k, \
value_string(val_str, sizeof(val_str), (struct unit_value){.val.i = v, .unit=u}), 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;
print_str("codec_name", dec->name);
print_str("codec_long_name", dec->long_name);
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);
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");
}
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_time("start_time", stream->start_time, &stream->time_base);
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);
print_str("format_long_name", fmt_ctx->iformat->long_name);
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);