热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

利用ffmpeg解析视频文件信息

解析文件的信息主要从AVFormatContextfmt_ctx,*AVCodecContext*codec_ctx,这两个结构体中获取,

解析文件的信息主要从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, ///AV_CODEC_ID_MPEG2VIDEO_XVMC,AV_CODEC_ID_H261,AV_CODEC_ID_H263,AV_CODEC_ID_RV10,AV_CODEC_ID_RV20,AV_CODEC_ID_MJPEG,AV_CODEC_ID_MJPEGB,..../* audio codecs */AV_CODEC_ID_MP2 = 0x15000,AV_CODEC_ID_MP3, ///AV_CODEC_ID_AAC,AV_CODEC_ID_AC3,AV_CODEC_ID_DTS,....
}

可以根据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

MP4文件

这里写图片描述
在VLC中解析结果对比
这里写图片描述


mkv文件

这里写图片描述
在VLC中解析结果对比
这里写图片描述


TS文件

这里写图片描述
在VLC中解析结果对比
这里写图片描述


rmvb文件

这里写图片描述
在VLC中解析结果对比
这里写图片描述


AVI文件

这里写图片描述
在VLC中解析结果对比
这里写图片描述


flv文件

这里写图片描述
在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 \n",argv[0]);return -1;}
// 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 nb_streams; i&#43;&#43;) {AVStream *stream &#61; fmt_ctx->streams[i];AVCodec *dec &#61; avcodec_find_decoder(stream->codecpar->codec_id);AVCodecContext *codec_ctx;if (!dec) {av_log(NULL, AV_LOG_ERROR, "Failed to find decoder for stream #%u\n", i);return AVERROR_DECODER_NOT_FOUND;}codec_ctx &#61; avcodec_alloc_context3(dec);if (!codec_ctx) {av_log(NULL, AV_LOG_ERROR, "Failed to allocate the decoder context for stream #%u\n", i);return AVERROR(ENOMEM);}ret &#61; avcodec_parameters_to_context(codec_ctx, stream->codecpar);if (ret <0) {av_log(NULL, AV_LOG_ERROR, "Failed to copy decoder parameters to input decoder context ""for stream #%u\n", i);return ret;}/* Reencode video & audio and remux subtitles etc. */if (codec_ctx->codec_type &#61;&#61; AVMEDIA_TYPE_VIDEO|| codec_ctx->codec_type &#61;&#61; AVMEDIA_TYPE_AUDIO) {const char *codec_type;const char *codec_name;const char *profile &#61; NULL;const char *pix_fmt &#61; NULL;codec_type &#61; av_get_media_type_string(codec_ctx->codec_type);codec_name &#61; avcodec_get_name(codec_ctx->codec_id);profile &#61; avcodec_profile_name(codec_ctx->codec_id, codec_ctx->profile);pix_fmt &#61; av_get_pix_fmt_name(codec_ctx->pix_fmt);int64_t bitrate &#61; get_bit_rate(codec_ctx);av_log(NULL, AV_LOG_INFO, "#Stream %d\n Type:%s\n Codec Format:%s\n",i,codec_type,codec_name);if(profile)av_log(NULL, AV_LOG_INFO, " Profile:%s\n",profile);if (codec_ctx->codec_type &#61;&#61; AVMEDIA_TYPE_VIDEO){//resolution ratioif (codec_ctx->width) av_log(NULL, AV_LOG_INFO, " Resolution Ratio:%dx%d\n",codec_ctx->width,codec_ctx->height);av_log(NULL, AV_LOG_INFO, " Pix_fmt:%s\n", codec_ctx->pix_fmt &#61;&#61; AV_PIX_FMT_NONE ? "none" :pix_fmt);//bitrateif (bitrate !&#61; 0) {av_log(NULL,AV_LOG_INFO," Bitrate: %"PRId64" kb/s\n", bitrate / 1000);} else if (codec_ctx->rc_max_rate > 0) {av_log(NULL,AV_LOG_INFO," Max Bitrate: %"PRId64" kb/s\n", (int64_t)codec_ctx->rc_max_rate / 1000);}float temp &#61; (float)stream->avg_frame_rate.num/(float)stream->avg_frame_rate.den;av_log(NULL, AV_LOG_INFO, " Frame rate:%.2ffps(%d/%d)\n",temp,stream->avg_frame_rate.num,stream->avg_frame_rate.den);if (codec_ctx->color_range !&#61; AVCOL_RANGE_UNSPECIFIED)av_log(NULL, AV_LOG_INFO, " Color Range:%s\n",av_color_range_name(codec_ctx->color_range));//color spaceif (codec_ctx->colorspace !&#61; AVCOL_SPC_UNSPECIFIED )av_log(NULL, AV_LOG_INFO, "Color Soace:%s\n ",av_get_colorspace_name(codec_ctx->colorspace));/**DAR - display aspect ratio就是视频播放时&#xff0c;我们看到的图像宽高的比例*SAR - storage aspect ratio就是对图像采集时&#xff0c;横向采集与纵向采集构成的点阵&#xff0c;横向点数与纵向点数的比值。*/AVRational display_aspect_ratio;if (codec_ctx->sample_aspect_ratio.num) {av_reduce(&display_aspect_ratio.num, &display_aspect_ratio.den,codec_ctx->width * (int64_t)codec_ctx->sample_aspect_ratio.num,codec_ctx->height * (int64_t)codec_ctx->sample_aspect_ratio.den,1024 * 1024);av_log(NULL, AV_LOG_INFO," SAR: %d:%d\n DAR: %d:%d\n",codec_ctx->sample_aspect_ratio.num, codec_ctx->sample_aspect_ratio.den,display_aspect_ratio.num, display_aspect_ratio.den);}}else if(codec_ctx->codec_type &#61;&#61; AVMEDIA_TYPE_AUDIO){if (bitrate !&#61; 0) {av_log(NULL,AV_LOG_INFO," Bitrate: %"PRId64" kb/s\n", bitrate / 1000);} else if (codec_ctx->rc_max_rate > 0) {av_log(NULL,AV_LOG_INFO," Max Bitrate: %"PRId64" kb/s\n", (int64_t)codec_ctx->rc_max_rate / 1000);}float temp &#61; (float)codec_ctx->sample_aspect_ratio.num/(float)codec_ctx->sample_aspect_ratio.den;av_log(NULL,AV_LOG_INFO," Sample ratio: %"PRId64" Hz,\n",codec_ctx->sample_rate/1000);av_log(NULL,AV_LOG_INFO," Channel(s): %d channels\n Channel Layout %"PRId64" layouts\n",codec_ctx->channels,codec_ctx->channel_layout);if (codec_ctx->sample_fmt !&#61; AV_SAMPLE_FMT_NONE) {av_log(NULL,AV_LOG_INFO," Sample Format :%s\n",av_get_sample_fmt_name(codec_ctx->sample_fmt));}}avcodec_close(codec_ctx);}}avformat_close_input(&fmt_ctx);return 0;}

推荐阅读
author-avatar
邵crnich
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有