只实现解码,不包含前置的demux,以及后置的resample
要求输入demux后的音频数据
实现的C++类如下:
AudioSoftDecoder.h:
#ifndef _AUDIOSOFTDECODER_H_
#define _AUDIOSOFTDECODER_H_
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
extern "C" {
#include "stdint.h"
#include <libavutil/frame.h>
#include <libavutil/mem.h>
#include <libavcodec/avcodec.h>
}
//解码最小包阈值
static const int AUDIO_REFILL_THRESH = 4096;
class AudioSoftDecoder {
public:
AudioSoftDecoder();
virtual ~AudioSoftDecoder();
virtual int init(int channels, int sampleRate, int64_t bitRate, int bitsPerCodedSample);
virtual int decode(uint8_t *inBuf, const int inBufLen, uint8_t *outBuf, int *outBufLen, bool isStreamEnd);
virtual void uninit();
private:
AVCodecContext *mCodexContext;
AVCodec *mCodec;
AVPacket mAvpkt;
AVFrame *mDecodedFrame;
std::vector<uint8_t> mRemainData;
protected:
int mAudioType;
};
#endif /* AUDIOSOFTDECODER_H_ */
AudioSoftDecoder.cpp
#include "AudioSoftDecoder.h"
#include <iostream>
// const int AudioSoftDecoder::AUDIO_OUTBUF_SIZE = 1024*1024*2;
// const int AudioSoftDecoder::AUDIO_INBUF_SIZE = 20480;
// const int AudioSoftDecoder::AUDIO_REFILL_THRESH = 4096;
AudioSoftDecoder::AudioSoftDecoder() : mCodexContext(nullptr),
mCodec(nullptr),
mDecodedFrame(nullptr),
mAudioType(AV_CODEC_ID_AAC){
}
AudioSoftDecoder::~AudioSoftDecoder() {
}
int AudioSoftDecoder::init(int channels, int sampleRate, int64_t bitRate, int bitsPerCodedSample){
/* register all the codecs */
avcodec_register_all();
av_init_packet(&mAvpkt);
/* find the MPEG audio decoder */
mCodec = avcodec_find_decoder((AVCodecID)mAudioType);
if (!mCodec) {
std::cout<<"Codec not found";
return -1;
}
mCodexContext = avcodec_alloc_context3(mCodec);
if (!mCodexContext) {
std::cout<<"Could not allocate audio codec context";
return -2;
}
mCodexContext->channels = channels;
mCodexContext->sample_rate = sampleRate;
mCodexContext->bit_rate = bitRate;
mCodexContext->bits_per_coded_sample = bitsPerCodedSample;
/* open it */
if (avcodec_open2(mCodexContext, mCodec, NULL) < 0) {
std::cout<<"Could not open codec";
return -3;
}
if(!(mDecodedFrame = av_frame_alloc())) {
std::cout<<"Could not allocate audio frame";
}
return 0;
}
void AudioSoftDecoder::uninit() {
avcodec_free_context(&mCodexContext);
av_frame_free(&mDecodedFrame);
mRemainData.clear();
}
int AudioSoftDecoder::decode(uint8_t *inBuf, const int inBufLen, uint8_t *outBuf, int *outBufLen, bool isStreamEnd){
if(!inBuf || !outBuf) {
std::cout<<"parameter error";
return -1;
}
int maxOutLen = *outBufLen;
*outBufLen = 0;
std::cout<<"inbufLen:"<<inBufLen<<std::endl;
uint8_t *allBuffer = nullptr;
//合并上次剩余的未解码数据
if(mRemainData.empty()) {
mAvpkt.data = inBuf;
mAvpkt.size = inBufLen;
} else {
mRemainData.insert(mRemainData.end(), inBuf, inBuf + inBufLen);
mAvpkt.data = &mRemainData[0];
mAvpkt.size = mRemainData.size();
}
while (mAvpkt.size > 0) {
int i, ch;
int gotFrame = 0;
int len = avcodec_decode_audio4(mCodexContext, mDecodedFrame, &gotFrame, &mAvpkt);
if (len < 0) {
std::cout<<"Error while decoding ret:" << len;
return -3;
}
if (gotFrame) {
/* if a frame has been decoded, output it */
int dataSize = av_get_bytes_per_sample(mCodexContext->sample_fmt);
if (dataSize < 0) {
/* This should not occur, checking just for paranoia */
std::cout<<"Failed to calculate data size"<<std::endl;
return -4;
}
for (i=0; i<mDecodedFrame->nb_samples; i++){
for (ch=0; ch<mCodexContext->channels; ch++){
int tmpLen = *outBufLen + dataSize;
if(tmpLen > maxOutLen) {
std::cout<<"decoder error -4 tmpLen:"<<tmpLen<<" maxOutLen:"<<maxOutLen<<std::endl;
return -5;
}
memcpy(outBuf, mDecodedFrame->data[ch] + dataSize*i, dataSize);
outBuf += dataSize;
*outBufLen = tmpLen;
}
}
}
mAvpkt.size -= len;
mAvpkt.data += len;
mAvpkt.dts =
mAvpkt.pts = AV_NOPTS_VALUE;
//如不足一帧,则存储起来,与后面数据一同解码
if (mAvpkt.size < AUDIO_REFILL_THRESH && !isStreamEnd) {
mRemainData.clear();
mRemainData.insert(mRemainData.end(), mAvpkt.data, mAvpkt.data + mAvpkt.size);
return mAvpkt.size;
}
}
if(isStreamEnd) {
std::cout<<"decoder end!"<<std::endl;
}
mRemainData.clear();
return 0;
}
解码AAC音频:
AACDecoder.h
class AACDecoder : public AudioSoftDecoder{
public:
AACDecoder();
~AACDecoder();
private:
};
AACDecoder.cpp
AACDecoder::AACDecoder(){
mAudioType = AV_CODEC_ID_AAC;
}
AACDecoder::~AACDecoder() {
}
解码MP3音频:
MP3Decoder.h
class MP3Decoder : public AudioSoftDecoder{
public:
MP3Decoder();
~MP3Decoder();
private:
};
MP3Decoder.cpp
MP3Decoder::MP3Decoder(){
mAudioType = AV_CODEC_ID_MP3;
}
MP3Decoder::~MP3Decoder(){
}
类使用:
int main(int argc, char **argv)
{
AACDecoder *adecoder = new AACDecoder();
adecoder->init(2, 44100, 128072, 16);
const char *outfilename, *filename;
int len;
FILE *f, *outfile;
uint8_t inbuf[AUDIO_INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
uint8_t outbuf[AUDIO_OUTBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
if (argc <= 2) {
std::cout<<"Usage: %s <input file> <output file>"<<argv[0];
return -1;
}
filename = argv[1];
outfilename = argv[2];
f = fopen(filename, "rb");
if (!f) {
std::cout<<"Could not open %s"<<filename;
return -1;
}
outfile = fopen(outfilename, "wb");
if (!outfile) {
std::cout<<"Could not open "<<outfilename;
return -1;
}
int realLen = fread(inbuf, 1, AUDIO_INBUF_SIZE, f);
bool isStreamEnd = false;
while (realLen > 0) {
int outLen = AUDIO_OUTBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE;
len = adecoder->decode(inbuf, realLen, outbuf, &outLen, realLen < AUDIO_INBUF_SIZE);
if (len < 0) {
std::cout<<"Error while decoding ret:"<<std::hex<<len<<std::endl;
return -1;
}
if (len >= 0 && outLen > 0) {
fwrite(outbuf, 1, outLen, outfile);
std::cout<<" wrote: "<<outLen<<std::endl;
}
realLen = fread(inbuf, 1, AUDIO_INBUF_SIZE, f);
}
adecoder->uninit();
delete adecoder;
fclose(outfile);
fclose(f);
return 0;
}
执行:
./decode_audio_aac ./maibuqifang_audioData.txt ./aac.pcm
播放解码后的aac.pcm:
ffplay -f s16le -ac 2 -ar 44100 aac.pcm