ffmpeg-- audio decoder
測試代碼來源于:http://ffmpeg.org/doxygen/trunk/decode_audio_8c-example.html
/* * Copyright (c) 2001 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /** * @file * audio decoding with libavcodec API example * * @example decode_audio.c */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <libavutil/frame.h> #include <libavutil/mem.h> #include <libavcodec/avcodec.h> #define AUDIO_INBUF_SIZE 20480 #define AUDIO_REFILL_THRESH 4096 static void decode(AVCodecContext *dec_ctx, AVPacket *pkt, AVFrame *frame,FILE *outfile) { int i, ch; int ret, data_size; /* send the packet with the compressed data to the decoder */ ret = avcodec_send_packet(dec_ctx, pkt); if (ret < 0) { fprintf(stderr, "Error submitting the packet to the decoder\n"); exit(1); } /* read all the output frames (in general there may be any number of them */ while (ret >= 0) { ret = avcodec_receive_frame(dec_ctx, frame); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) return; else if (ret < 0) { fprintf(stderr, "Error during decoding\n"); exit(1); } data_size = av_get_bytes_per_sample(dec_ctx->sample_fmt); if (data_size < 0) { /* This should not occur, checking just for paranoia */ fprintf(stderr, "Failed to calculate data size\n"); exit(1); } for (i = 0; i < frame->nb_samples; i++) for (ch = 0; ch < dec_ctx->channels; ch++) fwrite(frame->data[ch] + data_size*i, 1, data_size, outfile); } } int main(int argc, char **argv) { const char *outfilename, *filename; const AVCodec *codec; AVCodecContext *c= NULL; AVCodecParserContext *parser = NULL; int len, ret; FILE *f, *outfile; uint8_t inbuf[AUDIO_INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE]; uint8_t *data; size_t data_size; AVPacket *pkt; AVFrame *decoded_frame = NULL; if (argc <= 2) { fprintf(stderr, "Usage: %s <input file> <output file>\n", argv[0]); exit(0); } filename = argv[1]; outfilename = argv[2]; pkt = av_packet_alloc(); /* find the MPEG audio decoder */ codec = avcodec_find_decoder(AV_CODEC_ID_MP2); if (!codec) { fprintf(stderr, "Codec not found\n"); exit(1); } parser = av_parser_init(codec->id); if (!parser) { fprintf(stderr, "Parser not found\n"); exit(1); } c = avcodec_alloc_context3(codec); if (!c) { fprintf(stderr, "Could not allocate audio codec context\n"); exit(1); } /* open it */ if (avcodec_open2(c, codec, NULL) < 0) { fprintf(stderr, "Could not open codec\n"); exit(1); } f = fopen(filename, "rb"); if (!f) { fprintf(stderr, "Could not open %s\n", filename); exit(1); } outfile = fopen(outfilename, "wb"); if (!outfile) { av_free(c); exit(1); } /* decode until eof */ data = inbuf; data_size = fread(inbuf, 1, AUDIO_INBUF_SIZE, f); while (data_size > 0) { if (!decoded_frame) { if (!(decoded_frame = av_frame_alloc())) { fprintf(stderr, "Could not allocate audio frame\n"); exit(1); } } ret = av_parser_parse2(parser, c, &pkt->data, &pkt->size,data, data_size, AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0); if (ret < 0) { fprintf(stderr, "Error while parsing\n"); exit(1); } data += ret; data_size -= ret; if (pkt->size) decode(c, pkt, decoded_frame, outfile); if (data_size < AUDIO_REFILL_THRESH) { memmove(inbuf, data, data_size); data = inbuf; len = fread(data + data_size, 1,AUDIO_INBUF_SIZE - data_size, f); if (len > 0) data_size += len; } } /* flush the decoder */ pkt->data = NULL; pkt->size = 0; decode(c, pkt, decoded_frame, outfile); fclose(outfile); fclose(f); avcodec_free_context(&c); av_parser_close(parser); av_frame_free(&decoded_frame); av_packet_free(&pkt); return 0; } ????需要在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)
?主要函數(shù)介紹:
AVPacket *av_packet_alloc(void)
分配并初始化AVPacket結(jié)構(gòu)體,AVPacket是存儲壓縮編碼數(shù)據(jù)相關(guān)信息的結(jié)構(gòu)體。free AVPacket的函數(shù)為av_packet_free().
av_packet_alloc只allocate AVPacket本身,并不分配內(nèi)部data buffer. data buffer 使用其他方式allocate,比如av_new_packet.
AVCodec * avcodec_find_decoder(enum AVCodecID ?id)
使用codec ID在已經(jīng)注冊的decoders中查找相應的decoder,如果ffmpeg有注冊了相應的decoder,則返回AVCodec結(jié)構(gòu)體,否則返回NULL.AVCodec是存儲編解碼器信息的結(jié)構(gòu)體.
AVCodecParserContex *av_parser_init(int codec_id)
根據(jù)codec id,在已經(jīng)注冊的parser中查找,是否有相關(guān)codec的parser,如果存在該codec的parser,則分配AVCodecParserContex結(jié)構(gòu)體。parser用于從raw data中parse出packet.AVCodecParserContex存儲parser contex相關(guān)信息的結(jié)構(gòu)體,包含AVCodecParser結(jié)構(gòu)體和frame_offset,next_frame_offset等,AVCodecParser存儲parser相關(guān)信息。
AVCodecContext *avcodec_alloc_context3(const AVCodec *codec)
allocate?AVCodecContext 結(jié)構(gòu)體,對AVCodecContext 設(shè)置一些default值。AVCodecContext 存儲codec contex信息,包含AVCodec結(jié)構(gòu)。
int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options)
使用AVCodec對AVCodecContex進行初始化。
?AVFrame *av_frame_alloc(void)
allocate AVFrame 結(jié)構(gòu)體,并對AVFrame 的Filed設(shè)置default值。AVFrame存儲解碼后的數(shù)據(jù)。av_frame_alloc只allocate AVFrame本身,并不分配內(nèi)部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)
調(diào)用codec的parser的parser_parse函數(shù)從輸入的數(shù)據(jù)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作為輸入數(shù)據(jù)給到decoder解碼。如果decoder有send_packet函數(shù)則調(diào)用該函數(shù),如果沒有,則調(diào)用avcodec_decode_audio4()進行解碼,將解碼出來的AVFrame結(jié)構(gòu)保存在avctx->internal->buffer_frame。
如果返回0表示該函數(shù)成功返回。如果返回負數(shù)AVERROR(EAGAIN),decoder當前狀態(tài)不接收input數(shù)據(jù),用戶必須調(diào)用avcodec_recieve_frame來讀走output數(shù)據(jù),一旦output數(shù)據(jù)被讀走,resent packet后就不會返回這樣的錯誤。
int attribute_align_arg avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame)
如果decoder有recieve_frame函數(shù)則調(diào)用該函數(shù),如果沒有該函數(shù),則check avctx->internal->buffer_frame是否有數(shù)據(jù),如果有則返回avctx->internal->buffer_frame,沒有數(shù)據(jù)這調(diào)用avcodec_decode_audio4()進行解碼,將解碼出來的AVFrame結(jié)構(gòu)保存在avctx->internal->buffer_frame,并返回AVFrame。
對于video,一個avpkt對應一個video frame,但對于某些audio codec,一個avpkt有多個audio frame.如果有多個audio frame,需要在調(diào)用avcodec_send_packet后調(diào)用多次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出現(xiàn)error,否則返回消耗avpkt的byte數(shù)。
對于一個AVPacket包含多個audio frame的情況,第一調(diào)用avcodec_decode_audio4只解碼出第一個frame,返回值小于avpkt->size.再call一次avcodec_decode_audio4解碼出第二個frame.....即使函數(shù)不返回frame,也要將packet送到decoder直至消耗完或返回error.
某些decoder在input 和output有delay,這表示一些packet并不是立即經(jīng)由decoder解碼輸出,而需要decoding結(jié)束時flush,從而獲得所有的解碼數(shù)據(jù)。對于沒有delay的decoder,flush也是安全的。flush是通過調(diào)用該函數(shù),并將avpkt->data=NULL, avpkt->size=0.
?
轉(zhuǎn)載于:https://www.cnblogs.com/fellow1988/p/9131250.html
總結(jié)
以上是生活随笔為你收集整理的ffmpeg-- audio decoder的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: LeetCode 451. Sort C
- 下一篇: BZOJ4653 洛谷1712 UO