解析文件的信息主要从AVFormatContext fmt_ctx,*AVCodecContext *codec_ctx,这两个结构体中获取,fmt_ctx 初始化的函数avformat_open_input(),codec_ctx的初始化函数avcodec_alloc_context3()
下面列举一些代码里用到的结构体成员
typedef struct AVFormatContext {struct AVInputFormat *iformat;//输入数据的封装格式unsigned int nb_streams;//视音频流的个数AVStream **streams;//视音频流char filename[1024];//文件名int64_t duration//时长(单位:微秒us,转换为秒需要除以1000000)int bit_rate//比特率(单位bps,转换为kbps需要除以1000)AVDictionary *metadata//元数据int64_t start_time;//开始的时间......}
typedef struct AVCodecContext {enum AVMediaType codec_type;//编解码器的类型(视频,音频...)struct AVCodec *codec;//采用的解码器AVCodec(H.264,MPEG2...)int bit_rate;//平均比特率uint8_t *extradata;//针对特定编码器包含的附加信息(例如对于H.264解码器来说,存储sps,pps等) AVRational time_base;//根据该参数,可以把PTS转化为实际的时间(单位为秒s)int width, height;//如果是视频的话,代表宽和高int refs;//运动估计参考帧的个数(H.264的话会有多帧,MPEG2这类的一般就没有了)int sample_rate;//采样率(音频)int channels;//声道数(音频)enum AVSampleFormat sample_fmt;//采样格式int profile;//型(H.264里面就有,其他编码标准应该也有)int level;//级(和profile差不太多).......}
关于codec, 在libavcodec/avcode.h中定义了codec的ID
enum AVCodecID {/* video codecs */AV_CODEC_ID_MPEG1VIDEO,AV_CODEC_ID_MPEG2VIDEO, ///
}
可以根据codecID来找出codec的名字,利用const char *avcodec_get_name(enum AVCodecID id)
这个函数。
关于profile,在libavcodec/avcode.h中通过宏定义来定义了音频和视频的不同profile,通过函数const char *avcodec_profile_name(enum AVCodecID codec_id, int profile)可以获取音视频的profile。
#define FF_PROFILE_UNKNOWN -99
#define FF_PROFILE_RESERVED -100
#define FF_PROFILE_AAC_MAIN 0
#define FF_PROFILE_AAC_LOW 1
#define FF_PROFILE_AAC_SSR 2
#define FF_PROFILE_AAC_LTP 3
#define FF_PROFILE_MPEG2_422 0
#define FF_PROFILE_MPEG2_HIGH 1
#define FF_PROFILE_MPEG2_SS 2
#define FF_PROFILE_MPEG2_SNR_SCALABLE 3
#define FF_PROFILE_MPEG2_MAIN 4
#define FF_PROFILE_MPEG2_SIMPLE 5
....
SAR,Sample Aspect Ratio 采样纵横比。即视频横向对应的像素个数比上视频纵向的像素个数。即为我们通常提到的分辨率。
PAR,Pixel Aspect Ratio 像素宽高比。如果把像素想象成一个长方形,PAR即为这个长方形的长与宽的比。当长宽比为1时,这时的像素我们成为方形像素。
DAR,Display Aspect Ratio 显示宽高比。即最终播放出来的画面的宽与高之比。
SAR x PAR = DAR
已知其中任意两个可以推导出另一个。
以下为程序测试结果:
首先我的编译命令为:
export PKG_CONFIG_PATH=~/ffmpeg_build/lib/pkgconfig/:$PKG_CONFIG_PATH
gcc test.c -o test `pkg-config --libs --cflags libavformat`
运行测试:
./test 001.mp4
在VLC中解析结果对比
在VLC中解析结果对比
在VLC中解析结果对比
在VLC中解析结果对比
在VLC中解析结果对比
在VLC中解析结果对比
使用vlc显示的信息比较少,可以使用potplayer。
测试中对于某些输入文件,可能会打印出日志信息,一般情况下FFmpeg类库的源代码中是不允许使用printf()这种的函数的,所有的输出一律使用av_log()。av_log()的声明位于libavutil\log.h,void av_log(void* avcl, int level, const char *fmt, …)
#define AV_LOG_QUIET -8
#define AV_LOG_PANIC 0
#define AV_LOG_FATAL 8
#define AV_LOG_ERROR 16
#define AV_LOG_WARNING 24
#define AV_LOG_INFO 32
#define AV_LOG_VERBOSE 40
#define AV_LOG_DEBUG 48
#define AV_LOG_TRACE 56
从定义中可以看出来,随着严重程度逐渐下降,一共包含如下级别:AV_LOG_PANIC,AV_LOG_FATAL,AV_LOG_ERROR,AV_LOG_WARNING,AV_LOG_INFO,AV_LOG_VERBOSE,AV_LOG_DEBUG。每个级别定义的数值代表了严重程度,数值越小代表越严重。默认的级别是AV_LOG_INFO。此外,还有一个级别不输出任何信息,即AV_LOG_QUIET。
当前系统存在着一个“Log级别”。所有严重程度高于该级别的Log信息都会输出出来。例如当前的Log级别是AV_LOG_WARNING,则会输出AV_LOG_PANIC,AV_LOG_FATAL,AV_LOG_ERROR,AV_LOG_WARNING级别的信息,而不会输出AV_LOG_INFO级别的信息。可以通过av_log_get_level()获得当前Log的级别,通过另一个函数av_log_set_level()设置当前的Log级别。
下面附上代码:
#include "libavformat/avformat.h"
static int64_t get_bit_rate(AVCodecContext *ctx)
{int64_t bit_rate;int bits_per_sample;switch (ctx->codec_type) {case AVMEDIA_TYPE_VIDEO:case AVMEDIA_TYPE_DATA:case AVMEDIA_TYPE_SUBTITLE:case AVMEDIA_TYPE_ATTACHMENT:bit_rate = ctx->bit_rate;break;case AVMEDIA_TYPE_AUDIO:bits_per_sample = av_get_bits_per_sample(ctx->codec_id);bit_rate = bits_per_sample ? ctx->sample_rate * (int64_t)ctx->channels * bits_per_sample : ctx->bit_rate;break;default:bit_rate = 0;break;}return bit_rate;
}
int main(int argc,const char **argv)
{if(argc <2){av_log(NULL, AV_LOG_ERROR, "Invalid Input,Usage: %s
// av_log_set_level(AV_LOG_DEBUG);int ret;unsigned int i;AVFormatContext *fmt_ctx &#61; NULL;av_log(NULL, AV_LOG_INFO, "Input File Name:%s\n",argv[1]);av_register_all();if ((ret &#61; avformat_open_input(&fmt_ctx, argv[1], NULL, NULL)) <0) {av_log(NULL, AV_LOG_ERROR, "Cannot open input file!\n");return ret;}if(fmt_ctx->iformat->name)av_log(NULL, AV_LOG_INFO, " Input Format:%s \n", fmt_ctx->iformat->name);if ((ret &#61; avformat_find_stream_info(fmt_ctx, NULL)) <0) {av_log(NULL, AV_LOG_ERROR, "Cannot find stream information!\n");return ret;}if (fmt_ctx->duration !&#61; AV_NOPTS_VALUE) {int hours, mins, secs, us;int64_t duration &#61; fmt_ctx->duration &#43; (fmt_ctx->duration <&#61; INT64_MAX - 5000 ? 5000 : 0);secs &#61; duration / AV_TIME_BASE;us &#61; duration % AV_TIME_BASE;mins &#61; secs / 60;secs %&#61; 60;hours &#61; mins / 60;mins %&#61; 60;av_log(NULL, AV_LOG_INFO, " Duration: %02d:%02d:%02d.%02d", hours, mins, secs,(100 * us) / AV_TIME_BASE);}if (fmt_ctx->start_time !&#61; AV_NOPTS_VALUE) {int secs, us;av_log(NULL, AV_LOG_INFO, ", start: ");secs &#61; llabs(fmt_ctx->start_time / AV_TIME_BASE);us &#61; llabs(fmt_ctx->start_time % AV_TIME_BASE);av_log(NULL, AV_LOG_INFO, "%s%d.%06d",fmt_ctx->start_time >&#61; 0 ? "" : "-",secs,(int) av_rescale(us, 1000000, AV_TIME_BASE));}av_log(NULL, AV_LOG_INFO, ", bitrate: ");if (fmt_ctx->bit_rate)av_log(NULL, AV_LOG_INFO, "%"PRId64" kb/s", (int64_t)fmt_ctx->bit_rate / 1000);elseav_log(NULL, AV_LOG_INFO, "N/A");av_log(NULL, AV_LOG_INFO, "\n");for (i &#61; 0; i