一、FFMPeg一般流程:
1、av_register_all();//注册所有文件格式和编解码库
2、avformat_network_init();//打开网络视频流
3、av_open_input_file();//读取文件头部把信息保存到AVFormatContext结构体
4、av_find_stream_info();//为pFormatCtx->streams填充上正确的信息
5、CODEC_TYPE_VIDEO;//通过判断得到视频流类型
6、avcodec_find_decoder();//查找解码器
7、avcodec_open();//打开编解码器
8、avcodec_alloc_frame();//分配空间保存帧数据
9、av_read_frame();//不断从流中提取帧数据
10、avcodec_decode_video();//解码视频流
11、avcodec_close();//关闭解码器
12、avformat_close_input_file();//关闭输入文件
二、详解:
1、AVCodecContext:描述编解码器上下文的数据结构,包含编解码器需要的参数信息(位于:avcodec.h)
typedef struct AVCodecContext {
..... } AVCodecContext;
说明:
单纯使用libavcodec,参数信息需要调用者进行初始化;使用整个FFMPEG库,在调用avformat_open_input和avformat_find_stream_info时根据文件头信息及媒体流内头部信息初始化。
2、AVStream:描述一个媒体流(存储视频/音频流信息的结构体,位于:avformat.h) typedef struct AVStream { ...... } AVStream;
主要变量:
int index:标识视频/音频流
AVCodecContext *codec:视频/音频流的AVCodecContext
AVRational time_base:时间基准,真正的时间 =PTS*time_base
int64_t duration:该视频/音频流时间长度
AVDictionary *metadata:元数据信息
AVRational avg_frame_rate:帧率
AVPacket attached_pic:附加图片
3、AVFormatContext:描述媒体文件或媒体流构成和基本信息(包含码流参数较多,位于:avformat.h) typedef struct AVFormatContext { ...... } AVFormatContext;
AVFormatContext是一个很重要的数据结构,很多函数会使用它作为参数;是FFMPEG解封装(flv,mp4,rmvb,avi)功能的结构体。
主要变量:
struct AVInputFormat *iformat:输入数据的封装格式
AVIOContext *pb:输入数据缓存
unsigned int nb_streams:音视频流个数
AVStream **streams:音视频流
char filename[1024]:文件名
int64_t duration:时长(单位:us)
int bit_rate:比特率
AVDictionary *metadata:元数据
4、AVPacket:存储压缩编码数据相关信息的结构体(位于:avformat.h)
typedef struct AVPacket { ...... } AVPacket;
主要变量:
uint8_t *data:压缩编码数据,一个AVPacket的data通常对应一个NAL。
int size:data的大小
int64_t pts:显示时间戳
int64_t dts:解码时间戳
int stream_index:标识该AVPacket所属的视频/音频流。
三、API 1、int avformat_open_input(AVFormatContext **ic_ptr,const char *filename,AVInputFormat *fmt,AVDictionary **options); 作用:打开文件或URL,并使基于字节流的底层输入模块得到初始化;解析多媒体文件或多媒体流的头信息,创建AVFormatContext结构并填充其中的关键字段,依次为各个原始流建立AVStream结构。 参数: ic_ptr:用于返回avformat_open_input内部构造的一个AVFormatContext结构体。 filename:指定文件名。 fmt:用于显式指定输入文件的格式,如果设为空则自动判断其输入格式。 options:传入的附加参数。
说明:这个函数通过解析多媒体文件或流的头信息及其他辅助数据,能够获取足够多的关于文件、流和编解码器的信息,但任何一种多媒体格式提供的信息都是有限的,而且不同的多媒体软件制作对头信息的设置各有不同,另外这些软件在产生多媒体内容时难免引入错误,这种情况下并不能保证获取到所有需要的信息,这是就要考虑另一个函数:avformat_find_stream_info。
2、int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options);
作用:用于获取必要的编解码器参数。需要得到各媒体流对应编解码器的类型和id,这是两个定义在avutils.h和avcodec.h中的枚举: enum AVMediaType { AVMEDIA_TYPE_UNKNOWN = -1, AVMEDIA_TYPE_VIDEO, AVMEDIA_TYPE_AUDIO, AVMEDIA_TYPE_DATA, AVMEDIA_TYPE_SUBTITLE, AVMEDIA_TYPE_ATTACHMENT, AVMEDIA_TYPE_NB };
enum CodecID { CODEC_ID_NONE, CODEC_ID_MPEG1VIDEO, CODEC_ID_MPEG2VIDEO, CODEC_ID_MPEG2VIDEO_XVMC, CODEC_ID_H261, CODEC_ID_H263,
CODEC_ID_H264, ...
};
若媒体格式的数据流具有完整头信息,可以通过avformat_open_input得到编解码器的类型和id;否则,需要通过avformat_find_stream_info函数获取。此外,对于音频编解码器,时间基准、采样率、声道数、位宽、帧长度与视频编解码器图像大小、色彩空间等也需要从avformat_find_stream_info函数得到。 3、int av_read_frame(AVFormatContext *s, AVPacket *pkt);
作用:用于从多媒体文件或多媒体流中读取媒体数据,数据由AVPacket结构pkt来存放。对于音频数据,若是固定比特率,则pkt中装载一个或多个音频帧;若为可变比特率,则pkt中装载一个音频帧。对于视频数据,pkt中装载有一个视频帧。注:当再次调用本函数之前,需使用av_free_packet释放pkt所占用的资源。
4、int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags);
作用:通过改变媒体文件的读写指针来实现对媒体文件的随机访问,大多源于媒体播放器的快进、快退等功能。
参数: s:AVFormatContext指针,avformat_open_input返回得到。 stream_index:指定媒体流。 timestamp:时间标签。。 flags:定位方式。
5、void av_close_input_file(AVFormatContext *s); 作用:关闭媒体文件,释放资源,关闭物理IO。
6、AVCodec *avcodec_find_decoder(enum CodecID id); AVCodec *avcodec_find_decoder_by_name(const char *name); 作用:根据指定解码器ID或者解码器名称查找相应的解码器并返回AVCodec *。
7、int avcodec_open(AVCodecContext *avctx, AVCodec *codec); 作用:根据输入的AVCodec指针具体化AVCodecContext结构。在调用该函数之前,首先调用avcodec_alloc_context分配一个AVCodecContext结构,或调用avformat_open_input获取媒体文件中对应媒体流的AVCodecContext结构;此外,通过avcodec_find_decoder获取AVCodec结构。
8、int avcodec_decode_video2(AVCodecContext *avctx,AVFrame *picture,int *got_picture_ptr,AVPacket *avpkt);
作用:解码视频帧。
参数:
avctx:解码器上下文。
picture:输出数据。
got_picture_ptr:指示是否有解码数据输出。
avpkt:输入数据。
9、int avcodec_decode_audio4(AVCodecContext *avctx, AVFrame *frame, int *got_frame_ptr, AVPacket *avpkt);
作用:解码音频帧。输入数据在AVPacket结构中,输出数据在frame中,got_frame_ptr表示是否有数据输出。
参数:
avctx:解码器上下文。
frame:输出数据。
got_frame_ptr:指示是否有解码数据输出。
avpkt:输入数据。
10、int avcodec_close(AVCodecContext *avctx); 作用:关闭解码器,释放avcodec_open中分配的资源。
三、大体代码流程
[cpp] view plain copy
- int main(int argc, char **argv)
- {
- AVFormatContext* pCtx = NULL;
- AVCodecContext *pCodecCtx = NULL;
- AVCodec *pCodec = NULL;
- AVPacket packet;
- AVFrame *pFrame = NULL;
- FILE *fpo1 = NULL;
- FILE *fpo2 = NULL;
- int nframe;
- int err;
- int got_picture;
- int picwidth, picheight, linesize;
- unsigned char *pBuf;
- int i;
- int64_t timestamp;
- struct options opt;
- int usefo = 0;
- struct audio_dsp dsp;
- int dusecs;
- float usecs1 = 0;
- float usecs2 = 0;
- struct timeval elapsed1, elapsed2;
- int decoded = 0;
- av_register_all();
- av_log_set_callback(log_callback);
- av_log_set_level(50);
- err = avformat_open_input(&pCtx, opt.finput, 0, 0);
- if (err codec->extradata_size; i++){
- if (i%16 == 0) printf("\n");
- printf("%2x ", pCtx->streams[opt.streamId]->codec->extradata[i]);
- }
- }
- / *Try to open output file*/
- if (strlen(opt.foutput1) && strlen(opt.foutput2))
- {
- fpo1 = fopen(opt.foutput1, "wb");
- fpo2 = fopen(opt.foutput2, "wb");
- if (!fpo1 || !fpo2){
- printf("\n->error Open output file.\n");
- goto fail;
- }
- usefo = 1;
- }else{
- usefo = 0;
- }
- if (opt.streamId >= pCtx->nb_streams){
- printf("\n->StreamId\tERROR\n");
- goto fail;
- }
- if (opt.lstart > 0){
- err = av_seek_frame(pCtx, opt.streamId, opt.lstart, AVSEEK_FLAG_ANY);
- if (err streams[opt.streamId]->codec;
- if (opt.thread_count 0 ){
- pCodecCtx->thread_count = opt.thread_count;
- pCodecCtx->thread_type = FF_THREAD_FRAME;
- }
- pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
- if (!pCodec){
- printf("\n->Can't find decoder!\n");
- goto fail;
- }
- err = avcodec_open2(pCodecCtx, pCodec, 0);
- if (err channels;
- dsp.speed = pCodecCtx->sample_rate;
- dsp.format = map_formats(pCodecCtx->sample_fmt);
- if (set_audio(&dsp)
关注打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?