测试代码来源于:http://ffmpeg.org/doxygen/trunk/decode_audio_8c-example.html
需要在sample code加一行avcodec_register_all()
Makefile如下:
export CC=gcc
FFMPEGPATH=/mnt/hgfs/share/ffmpeg-3.3.3/ffmpeg-3.3.3/output
SOURCE=decode_audio.c
INCLUDE=-I$(FFMPEGPATH)/include
LINK=-L$(FFMPEGPATH)/lib/ -lavcodec -lavformat -lavutil -lswresample
LINK+=-lpthread -lm -ldl
TARGET=adecoder
all:
$(CC) $(SOURCE) $(INCLUDE) $(LINK) -o $(TARGET)
主要函数介绍:
AVPacket *av_packet_alloc(void)
分配并初始化AVPacket结构体,AVPacket是存储压缩编码数据相关信息的结构体。free AVPacket的函数为av_packet_free().
av_packet_alloc只allocate AVPacket本身,并不分配内部data buffer. data buffer 使用其他方式allocate,比如av_new_packet.
AVCodec * avcodec_find_decoder(enum AVCodecID id)
使用codec ID在已经注册的decoders中查找相应的decoder,如果ffmpeg有注册了相应的decoder,则返回AVCodec结构体,否则返回NULL.AVCodec是存储编解码器信息的结构体.
AVCodecParserContex *av_parser_init(int codec_id)
根据codec id,在已经注册的parser中查找,是否有相关codec的parser,如果存在该codec的parser,则分配AVCodecParserContex结构体。parser用于从raw data中parse出packet.AVCodecParserContex存储parser contex相关信息的结构体,包含AVCodecParser结构体和frame_offset,next_frame_offset等,AVCodecParser存储parser相关信息。
AVCodecContext *avcodec_alloc_context3(const AVCodec *codec)
allocate AVCodecContext 结构体,对AVCodecContext 设置一些default值。AVCodecContext 存储codec contex信息,包含AVCodec结构。
int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options)
使用AVCodec对AVCodecContex进行初始化。
AVFrame *av_frame_alloc(void)
allocate AVFrame 结构体,并对AVFrame 的Filed设置default值。AVFrame存储解码后的数据。av_frame_alloc只allocate AVFrame本身,并不分配内部data buffer. data buffer 使用其他方式allocate,比如av_frame_get_buffer().
int av_parser_parse2(AVCodecParserContext *s, AVCodecContext *avctx, uint8_t **poutbuf, int *poutbuf_size,const uint8_t *buf, int buf_size, int64_t pts, int64_t dts, int64_t pos)
调用codec的parser的parser_parse函数从输入的数据buf中 parse一个packet出来。packet的data放到poutbuf, size为poutbuf_size.
int attribute_align_arg avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt)
将parser parse出的raw packet作为输入数据给到decoder解码。如果decoder有send_packet函数则调用该函数,如果没有,则调用avcodec_decode_audio4()进行解码,将解码出来的AVFrame结构保存在avctx->internal->buffer_frame。
如果返回0表示该函数成功返回。如果返回负数AVERROR(EAGAIN),decoder当前状态不接收input数据,用户必须调用avcodec_recieve_frame来读走output数据,一旦output数据被读走,resent packet后就不会返回这样的错误。
int attribute_align_arg avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame)
如果decoder有recieve_frame函数则调用该函数,如果没有该函数,则check avctx->internal->buffer_frame是否有数据,如果有则返回avctx->internal->buffer_frame,没有数据这调用avcodec_decode_audio4()进行解码,将解码出来的AVFrame结构保存在avctx->internal->buffer_frame,并返回AVFrame。
对于video,一个avpkt对应一个video frame,但对于某些audio codec,一个avpkt有多个audio frame.如果有多个audio frame,需要在调用avcodec_send_packet后调用多次avcodec_recieve_frame直到packet完全被消耗,才能send new packet.
int attribute_align_arg avcodec_decode_audio4(AVCodecContext *avctx,AVFrame *frame,int *got_frame_ptr,const AVPacket *avpkt)
从输入的avpcket解码出audio frame.返回值为负值表示decoder出现error,否则返回消耗avpkt的byte数。
对于一个AVPacket包含多个audio frame的情况,第一调用avcodec_decode_audio4只解码出第一个frame,返回值小于avpkt->size.再call一次avcodec_decode_audio4解码出第二个frame.....即使函数不返回frame,也要将packet送到decoder直至消耗完或返回error.
某些decoder在input 和output有delay,这表示一些packet并不是立即经由decoder解码输出,而需要decoding结束时flush,从而获得所有的解码数据。对于没有delay的decoder,flush也是安全的。flush是通过调用该函数,并将avpkt->data=NULL, avpkt->size=0.