測試代碼來源於: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.