Created
May 15, 2012 14:28
-
-
Save lu-zero/2702182 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/avprobe.c b/avprobe.c | |
index 8d2ec24..848d278 100644 | |
--- a/avprobe.c | |
+++ b/avprobe.c | |
@@ -63,6 +63,207 @@ void exit_program(int ret) | |
exit(ret); | |
} | |
+static int print_section_separator; | |
+static int print_chapter_separator; | |
+static int print_item_separator; | |
+static int indent_level; | |
+ | |
+ | |
+AVIOContext *avp_out = NULL; | |
+ | |
+#define AVP_INDENT() avio_printf(avp_out, "%*c", indent_level * 2, ' ') | |
+ | |
+static void default_print_header(void) | |
+{ | |
+ avio_printf(avp_out, "{"); | |
+ indent_level++; | |
+} | |
+static void default_print_footer(void) | |
+{ | |
+ avio_printf(avp_out, "}\n"); | |
+ indent_level--; | |
+} | |
+ | |
+static void default_print_chapter_header(const char *name) | |
+{ | |
+ if (print_chapter_separator) | |
+ avio_printf(avp_out, ",\n"); | |
+ AVP_INDENT(); | |
+ avio_printf(avp_out, "'%s' : {\n", name); | |
+ indent_level++; | |
+} | |
+static void default_print_chapter_footer(const char *name) | |
+{ | |
+ indent_level--; | |
+ avio_printf(avp_out, "\n"); | |
+ AVP_INDENT(); | |
+ avio_printf(avp_out, "}"); | |
+} | |
+ | |
+static void default_print_section_header(const char *name) | |
+{ | |
+ if (print_section_separator) | |
+ avio_printf(avp_out, ",\n"); | |
+ AVP_INDENT(); | |
+ avio_printf(avp_out, "'%s' : {\n", name); | |
+ indent_level++; | |
+} | |
+ | |
+static void default_print_section_footer(const char *name) | |
+{ | |
+ indent_level--; | |
+ avio_printf(avp_out, "\n"); | |
+ AVP_INDENT(); | |
+ avio_printf(avp_out, "}"); | |
+} | |
+ | |
+static void default_print_integer(const char *key, int64_t value) | |
+{ | |
+ if (print_item_separator) | |
+ avio_printf(avp_out, ",\n"); | |
+ AVP_INDENT(); | |
+ avio_printf(avp_out, "'%s' : %"PRId64"", key, value); | |
+} | |
+ | |
+static void default_escape_print(const char *s) | |
+{ | |
+ int i = 0; | |
+ char c = 0; | |
+ | |
+ while (c = s[i++]) { | |
+ switch (c) { | |
+ case '\r': avio_printf(avp_out, "%s", "\\r"); break; | |
+ case '\n': avio_printf(avp_out, "%s", "\\n"); break; | |
+ case '\\': avio_printf(avp_out, "%s", "\\\\"); break; | |
+ case '"' : avio_printf(avp_out, "%s", "\\\""); break; | |
+ case '\f': avio_printf(avp_out, "%s", "\\f"); break; | |
+ case '\b': avio_printf(avp_out, "%s", "\\b"); break; | |
+ case '\t': avio_printf(avp_out, "%s", "\\t"); break; | |
+ default: | |
+ if ((unsigned char)c < 32) | |
+ avio_printf(avp_out, "\\u00%02x", c & 0xff); | |
+ else | |
+ avio_w8(avp_out, c); | |
+ break; | |
+ } | |
+ } | |
+} | |
+ | |
+static void default_print_string(const char *key, const char *value) | |
+{ | |
+ if (print_item_separator) | |
+ avio_printf(avp_out, ",\n"); | |
+ AVP_INDENT(); | |
+ avio_w8(avp_out, '\''); | |
+ default_escape_print(key); | |
+ avio_printf(avp_out, "' : '"); | |
+ default_escape_print(value); | |
+ avio_w8(avp_out, '\''); | |
+} | |
+ | |
+static void show_format_entry_integer(const char *key, int64_t value) | |
+{ | |
+ if (key && av_dict_get(fmt_entries_to_show, key, NULL, 0)) { | |
+ avio_printf(avp_out, "%s=%"PRId64"\n", key, value); | |
+ } | |
+} | |
+ | |
+static void show_format_entry_string(const char *key, const char *value) | |
+{ | |
+ if (key && av_dict_get(fmt_entries_to_show, key, NULL, 0)) { | |
+ avio_printf(avp_out, "%s=%s\n", key, value); | |
+ } | |
+} | |
+ | |
+ | |
+void (*print_header)(void) = default_print_header; | |
+void (*print_footer)(void) = default_print_footer; | |
+ | |
+void (*print_chapter_header)(const char *name) = | |
+default_print_chapter_header; | |
+void (*print_chapter_footer)(const char *name) = | |
+default_print_chapter_footer; | |
+void (*print_section_header)(const char *name) = | |
+default_print_section_header; | |
+void (*print_section_footer)(const char *name) = | |
+default_print_section_footer; | |
+void (*print_integer) (const char *key, int64_t value) = | |
+default_print_integer; | |
+void (*print_string) (const char *key, const char *value) = | |
+default_print_string; | |
+ | |
+static void avp_header(void) | |
+{ | |
+ if (print_header) | |
+ print_header(); | |
+ print_chapter_separator = 0; | |
+} | |
+ | |
+static void avp_footer(void) | |
+{ | |
+ if (print_footer) | |
+ print_footer(); | |
+} | |
+ | |
+static void avp_chapter_header(const char *chapter) | |
+{ | |
+ if (print_chapter_header) | |
+ print_chapter_header(chapter); | |
+ print_section_separator = 0; | |
+} | |
+ | |
+static void avp_chapter_footer(const char *chapter) | |
+{ | |
+ if (print_chapter_footer) | |
+ print_chapter_footer(chapter); | |
+ print_chapter_separator = 1; | |
+} | |
+ | |
+static void avp_section_header(const char *section) | |
+{ | |
+ if (!fmt_entries_to_show || | |
+ (section && av_dict_get(fmt_entries_to_show, section, NULL, 0))) { | |
+ if (print_section_header) | |
+ print_section_header(section); | |
+ print_item_separator = 0; | |
+ } | |
+} | |
+ | |
+static void avp_section_footer(const char *section) | |
+{ | |
+ if (!fmt_entries_to_show || | |
+ (section && av_dict_get(fmt_entries_to_show, section, NULL, 0))) { | |
+ if (print_section_footer) | |
+ print_section_footer(section); | |
+ print_section_separator = 1; | |
+ } | |
+} | |
+ | |
+static void avp_int(const char *key, int64_t value) | |
+{ | |
+ print_integer(key, value); | |
+ print_item_separator = 1; | |
+} | |
+ | |
+static void avp_str(const char *key, const char *value) | |
+{ | |
+ print_string(key, value); | |
+ print_item_separator = 1; | |
+} | |
+ | |
+static void avp_dict(AVDictionary *dict, const char *name) | |
+{ | |
+ AVDictionaryEntry *entry = NULL; | |
+ if (!dict) | |
+ return; | |
+ print_section_separator = print_item_separator; | |
+ avp_section_header(name); | |
+ while ((entry = av_dict_get(dict, "", entry, AV_DICT_IGNORE_SUFFIX))) { | |
+ print_string(entry->key, entry->value); | |
+ } | |
+ avp_section_footer(name); | |
+} | |
+ | |
static char *value_string(char *buf, int buf_size, double val, const char *unit) | |
{ | |
if (unit == unit_second_str && use_value_sexagesimal_format) { | |
@@ -89,11 +290,12 @@ static char *value_string(char *buf, int buf_size, double val, const char *unit) | |
val /= pow(10, index * 3); | |
prefix_string = decimal_unit_prefixes[index]; | |
} | |
- | |
- snprintf(buf, buf_size, "%.3f %s%s", val, prefix_string, | |
+ snprintf(buf, buf_size, "%.*f%s%s", | |
+ index ? 3 : 0, val, | |
+ prefix_string, | |
show_value_unit ? unit : ""); | |
} else { | |
- snprintf(buf, buf_size, "%f %s", val, show_value_unit ? unit : ""); | |
+ snprintf(buf, buf_size, "%f%s", val, show_value_unit ? unit : ""); | |
} | |
return buf; | |
@@ -111,7 +313,7 @@ static char *time_value_string(char *buf, int buf_size, int64_t val, | |
return buf; | |
} | |
-static char *ts_value_string (char *buf, int buf_size, int64_t ts) | |
+static char *ts_value_string(char *buf, int buf_size, int64_t ts) | |
{ | |
if (ts == AV_NOPTS_VALUE) { | |
snprintf(buf, buf_size, "N/A"); | |
@@ -122,6 +324,21 @@ static char *ts_value_string (char *buf, int buf_size, int64_t ts) | |
return buf; | |
} | |
+static char *rational_string(char *buf, int buf_size, const char *sep, | |
+ const AVRational *rat) | |
+{ | |
+ snprintf(buf, buf_size, "%d%s%d", rat->num, sep, rat->den); | |
+ return buf; | |
+} | |
+ | |
+static char *tag_string(char *buf, int buf_size, int tag) | |
+{ | |
+ snprintf(buf, buf_size, "0x%04x", tag); | |
+ return buf; | |
+} | |
+ | |
+ | |
+ | |
static const char *media_type_string(enum AVMediaType media_type) | |
{ | |
switch (media_type) { | |
@@ -139,25 +356,25 @@ static void show_packet(AVFormatContext *fmt_ctx, AVPacket *pkt) | |
char val_str[128]; | |
AVStream *st = fmt_ctx->streams[pkt->stream_index]; | |
- printf("[PACKET]\n"); | |
- printf("codec_type=%s\n", media_type_string(st->codec->codec_type)); | |
- printf("stream_index=%d\n", pkt->stream_index); | |
- printf("pts=%s\n", ts_value_string(val_str, sizeof(val_str), pkt->pts)); | |
- printf("pts_time=%s\n", time_value_string(val_str, sizeof(val_str), | |
- pkt->pts, &st->time_base)); | |
- printf("dts=%s\n", ts_value_string(val_str, sizeof(val_str), pkt->dts)); | |
- printf("dts_time=%s\n", time_value_string(val_str, sizeof(val_str), | |
- pkt->dts, &st->time_base)); | |
- printf("duration=%s\n", ts_value_string(val_str, sizeof(val_str), | |
- pkt->duration)); | |
- printf("duration_time=%s\n", time_value_string(val_str, sizeof(val_str), | |
- pkt->duration, | |
- &st->time_base)); | |
- printf("size=%s\n", value_string(val_str, sizeof(val_str), | |
- pkt->size, unit_byte_str)); | |
- printf("pos=%"PRId64"\n", pkt->pos); | |
- printf("flags=%c\n", pkt->flags & AV_PKT_FLAG_KEY ? 'K' : '_'); | |
- printf("[/PACKET]\n"); | |
+ avp_section_header("packet"); | |
+ avp_str("codec_type", media_type_string(st->codec->codec_type)); | |
+ avp_int("stream_index", pkt->stream_index); | |
+ avp_str("pts", ts_value_string(val_str, sizeof(val_str), pkt->pts)); | |
+ avp_str("pts_time", time_value_string(val_str, sizeof(val_str), | |
+ pkt->pts, &st->time_base)); | |
+ avp_str("dts", ts_value_string(val_str, sizeof(val_str), pkt->dts)); | |
+ avp_str("dts_time", time_value_string(val_str, sizeof(val_str), | |
+ pkt->dts, &st->time_base)); | |
+ avp_str("duration", ts_value_string(val_str, sizeof(val_str), | |
+ pkt->duration)); | |
+ avp_str("duration_time", time_value_string(val_str, sizeof(val_str), | |
+ pkt->duration, | |
+ &st->time_base)); | |
+ avp_str("size", value_string(val_str, sizeof(val_str), | |
+ pkt->size, unit_byte_str)); | |
+ avp_int("pos", pkt->pos); | |
+ avp_str("flags", pkt->flags & AV_PKT_FLAG_KEY ? "K" : "_"); | |
+ avp_section_footer("packet"); | |
} | |
static void show_packets(AVFormatContext *fmt_ctx) | |
@@ -165,9 +382,10 @@ static void show_packets(AVFormatContext *fmt_ctx) | |
AVPacket pkt; | |
av_init_packet(&pkt); | |
- | |
+ avp_chapter_header("packets"); | |
while (!av_read_frame(fmt_ctx, &pkt)) | |
show_packet(fmt_ctx, &pkt); | |
+ avp_chapter_footer("packets"); | |
} | |
static void show_stream(AVFormatContext *fmt_ctx, int stream_idx) | |
@@ -176,136 +394,121 @@ static void show_stream(AVFormatContext *fmt_ctx, int stream_idx) | |
AVCodecContext *dec_ctx; | |
AVCodec *dec; | |
char val_str[128]; | |
- AVDictionaryEntry *tag = NULL; | |
AVRational display_aspect_ratio; | |
- printf("[STREAM]\n"); | |
+ avp_section_header("stream"); | |
- printf("index=%d\n", stream->index); | |
+ avp_int("index", stream->index); | |
if ((dec_ctx = stream->codec)) { | |
if ((dec = dec_ctx->codec)) { | |
- printf("codec_name=%s\n", dec->name); | |
- printf("codec_long_name=%s\n", dec->long_name); | |
+ avp_str("codec_name", dec->name); | |
+ avp_str("codec_long_name", dec->long_name); | |
} else { | |
- printf("codec_name=unknown\n"); | |
+ avp_str("codec_name", "unknown"); | |
} | |
- printf("codec_type=%s\n", media_type_string(dec_ctx->codec_type)); | |
- printf("codec_time_base=%d/%d\n", | |
- dec_ctx->time_base.num, dec_ctx->time_base.den); | |
+ avp_str("codec_type", media_type_string(dec_ctx->codec_type)); | |
+ avp_str("codec_time_base", | |
+ rational_string(val_str, sizeof(val_str), | |
+ "/", &dec_ctx->time_base)); | |
/* print AVI/FourCC tag */ | |
av_get_codec_tag_string(val_str, sizeof(val_str), dec_ctx->codec_tag); | |
- printf("codec_tag_string=%s\n", val_str); | |
- printf("codec_tag=0x%04x\n", dec_ctx->codec_tag); | |
+ avp_str("codec_tag_string", val_str); | |
+ avp_str("codec_tag", tag_string(val_str, sizeof(val_str), | |
+ dec_ctx->codec_tag)); | |
switch (dec_ctx->codec_type) { | |
case AVMEDIA_TYPE_VIDEO: | |
- printf("width=%d\n", dec_ctx->width); | |
- printf("height=%d\n", dec_ctx->height); | |
- printf("has_b_frames=%d\n", dec_ctx->has_b_frames); | |
+ avp_int("width", dec_ctx->width); | |
+ avp_int("height", dec_ctx->height); | |
+ avp_int("has_b_frames", dec_ctx->has_b_frames); | |
if (dec_ctx->sample_aspect_ratio.num) { | |
- printf("sample_aspect_ratio=%d:%d\n", | |
- dec_ctx->sample_aspect_ratio.num, | |
- dec_ctx->sample_aspect_ratio.den); | |
+ avp_str("sample_aspect_ratio", | |
+ rational_string(val_str, sizeof(val_str), ":", | |
+ &dec_ctx->sample_aspect_ratio)); | |
av_reduce(&display_aspect_ratio.num, &display_aspect_ratio.den, | |
dec_ctx->width * dec_ctx->sample_aspect_ratio.num, | |
dec_ctx->height * dec_ctx->sample_aspect_ratio.den, | |
1024*1024); | |
- printf("display_aspect_ratio=%d:%d\n", | |
- display_aspect_ratio.num, display_aspect_ratio.den); | |
+ avp_str("display_aspect_ratio", | |
+ rational_string(val_str, sizeof(val_str), ":", | |
+ &display_aspect_ratio)); | |
} | |
- printf("pix_fmt=%s\n", | |
+ avp_str("pix_fmt", | |
dec_ctx->pix_fmt != PIX_FMT_NONE ? av_pix_fmt_descriptors[dec_ctx->pix_fmt].name | |
: "unknown"); | |
- printf("level=%d\n", dec_ctx->level); | |
+ avp_int("level", dec_ctx->level); | |
break; | |
case AVMEDIA_TYPE_AUDIO: | |
- printf("sample_rate=%s\n", value_string(val_str, sizeof(val_str), | |
- dec_ctx->sample_rate, | |
- unit_hertz_str)); | |
- printf("channels=%d\n", dec_ctx->channels); | |
- printf("bits_per_sample=%d\n", | |
- av_get_bits_per_sample(dec_ctx->codec_id)); | |
+ avp_str("sample_rate=", | |
+ value_string(val_str, sizeof(val_str), | |
+ dec_ctx->sample_rate, | |
+ unit_hertz_str)); | |
+ avp_int("channels", dec_ctx->channels); | |
+ avp_int("bits_per_sample", | |
+ av_get_bits_per_sample(dec_ctx->codec_id)); | |
break; | |
} | |
} else { | |
- printf("codec_type=unknown\n"); | |
+ avp_str("codec_type", "unknown"); | |
} | |
if (fmt_ctx->iformat->flags & AVFMT_SHOW_IDS) | |
- printf("id=0x%x\n", stream->id); | |
- printf("r_frame_rate=%d/%d\n", | |
- stream->r_frame_rate.num, stream->r_frame_rate.den); | |
- printf("avg_frame_rate=%d/%d\n", | |
- stream->avg_frame_rate.num, stream->avg_frame_rate.den); | |
- printf("time_base=%d/%d\n", | |
- stream->time_base.num, stream->time_base.den); | |
- printf("start_time=%s\n", | |
- time_value_string(val_str, sizeof(val_str), | |
+ avp_int("id", stream->id); | |
+ avp_str("r_frame_rate", | |
+ rational_string(val_str, sizeof(val_str), "/", | |
+ &stream->r_frame_rate)); | |
+ avp_str("avg_frame_rate", | |
+ rational_string(val_str, sizeof(val_str), "/", | |
+ &stream->avg_frame_rate)); | |
+ avp_str("time_base", | |
+ rational_string(val_str, sizeof(val_str), "/", | |
+ &stream->time_base)); | |
+ avp_str("start_time", | |
+ time_value_string(val_str, sizeof(val_str), | |
stream->start_time, &stream->time_base)); | |
- printf("duration=%s\n", | |
- time_value_string(val_str, sizeof(val_str), | |
- stream->duration, &stream->time_base)); | |
+ avp_str("duration", | |
+ time_value_string(val_str, sizeof(val_str), | |
+ stream->duration, &stream->time_base)); | |
if (stream->nb_frames) | |
- printf("nb_frames=%"PRId64"\n", stream->nb_frames); | |
+ avp_int("nb_frames", stream->nb_frames); | |
- while ((tag = av_dict_get(stream->metadata, "", tag, | |
- AV_DICT_IGNORE_SUFFIX))) | |
- printf("TAG:%s=%s\n", tag->key, tag->value); | |
+ avp_dict(stream->metadata, "tags"); | |
- printf("[/STREAM]\n"); | |
-} | |
- | |
-static void print_format_entry(const char *tag, | |
- const char *val) | |
-{ | |
- if (!fmt_entries_to_show) { | |
- if (tag) { | |
- printf("%s=%s\n", tag, val); | |
- } else { | |
- printf("%s\n", val); | |
- } | |
- } else if (tag && av_dict_get(fmt_entries_to_show, tag, NULL, 0)) { | |
- printf("%s=%s\n", tag, val); | |
- } | |
+ avp_section_footer("stream"); | |
} | |
static void show_format(AVFormatContext *fmt_ctx) | |
{ | |
- AVDictionaryEntry *tag = NULL; | |
char val_str[128]; | |
int64_t size = fmt_ctx->pb ? avio_size(fmt_ctx->pb) : -1; | |
- print_format_entry(NULL, "[FORMAT]"); | |
- print_format_entry("filename", fmt_ctx->filename); | |
+ avp_section_header("format"); | |
+ avp_str("filename", fmt_ctx->filename); | |
snprintf(val_str, sizeof(val_str) - 1, "%d", fmt_ctx->nb_streams); | |
- print_format_entry("nb_streams", val_str); | |
- print_format_entry("format_name", fmt_ctx->iformat->name); | |
- print_format_entry("format_long_name", fmt_ctx->iformat->long_name); | |
- print_format_entry("start_time", | |
+ avp_str("nb_streams", val_str); | |
+ avp_str("format_name", fmt_ctx->iformat->name); | |
+ avp_str("format_long_name", fmt_ctx->iformat->long_name); | |
+ avp_str("start_time", | |
time_value_string(val_str, sizeof(val_str), | |
fmt_ctx->start_time, &AV_TIME_BASE_Q)); | |
- print_format_entry("duration", | |
+ avp_str("duration", | |
time_value_string(val_str, sizeof(val_str), | |
fmt_ctx->duration, &AV_TIME_BASE_Q)); | |
- print_format_entry("size", | |
+ avp_str("size", | |
size >= 0 ? value_string(val_str, sizeof(val_str), | |
size, unit_byte_str) | |
: "unknown"); | |
- print_format_entry("bit_rate", | |
+ avp_str("bit_rate", | |
value_string(val_str, sizeof(val_str), | |
fmt_ctx->bit_rate, unit_bit_per_second_str)); | |
- while ((tag = av_dict_get(fmt_ctx->metadata, "", tag, | |
- AV_DICT_IGNORE_SUFFIX))) { | |
- snprintf(val_str, sizeof(val_str) - 1, "TAG:%s", tag->key); | |
- print_format_entry(val_str, tag->value); | |
- } | |
+ avp_dict(fmt_ctx->metadata, "tags"); | |
- print_format_entry(NULL, "[/FORMAT]"); | |
+ avp_section_footer("format"); | |
} | |
static int open_input_file(AVFormatContext **fmt_ctx_ptr, const char *filename) | |
@@ -363,9 +566,12 @@ static int probe_file(const char *filename) | |
if (do_show_packets) | |
show_packets(fmt_ctx); | |
- if (do_show_streams) | |
+ if (do_show_streams) { | |
+ avp_chapter_header("streams"); | |
for (i = 0; i < fmt_ctx->nb_streams; i++) | |
show_stream(fmt_ctx, i); | |
+ avp_chapter_footer("streams"); | |
+ } | |
if (do_show_format) | |
show_format(fmt_ctx); | |
@@ -394,6 +600,15 @@ static int opt_format(const char *opt, const char *arg) | |
static int opt_show_format_entry(const char *opt, const char *arg) | |
{ | |
do_show_format = 1; | |
+ print_header = NULL; | |
+ print_footer = NULL; | |
+ print_chapter_header = NULL; | |
+ print_chapter_footer = NULL; | |
+ print_section_header = NULL; | |
+ print_section_footer = NULL; | |
+ | |
+ print_integer = show_format_entry_integer; | |
+ print_string = show_format_entry_string; | |
av_dict_set(&fmt_entries_to_show, arg, "", 0); | |
return 0; | |
} | |
@@ -451,9 +666,21 @@ static const OptionDef options[] = { | |
{ NULL, }, | |
}; | |
+static int avp_buf_write(void *opaque, uint8_t *buf, int buf_size) | |
+{ | |
+ printf("%.*s", buf_size, buf); | |
+ return 0; | |
+} | |
+ | |
+#define AVP_BUFFSIZE 4096 | |
+ | |
int main(int argc, char **argv) | |
{ | |
int ret; | |
+ uint8_t *buffer = av_malloc(AVP_BUFFSIZE); | |
+ | |
+ if (!buffer) | |
+ exit(1); | |
parse_loglevel(argc, argv, options); | |
av_register_all(); | |
@@ -475,7 +702,16 @@ int main(int argc, char **argv) | |
exit(1); | |
} | |
+ avp_out = avio_alloc_context(buffer, AVP_BUFFSIZE, 1, NULL, NULL, | |
+ avp_buf_write, NULL); | |
+ if (!avp_out) | |
+ exit(1); | |
+ | |
+ avp_header(); | |
ret = probe_file(input_filename); | |
+ avp_footer(); | |
+ avio_flush(avp_out); | |
+ avio_close(avp_out); | |
avformat_network_deinit(); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment