avprobe.c 14.8 KB
Newer Older
Stefano Sabatini's avatar
Stefano Sabatini committed
1
/*
Anton Khirnov's avatar
Anton Khirnov committed
2
 * avprobe : Simple Media Prober based on the Libav libraries
Stefano Sabatini's avatar
Stefano Sabatini committed
3 4
 * Copyright (c) 2007-2010 Stefano Sabatini
 *
5
 * This file is part of Libav.
Stefano Sabatini's avatar
Stefano Sabatini committed
6
 *
7
 * Libav is free software; you can redistribute it and/or
Stefano Sabatini's avatar
Stefano Sabatini committed
8 9 10 11
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
12
 * Libav is distributed in the hope that it will be useful,
Stefano Sabatini's avatar
Stefano Sabatini committed
13 14 15 16 17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with Libav; if not, write to the Free Software
Stefano Sabatini's avatar
Stefano Sabatini committed
19 20 21
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

22 23
#include "config.h"

Stefano Sabatini's avatar
Stefano Sabatini committed
24 25
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
26
#include "libavutil/opt.h"
Stefano Sabatini's avatar
Stefano Sabatini committed
27
#include "libavutil/pixdesc.h"
28
#include "libavutil/dict.h"
29
#include "libavdevice/avdevice.h"
Stefano Sabatini's avatar
Stefano Sabatini committed
30 31
#include "cmdutils.h"

Anton Khirnov's avatar
Anton Khirnov committed
32
const char program_name[] = "avprobe";
Stefano Sabatini's avatar
Stefano Sabatini committed
33 34 35
const int program_birth_year = 2007;

static int do_show_format  = 0;
36
static int do_show_packets = 0;
Stefano Sabatini's avatar
Stefano Sabatini committed
37 38 39 40 41 42 43 44 45 46
static int do_show_streams = 0;

static int show_value_unit              = 0;
static int use_value_prefix             = 0;
static int use_byte_value_binary_prefix = 0;
static int use_value_sexagesimal_format = 0;

/* globals */
static const OptionDef options[];

Anton Khirnov's avatar
Anton Khirnov committed
47
/* AVprobe context */
Stefano Sabatini's avatar
Stefano Sabatini committed
48
static const char *input_filename;
49
static AVInputFormat *iformat = NULL;
Stefano Sabatini's avatar
Stefano Sabatini committed
50 51 52 53 54 55 56 57 58

static const char *binary_unit_prefixes [] = { "", "Ki", "Mi", "Gi", "Ti", "Pi" };
static const char *decimal_unit_prefixes[] = { "", "K" , "M" , "G" , "T" , "P"  };

static const char *unit_second_str          = "s"    ;
static const char *unit_hertz_str           = "Hz"   ;
static const char *unit_byte_str            = "byte" ;
static const char *unit_bit_per_second_str  = "bit/s";

59 60 61 62 63
void exit_program(int ret)
{
    exit(ret);
}

Stefano Sabatini's avatar
Stefano Sabatini committed
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
static char *value_string(char *buf, int buf_size, double val, const char *unit)
{
    if (unit == unit_second_str && use_value_sexagesimal_format) {
        double secs;
        int hours, mins;
        secs  = val;
        mins  = (int)secs / 60;
        secs  = secs - mins * 60;
        hours = mins / 60;
        mins %= 60;
        snprintf(buf, buf_size, "%d:%02d:%09.6f", hours, mins, secs);
    } else if (use_value_prefix) {
        const char *prefix_string;
        int index;

        if (unit == unit_byte_str && use_byte_value_binary_prefix) {
80
            index = (int) (log(val)/log(2)) / 10;
Stefano Sabatini's avatar
Stefano Sabatini committed
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
            index = av_clip(index, 0, FF_ARRAY_ELEMS(binary_unit_prefixes) -1);
            val /= pow(2, index*10);
            prefix_string = binary_unit_prefixes[index];
        } else {
            index = (int) (log10(val)) / 3;
            index = av_clip(index, 0, FF_ARRAY_ELEMS(decimal_unit_prefixes) -1);
            val /= pow(10, index*3);
            prefix_string = decimal_unit_prefixes[index];
        }

        snprintf(buf, buf_size, "%.3f %s%s", val, prefix_string, show_value_unit ? unit : "");
    } else {
        snprintf(buf, buf_size, "%f %s", val, show_value_unit ? unit : "");
    }

    return buf;
}

static char *time_value_string(char *buf, int buf_size, int64_t val, const AVRational *time_base)
{
    if (val == AV_NOPTS_VALUE) {
        snprintf(buf, buf_size, "N/A");
    } else {
        value_string(buf, buf_size, val * av_q2d(*time_base), unit_second_str);
    }

    return buf;
}

110 111 112 113 114 115 116 117 118 119 120
static char *ts_value_string (char *buf, int buf_size, int64_t ts)
{
    if (ts == AV_NOPTS_VALUE) {
        snprintf(buf, buf_size, "N/A");
    } else {
        snprintf(buf, buf_size, "%"PRId64, ts);
    }

    return buf;
}

121
static const char *media_type_string(enum AVMediaType media_type)
Stefano Sabatini's avatar
Stefano Sabatini committed
122
{
123 124 125 126 127 128
    switch (media_type) {
    case AVMEDIA_TYPE_VIDEO:      return "video";
    case AVMEDIA_TYPE_AUDIO:      return "audio";
    case AVMEDIA_TYPE_DATA:       return "data";
    case AVMEDIA_TYPE_SUBTITLE:   return "subtitle";
    case AVMEDIA_TYPE_ATTACHMENT: return "attachment";
Stefano Sabatini's avatar
Stefano Sabatini committed
129 130 131 132
    default:                      return "unknown";
    }
}

133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
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");
}

static void show_packets(AVFormatContext *fmt_ctx)
{
    AVPacket pkt;

    av_init_packet(&pkt);

    while (!av_read_frame(fmt_ctx, &pkt))
        show_packet(fmt_ctx, &pkt);
}

Stefano Sabatini's avatar
Stefano Sabatini committed
163 164 165 166 167 168
static void show_stream(AVFormatContext *fmt_ctx, int stream_idx)
{
    AVStream *stream = fmt_ctx->streams[stream_idx];
    AVCodecContext *dec_ctx;
    AVCodec *dec;
    char val_str[128];
169
    AVDictionaryEntry *tag = NULL;
170
    AVRational display_aspect_ratio;
Stefano Sabatini's avatar
Stefano Sabatini committed
171 172 173 174 175 176 177 178 179 180 181 182 183

    printf("[STREAM]\n");

    printf("index=%d\n",        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);
        } else {
            printf("codec_name=unknown\n");
        }

184
        printf("codec_type=%s\n",         media_type_string(dec_ctx->codec_type));
Stefano Sabatini's avatar
Stefano Sabatini committed
185 186 187
        printf("codec_time_base=%d/%d\n", dec_ctx->time_base.num, dec_ctx->time_base.den);

        /* print AVI/FourCC tag */
188 189 190
        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);
Stefano Sabatini's avatar
Stefano Sabatini committed
191 192

        switch (dec_ctx->codec_type) {
193
        case AVMEDIA_TYPE_VIDEO:
Stefano Sabatini's avatar
Stefano Sabatini committed
194 195 196
            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);
197
            if (dec_ctx->sample_aspect_ratio.num) {
198 199 200 201 202 203 204 205
                printf("sample_aspect_ratio=%d:%d\n", dec_ctx->sample_aspect_ratio.num,
                                                      dec_ctx->sample_aspect_ratio.den);
                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);
206
            }
Stefano Sabatini's avatar
Stefano Sabatini committed
207 208
            printf("pix_fmt=%s\n",                 dec_ctx->pix_fmt != PIX_FMT_NONE ?
                   av_pix_fmt_descriptors[dec_ctx->pix_fmt].name : "unknown");
209
            printf("level=%d\n",                   dec_ctx->level);
Stefano Sabatini's avatar
Stefano Sabatini committed
210 211
            break;

212
        case AVMEDIA_TYPE_AUDIO:
Stefano Sabatini's avatar
Stefano Sabatini committed
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
            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));
            break;
        }
    } else {
        printf("codec_type=unknown\n");
    }

    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), stream->start_time,
                                                  &stream->time_base));
    printf("duration=%s\n",     time_value_string(val_str, sizeof(val_str), stream->duration,
                                                  &stream->time_base));
233 234
    if (stream->nb_frames)
        printf("nb_frames=%"PRId64"\n",    stream->nb_frames);
Stefano Sabatini's avatar
Stefano Sabatini committed
235

236
    while ((tag = av_dict_get(stream->metadata, "", tag, AV_DICT_IGNORE_SUFFIX)))
237
        printf("TAG:%s=%s\n", tag->key, tag->value);
Stefano Sabatini's avatar
Stefano Sabatini committed
238 239 240 241 242 243

    printf("[/STREAM]\n");
}

static void show_format(AVFormatContext *fmt_ctx)
{
244
    AVDictionaryEntry *tag = NULL;
Stefano Sabatini's avatar
Stefano Sabatini committed
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
    char val_str[128];

    printf("[FORMAT]\n");

    printf("filename=%s\n",         fmt_ctx->filename);
    printf("nb_streams=%d\n",       fmt_ctx->nb_streams);
    printf("format_name=%s\n",      fmt_ctx->iformat->name);
    printf("format_long_name=%s\n", fmt_ctx->iformat->long_name);
    printf("start_time=%s\n",       time_value_string(val_str, sizeof(val_str), fmt_ctx->start_time,
                                                      &AV_TIME_BASE_Q));
    printf("duration=%s\n",         time_value_string(val_str, sizeof(val_str), fmt_ctx->duration,
                                                      &AV_TIME_BASE_Q));
    printf("size=%s\n",             value_string(val_str, sizeof(val_str), fmt_ctx->file_size,
                                                 unit_byte_str));
    printf("bit_rate=%s\n",         value_string(val_str, sizeof(val_str), fmt_ctx->bit_rate,
                                                 unit_bit_per_second_str));

262
    while ((tag = av_dict_get(fmt_ctx->metadata, "", tag, AV_DICT_IGNORE_SUFFIX)))
Stefano Sabatini's avatar
Stefano Sabatini committed
263 264 265 266 267 268 269 270
        printf("TAG:%s=%s\n", tag->key, tag->value);

    printf("[/FORMAT]\n");
}

static int open_input_file(AVFormatContext **fmt_ctx_ptr, const char *filename)
{
    int err, i;
271 272
    AVFormatContext *fmt_ctx = NULL;
    AVDictionaryEntry *t;
Stefano Sabatini's avatar
Stefano Sabatini committed
273

274
    if ((err = avformat_open_input(&fmt_ctx, filename, iformat, &format_opts)) < 0) {
Stefano Sabatini's avatar
Stefano Sabatini committed
275 276 277
        print_error(filename, err);
        return err;
    }
278 279 280 281 282
    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;
    }

Stefano Sabatini's avatar
Stefano Sabatini committed
283 284

    /* fill the streams in the format context */
285
    if ((err = avformat_find_stream_info(fmt_ctx, NULL)) < 0) {
Stefano Sabatini's avatar
Stefano Sabatini committed
286 287 288 289
        print_error(filename, err);
        return err;
    }

290
    av_dump_format(fmt_ctx, 0, filename, 0);
