FFMPEG使用(转)

1.简介

FFmpeg是一个集录制、转换、音/视频编码解码功能为一体的完整的开源解决方案。FFmpeg的

开发是基于Linux操作系统,但是可以在大多数操作系统中编译和使用。FFmpeg支持MPEG、

DivX、MPEG4、AC3、DV、FLV等40多种编码,AVI、MPEG、OGG、Matroska、ASF等90多种解码.

TCPMP,VLC,MPlayer等开源播放器都用到了FFmpeg。

FFmpeg主目录下主要有libavcodec、libavformat和libavutil等子目录。其中libavcodec用

于存放各个encode/decode模块,libavformat用于存放muxer/demuxer模块,libavutil用于

存放内存操作等辅助性模块。

以flashmovie的flv文件格式为例,muxer/demuxer的flvenc.c和flvdec.c文件在

libavformat目录下,encode/decode的mpegvideo.c和h263de.c在libavcodec目录下。

2.muxer/demuxer与encoder/decoder定义与初始化

muxer/demuxer和encoder/decoder在FFmpeg中的实现代码里,有许多相同的地方,而二者最

大的差别是muxer和demuxer分别是不同的结构AVOutputFormat与AVInputFormat,而encoder

和decoder都是用的AVCodec结构。

muxer/demuxer和encoder/decoder在FFmpeg中相同的地方有:

二者都是在main()开始的av_register_all()函数内初始化的

二者都是以链表的形式保存在全局变量中的

muxer/demuxer是分别保存在全局变量AVOutputFormat*first_oformat与

AVInputFormat*first_iformat中的。

encoder/decoder都是保存在全局变量AVCodec*first_avcodec中的。

二者都用函数指针的方式作为开放的公共接口

demuxer开放的接口有:

int(*read_probe)(AVProbeData*);

int(*read_header)(structAVFormatContext*,AVFormatParameters*ap);

int(*read_packet)(structAVFormatContext*,AVPacket*pkt);

int(*read_close)(structAVFormatContext*);

int(*read_seek)(structAVFormatContext*,intstream_index,int64_ttimestamp,intflags);

muxer开放的接口有:

int(*write_header)(structAVFormatContext*);

int(*write_packet)(structAVFormatContext*,AVPacket*pkt);

int(*write_trailer)(structAVFormatContext*);

encoder/decoder的接口是一样的,只不过二者分别只实现encoder和decoder函数:

int(*init)(AVCodecContext*);

int(*encode)(AVCodecContext*,uint8_t*buf,intbuf_size,void*data);

int(*close)(AVCodecContext*);

int(*decode)(AVCodecContext*,void*outdata,int*outdata_size,uint8_t*buf,intbuf_size);

仍以flv文件为例来说明muxer/demuxer的初始化。

在libavformat\allformats.c文件的av_register_all(void)函数中,通过执行

REGISTER_MUXDEMUX(FLV,flv);

将支持flv格式的flv_muxer与flv_demuxer变量分别注册到全局变量first_oformat与first_iformat链表的最后位置。

其中flv_muxer在libavformat\flvenc.c中定义如下:

AVOutputFormatflv_muxer={

"flv",

"flvformat",

"video/x-flv",

"flv",

sizeof(FLVContext),

#ifdefCONFIG_LIBMP3LAME

CODEC_ID_MP3,

#else//CONFIG_LIBMP3LAME

CODEC_ID_NONE,

CODEC_ID_FLV1,

flv_write_header,

flv_write_packet,

flv_write_trailer,

.codec_tag=(constAVCodecTag*[]){flv_video_codec_ids,flv_audio_codec_ids,0},

}

AVOutputFormat结构的定义如下:

typedefstructAVOutputFormat{

constchar*name;

constchar*long_name;

constchar*mime_type;

constchar*extensions;/**<commaseparatedfilenameextensions*/

/**sizeofprivatedatasothatitcanbeallocatedinthewrapper*/

intpriv_data_size;

/*outputsupport*/

enumCodecIDaudio_codec;/**<defaultaudiocodec*/

enumCodecIDvideo_codec;/**<defaultvideocodec*/

int(*write_header)(structAVFormatContext*);

int(*write_packet)(structAVFormatContext*,AVPacket*pkt);

int(*write_trailer)(structAVFormatContext*);

/**canuseflags:AVFMT_NOFILE,AVFMT_NEEDNUMBER,AVFMT_GLOBALHEADER*/

intflags;

/**currentlyonlyusedtosetpixelformatifnotYUV420P*/

int(*set_parameters)(structAVFormatContext*,AVFormatParameters*);

int(*interleave_packet)(structAVFormatContext*,AVPacket*out,AVPacket*in,intflush);

/**

*listofsupportedcodec_id-codec_tagpairs,orderedby"betterchoicefirst"

*thearraysareallCODEC_ID_NONEterminated

*/

conststructAVCodecTag**codec_tag;

/*privatefields*/

structAVOutputFormat*next;

}AVOutputFormat;

