http://it6655.com/2012/09/ffmpeg-8-decoderencoder-html
1概述
编解码模块主要包含的数据结构为:AVCodec、AVCodecContext每一个解码类型都会有自己的Codec静态对像,Codec的int priv_data_size记录该解码器上下文的结构大小,如MsrleContext。这些都是编译时确定的,程序运行时通过avcodec_register_all()将所有的解码器注册成一个链表。在av_open_input_stream()函数中调用AVInputFormat的read_header()中读文件头信息时,会读出数据流的CodecID,即确定了他的解码器Codec。
在main()函数中除了解析传入参数并初始化demuxer与muxer的parse_options( )函数以外,其他的功能都是在av_encode( )函数里完成的。在libavcodec\utils.c中有如下二个函数:AVCodec *avcodec_find_encoder(enum CodecID id)和AVCodec *avcodec_find_decoder(enum CodecID id)他们的功能就是根据传入的CodecID,找到匹配的encoder和decoder。在av_encode( )函数的开头,首先初始化各个AVInputStream和AVOutputStream,然后分别调用上述二个函数,并将匹配上的encoder与decoder分别保存在:
AVInputStream->AVStream *st->AVCodecContext *codec->struct AVCodec *codec
与AVOutputStream->AVStream *st->AVCodecContext *codec->struct AVCodec *codec变量。
2 相关数据结构的初始化
AVCodecContext结构 AVCodecContext保存AVCodec指针和与codec相关数据,如video的width、height,audio的sample rate等。 AVCodecContext中的codec_type,codec_id二个变量对于encoder/decoder的匹配来说,最为重要。
enum CodecType codec_type; /* see CODEC_TYPE_xxx */
enum CodecID codec_id; /* see CODEC_ID_xxx */
如上所示,codec_type保存的是CODEC_TYPE_VIDEO,CODEC_TYPE_AUDIO等媒体类型,codec_id保存的是CODEC_ID_FLV1,CODEC_ID_VP6F等编码方式。 以支持flv格式为例,在前述的av_open_input_file(…… ) 函数中,匹配到正确的AVInputFormat demuxer后,通过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头中的数据来设置的。 以avidec为例有如下初始化,我们主要知道的就是code_id和code_type 该字段关联具体的解码器,和解码类型(音视频或subtitle)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
if (st - >codec - >stream_codec_tag == AV_RL32 ( "Axan" ) )
{
st - >codec - >codec_id = CODEC_ID_XAN_DPCM ;
st - >codec - >codec_tag = 0 ;
}
if (amv_file_format )
{
st - >codec - >codec_id = CODEC_ID_ADPCM_IMA_AMV ; ast - >dshow_block_align = 0 ;
}
break ;
case AVMEDIA_TYPE_SUBTITLE :
st - >codec - >codec_type = AVMEDIA_TYPE_SUBTITLE ;
st - >request_probe = 1 ;
break ;
default :
st - >codec - >codec_type = AVMEDIA_TYPE_DATA ;
st - >codec - >codec_id = CODEC_ID_NONE ;
st - >codec - >codec_tag = 0 ;
avio_skip (pb, size ) ;