Stefano Sabatini's avatar
Stefano Sabatini committed
291 292 293 294 295 296 297

    /* 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 (!(codec = avcodec_find_decoder(stream->codec->codec_id))) {
298
            fprintf(stderr, "Unsupported codec with id %d for input stream %d\n",
Stefano Sabatini's avatar
Stefano Sabatini committed
299
                    stream->codec->codec_id, stream->index);
300
        } else if (avcodec_open2(stream->codec, codec, NULL) < 0) {
Stefano Sabatini's avatar
Stefano Sabatini committed
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
            fprintf(stderr, "Error while opening codec for input stream %d\n",
                    stream->index);
        }
    }

    *fmt_ctx_ptr = fmt_ctx;
    return 0;
}

static int probe_file(const char *filename)
{
    AVFormatContext *fmt_ctx;
    int ret, i;

    if ((ret = open_input_file(&fmt_ctx, filename)))
        return ret;

318 319 320
    if (do_show_packets)
        show_packets(fmt_ctx);

Stefano Sabatini's avatar
Stefano Sabatini committed
321 322 323 324 325 326 327
    if (do_show_streams)
        for (i = 0; i < fmt_ctx->nb_streams; i++)
            show_stream(fmt_ctx, i);

    if (do_show_format)
        show_format(fmt_ctx);

328
    avformat_close_input(&fmt_ctx);
Stefano Sabatini's avatar
Stefano Sabatini committed
329 330 331 332 333 334
    return 0;
}

static void show_usage(void)
{
    printf("Simple multimedia streams analyzer\n");
Anton Khirnov's avatar
Anton Khirnov committed
335
    printf("usage: %s [OPTIONS] [INPUT_FILE]\n", program_name);
Stefano Sabatini's avatar
Stefano Sabatini committed
336 337 338
    printf("\n");
}

Stefano Sabatini's avatar
Stefano Sabatini committed
339
static int opt_format(const char *opt, const char *arg)
340 341 342 343
{
    iformat = av_find_input_format(arg);
    if (!iformat) {
        fprintf(stderr, "Unknown input format: %s\n", arg);
Stefano Sabatini's avatar
Stefano Sabatini committed
344
        return AVERROR(EINVAL);
345
    }
Stefano Sabatini's avatar
Stefano Sabatini committed
346
    return 0;
347 348
}

349
static void opt_input_file(void *optctx, const char *arg)
Stefano Sabatini's avatar
Stefano Sabatini committed
350
{
351
    if (input_filename) {
352 353
        fprintf(stderr, "Argument '%s' provided as input filename, but '%s' was already specified.\n",
                arg, input_filename);
354 355
        exit(1);
    }
356 357 358
    if (!strcmp(arg, "-"))
        arg = "pipe:";
    input_filename = arg;
Stefano Sabatini's avatar
Stefano Sabatini committed
359 360 361 362
}

static void show_help(void)
{
363
    av_log_set_callback(log_callback_help);
Stefano Sabatini's avatar
Stefano Sabatini committed
364 365 366
    show_usage();
    show_help_options(options, "Main options:\n", 0, 0);
    printf("\n");
367
    show_help_children(avformat_get_class(), AV_OPT_FLAG_DECODING_PARAM);
Stefano Sabatini's avatar
Stefano Sabatini committed
368 369 370 371 372 373 374 375 376 377 378 379
}

static void opt_pretty(void)
{
    show_value_unit              = 1;
    use_value_prefix             = 1;
    use_byte_value_binary_prefix = 1;
    use_value_sexagesimal_format = 1;
}

static const OptionDef options[] = {
#include "cmdutils_common_opts.h"
380
    { "f", HAS_ARG, {(void*)opt_format}, "force format", "format" },
381 382
    { "unit", OPT_BOOL, {(void*)&show_value_unit}, "show unit of the displayed values" },
    { "prefix", OPT_BOOL, {(void*)&use_value_prefix}, "use SI prefixes for the displayed values" },
Stefano Sabatini's avatar
Stefano Sabatini committed
383 384 385 386 387 388 389
    { "byte_binary_prefix", OPT_BOOL, {(void*)&use_byte_value_binary_prefix},
      "use binary prefixes for byte units" },
    { "sexagesimal", OPT_BOOL,  {(void*)&use_value_sexagesimal_format},
      "use sexagesimal format HOURS:MM:SS.MICROSECONDS for time units" },
    { "pretty", 0, {(void*)&opt_pretty},
      "prettify the format of displayed values, make it more human readable" },
    { "show_format",  OPT_BOOL, {(void*)&do_show_format} , "show format/container info" },
390
    { "show_packets", OPT_BOOL, {(void*)&do_show_packets}, "show packets info" },
391
    { "show_streams", OPT_BOOL, {(void*)&do_show_streams}, "show streams info" },
Stefano Sabatini's avatar
Stefano Sabatini committed
392
    { "default", HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, {(void*)opt_default}, "generic catch all option", "" },
Stefano Sabatini's avatar
Stefano Sabatini committed
393 394 395 396 397
    { NULL, },
};

int main(int argc, char **argv)
{
398 399
    int ret;

400
    parse_loglevel(argc, argv, options);
Stefano Sabatini's avatar
Stefano Sabatini committed
401
    av_register_all();
402
    avformat_network_init();
403
    init_opts();
404 405 406
#if CONFIG_AVDEVICE
    avdevice_register_all();
#endif
Stefano Sabatini's avatar
Stefano Sabatini committed
407 408

    show_banner();
409
    parse_options(NULL, argc, argv, options, opt_input_file);
Stefano Sabatini's avatar
Stefano Sabatini committed
410 411 412 413

    if (!input_filename) {
        show_usage();
        fprintf(stderr, "You have to specify one input file.\n");
Anton Khirnov's avatar
Anton Khirnov committed
414
        fprintf(stderr, "Use -h to get full help or, even better, run 'man %s'.\n", program_name);
Stefano Sabatini's avatar
Stefano Sabatini committed
415 416 417
        exit(1);
    }

418 419
    ret = probe_file(input_filename);

420 421
    avformat_network_deinit();

422
    return ret;
Stefano Sabatini's avatar
Stefano Sabatini committed
423
}