背景
最近从FFmpeg中学习了音频解码相关的知识,刚好做了音频G711A解码的工作,特此记录分享。
功能描述
我的需求是解码一帧帧的音频G711A的数据,所以我是从内存中取一帧完整的G711A音频数据去做解码动作,解码后的PCM数据我再另做处理(存成PCM文件或者重采样再编码)。
源码构成
源码主要的构成,主要是初始化解码器和解码两个接口。
class DecodeAudio
{
public:
DecodeAudio();
~DecodeAudio();
int audioInit(AVCodecID codec_id, AVSampleFormat sample_fmt, int sample_rate, int channels);
AVFrame* decode(char *data, int datalen);
void audioUnit(void);
private:
AVCodec *pCodecAudioDec;
AVCodecContext *pCodecCtxAudio;
AVFrame *pFrameAudio;
AVPacket *pPacketAudio;
};
接口介绍
解码初始化:
int DecodeAudio::audioInit(AVCodecID codec_id, AVSampleFormat sample_fmt, int sample_rate, int channels)
{
pCodecAudioDec = avcodec_find_decoder(codec_id);
if (!pCodecAudioDec) {
printf("Codec not found audio codec id\n");
return -1;
}
pCodecCtxAudio = avcodec_alloc_context3(pCodecAudioDec);
if (!pCodecCtxAudio) {
printf("Could not allocate audio codec context\n");
return -1;
}
pCodecCtxAudio->sample_fmt = sample_fmt;
pCodecCtxAudio->sample_rate = sample_rate;
pCodecCtxAudio->channels = channels;
if (avcodec_open2(pCodecCtxAudio, pCodecAudioDec, NULL) < 0) {
printf("Could not open codec\n");
return -1;
}
pPacketAudio = av_packet_alloc();
if (NULL == pPacketAudio)
return -1;
pFrameAudio = av_frame_alloc();
if (NULL == pFrameAudio)
return -1;
return 0;
}
注意:解码G711A的话AVCodecID 是 AV_CODEC_ID_PCM_ALAW !
解码初始化的流程很简单,主要是:查找解码器、创建解码上下文、打开解码器等。
解码上下文需要设置的参数:
sample_fmt:采样格式
sample_rate:采样频率
channels:采样通道数
解码:
解码接口输入是一帧完整的音频编码数据:
AVFrame* DecodeAudio::decode(char *data, int datalen)
{
int ret = 0;
pPacketAudio->size = datalen;
pPacketAudio->data = (uint8_t *)av_malloc(pPacketAudio->size);
memcpy(pPacketAudio->data, data, datalen);
ret = av_packet_from_data(pPacketAudio, pPacketAudio->data, pPacketAudio->size);
if (ret <0)
{
printf("av_packet_from_data error \n");
av_free(pPacketAudio->data);
return NULL;
}
ret = avcodec_send_packet(pCodecCtxAudio, pPacketAudio);
av_packet_unref(pPacketAudio);
if (ret < 0) {
printf("avcodec_send_packet error \n");
return NULL;
}
ret = avcodec_receive_frame(pCodecCtxAudio, pFrameAudio);
if (ret < 0) {
printf("avcodec_receive_frame error \n");
return NULL;
}
return pFrameAudio;
}
解码主要内容:
av_packet_from_data:产生要解码的AVPacket数据;
avcodec_send_packet:输入待解码码流;
avcodec_receive_frame:输出解码数据。
解码出来的audioframe->data[0]就是一帧原始的pcm音频数据,可以直接存成文件,数据长度为audioframe->linesize[0]。
接口调用
DecodeAudio *pdecodeaudio = NULL;
pdecodeaudio = new DecodeAudio;
pdecodeaudio->audioInit(AV_CODEC_ID_PCM_ALAW, AV_SAMPLE_FMT_S16, 8000, 1) < 0);
//g711data为一帧的G711A音频数据
AVFrame *audioframe = pdecodeaudio->decode(g711data, g711len);
//解码出来的audioframe->data[0]就是一帧原始的pcm音频数据,可以直接存成文件,数据长度为audioframe->linesize[0]
delete pdecodeaudio;
下载
源码下载:https://download.csdn.net/download/qq_22633333/11584405