由AVOutputFormat结构的定义可知,flv_muxer变量初始化的第一、二个成员分别为该muxer

的名称与长名称,第三、第四个成员为所对应MIMIEType和后缀名,第五个成员是所对应的

私有结构的大小,第六、第七个成员为所对应的音频编码和视频编码类型ID,接下来就是三

个重要的接口函数,该muxer的功能也就是通过调用这三个接口实现的。

flv_demuxer在libavformat\flvdec.c中定义如下,与flv_muxer类似,在这儿主要也是设置

了5个接口函数,其中flv_probe接口用途是测试传入的数据段是否是符合当前文件格式,这

个接口在匹配当前demuxer时会用到。

AVInputFormatflv_demuxer={

"flv",

"flvformat",

0,

flv_probe,

flv_read_header,

flv_read_packet,

flv_read_close,

flv_read_seek,

.extensions="flv",

.value=CODEC_ID_FLV1,

};

在上述av_register_all(void)函数中通过执行libavcodec\allcodecs.c文件里的

avcodec_register_all(void)函数来初始化全部的encoder/decoder。

因为不是每种编码方式都支持encode和decode,所以有以下三种注册方式:

#defineREGISTER_ENCODER(X,x)\

if(ENABLE_##X##_ENCODER)register_avcodec(&x##_encoder)

#defineREGISTER_DECODER(X,x)\

if(ENABLE_##X##_DECODER)register_avcodec(&x##_decoder)

#defineREGISTER_ENCDEC(X,x)REGISTER_ENCODER(X,x);REGISTER_DECODER(X,x)

如支持flv的flv_encoder和flv_decoder变量就分别是在libavcodec\mpegvideo.c和

libavcodec\h263de.c中创建的。

3.当前muxer/demuxer的匹配

在FFmpeg的文件转换过程中,首先要做的就是根据传入文件和传出文件的后缀名[FIXME]匹配

合适的demuxer和muxer。匹配上的demuxer和muxer都保存在如下所示,定义在ffmpeg.c里的

全局变量file_iformat和file_oformat中:

staticAVInputFormat*file_iformat;

staticAVOutputFormat*file_oformat;

3.1demuxer匹配

在libavformat\utils.c中的staticAVInputFormat*av_probe_input_format2(

AVProbeData*pd,intis_opened,int*score_max)函数用途是根据传入的probedata数据

,依次调用每个demuxer的read_probe接口,来进行该demuxer是否和传入的文件内容匹配的

判断。其调用顺序如下:

voidparse_options(intargc,char**argv,constOptionDef*options,

void(*parse_arg_function)(constchar*));

staticvoidopt_input_file(constchar*filename)

intav_open_input_file(……)

AVInputFormat*av_probe_input_format(AVProbeData*pd,

intis_opened)

staticAVInputFormat*av_probe_input_format2(……)

opt_input_file函数是在保存在constOptionDefoptions[]数组中,用于

voidparse_options(intargc,char**argv,constOptionDef*options)中解析argv里的

“-i”参数,也就是输入文件名时调用的。

3.2muxer匹配

与demuxer的匹配不同,muxer的匹配是调用guess_format函数,根据main()函数的argv里的

输出文件后缀名来进行的。

voidparse_options(intargc,char**argv,constOptionDef*options,

void(*parse_arg_function)(constchar*));

voidparse_arg_file(constchar*filename)

staticvoidopt_output_file(constchar*filename)

AVOutputFormat*guess_format(constchar*short_name,

constchar*filename,

constchar*mime_type)

3.3当前encoder/decoder的匹配

在main()函数中除了解析传入参数并初始化demuxer与muxer的parse_options()函数以外,

其他的功能都是在av_encode()函数里完成的。

在libavcodec\utils.c中有如下二个函数:

AVCodec*avcodec_find_encoder(enumCodecIDid)

AVCodec*avcodec_find_decoder(enumCodecIDid)

他们的功能就是根据传入的CodecID,找到匹配的encoder和decoder。

在av_encode()函数的开头,首先初始化各个AVInputStream和AVOutputStream,然后分别调

用上述二个函数,并将匹配上的encoder与decoder分别保存在:

AVInputStream->AVStream*st->AVCodecContext*codec->structAVCodec*codec与

AVOutputStream->AVStream*st->AVCodecContext*codec->structAVCodec*codec变量。

4.其他主要数据结构

4.1AVFormatContext

AVFormatContext是FFMpeg格式转换过程中实现输入和输出功能、保存相关数据的主要结构。

每一个输入和输出文件,都在如下定义的指针数组全局变量中有对应的实体。

staticAVFormatContext*output_files[MAX_FILES];

staticAVFormatContext*input_files[MAX_FILES];

对于输入和输出,因为共用的是同一个结构体,所以需要分别对该结构中如下定义的iformat

或oformat成员赋值。

structAVInputFormat*iformat;

structAVOutputFormat*oformat;

对一个AVFormatContext来说,这二个成员不能同时有值,即一个AVFormatContext不能同时

含有demuxer和muxer。在main()函数开头的parse_options()函数中找到了匹配的muxer和

demuxer之后,根据传入的argv参数,初始化每个输入和输出的AVFormatContext结构,

文章出处:http://www.diybl.com/course/6_system/linux/Linuxjs/2008727/134072.html

并保

存在相应的output_files和input_files指针数组中。在av_encode()函数中,output_files

和input_files是作为函数参数传入后,在其他地方就没有用到了。

4.2AVCodecContext

保存AVCodec指针和与codec相关数据,如video的width、height,audio的samplerate等。

AVCodecContext中的codec_type,codec_id二个变量对于encoder/decoder的匹配来说,最为

重要。

enumCodecTypecodec_type;/*seeCODEC_TYPE_xxx*/

enumCodecIDcodec_id;/*seeCODEC_ID_xxx*/

如上所示,codec_type保存的是CODEC_TYPE_VIDEO,CODEC_TYPE_AUDIO等媒体类型,

codec_id保存的是CODEC_ID_FLV1,CODEC_ID_VP6F等编码方式。

以支持flv格式为例,在前述的av_open_input_file(……)函数中,匹配到正确的

AVInputFormatdemuxer后,通过av_open_input_stream()函数中调用AVInputFormat的

read_header接口来执行flvdec.c中的flv_read_header()函数。在flv_read_header()函数

内,根据文件头中的数据,创建相应的视频或音频AVStream,并设置AVStream中

AVCodecContext的正确的codec_type值。codec_id值是在解码过程中flv_read_packet()函

数执行时根据每一个packet头中的数据来设置的。

4.3AVStream

AVStream结构保存与数据流相关的编解码器,数据段等信息。比较重要的有如下二个成员:

AVCodecContext*codec;/**<codeccontext*/

void*priv_data;

其中codec指针保存的就是上节所述的encoder或decoder结构。priv_data指针保存的是和具

体编解码流相关的数据,如下代码所示,在ASF的解码过程中,priv_data保存的就是

ASFStream结构的数据。

AVStream*st;

ASFStream*asf_st;

……

st->priv_data=asf_st;

4.4AVInputStream/AVOutputStream

根据输入和输出流的不同,前述的AVStream结构都是封装在AVInputStream和AVOutputStream

结构中,在av_encode()函数中使用。AVInputStream中还保存的有与时间有关的信息。

AVOutputStream中还保存有与音视频同步等相关的信息。

4.5AVPacket

AVPacket结构定义如下,其是用于保存读取的packet数据。

typedefstructAVPacket{

int64_tpts;///<presentationtimestampintime_baseunits

int64_tdts;///<decompressiontimestampintime_baseunits

uint8_t*data;

intsize;

intstream_index;

intflags;

intduration;///<presentationdurationintime_baseunits(0ifnotavailable)

void(*destruct)(structAVPacket*);

void*priv;

int64_tpos;///<bytepositioninstream,-1ifunknown

}AVPacket;

在av_encode()函数中,调用AVInputFormat的

(*read_packet)(structAVFormatContext*,AVPacket*pkt)接口,读取输入文件的一帧数

据保存在当前输入AVFormatContext的AVPacket成员中。

5.av_encode函数主要流程

av_encode()函数是FFMpeg中最重要的函数,编解码和输出等大部分功能都在此函数完成,

因此有必要详细描述一下这个函数的主要流程。

1).inputstreamsinitializing

2).outputstreamsinitializing

3).encodersanddecodersinitializing

4).setmetadatainformationfrominputfileifrequired.

5).writeoutputfilesheader

6).loopofhandlingeachframe

a.readframefrominputfile:

b.decodeframedata

c.encodenewframedata

d.writenewframetooutputfile

7).writeoutputfilestrailer

.closeeachencoderanddecoder

文章出处:http://www.diybl.com/course/6_system/linux/Linuxjs/2008727/134072_2.html

相关推荐