AAC 音频解码类

Posted qianbo_insist

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AAC 音频解码类相关的知识,希望对你有一定的参考价值。

写全各类编码编解码

h264编码

AAC解码

1、声明

#define out_sample_fmt	AV_SAMPLE_FMT_S16
#define out_channels	2

class AACDecode
{
public:
	AACDecode();
	~AACDecode();

	int  DoInit();
	void DoUnInit();
	bool decodeAACAudio(char *buff, unsigned int buffLen, unsigned int &audioLen);
	
	AVCodecContext* GetContext(){
		return _codecCtx;
	}
	uint8_t *getAudioChunk(){
		return dst_data[0];
	}
private:
//	FFMPEGLibrary _ffmpeg;
	int64_t src_ch_layout = AV_CH_LAYOUT_STEREO, dst_ch_layout = AV_CH_LAYOUT_SURROUND;
	int src_rate = 44100, dst_rate = 44100;
	int src_nb_samples = 1024;
	int dst_nb_samples, max_dst_nb_samples;
	int dst_nb_channels = 0;
	uint8_t **dst_data = NULL;
	int dst_linesize;
	//uint8_t *_audioChunk = nullptr;

	AVCodec *_codec;
	AVCodecContext *_codecCtx;
	AVFrame* _outputFrame;
	SwrContext * _swrCtx = NULL;

	int AudioResampling();
};

2、实现

#include "AACDecode.h"


AACDecode::AACDecode()
{
}


AACDecode::~AACDecode()
{
}

int AACDecode::DoInit()
{
	FFMPEGLibraryInstance.Load();
	if (!FFMPEGLibraryInstance.IsLoaded()){
		return -1;
	}

	if ((_codec = FFMPEGLibraryInstance.AvcodecFindDecoder(AV_CODEC_ID_AAC)) == NULL) {
		return false;
	}

	_codecCtx = FFMPEGLibraryInstance.AvcodecAllocContext(_codec);
	if (_codecCtx == NULL) {
		return false;
	}

	if (FFMPEGLibraryInstance.AvcodecOpen(_codecCtx, _codec) < 0) {
		return false;
	}

	_outputFrame = FFMPEGLibraryInstance.AvcodecAllocFrame();
	if (_outputFrame == NULL) {
		return false;
	}

	/*输出声音模式*/
	if (out_channels == 1){
		dst_ch_layout = AV_CH_LAYOUT_MONO;
	}
	else if (out_channels == 2){
		dst_ch_layout = AV_CH_LAYOUT_STEREO;
	}
	else{
		dst_ch_layout = AV_CH_LAYOUT_SURROUND;
	}

	/*音频通道布局*/
	if (src_ch_layout <= 0){
		printf("src_ch_layout error \\n");
		return -1;
	}

	_swrCtx = swr_alloc();
	if (!_swrCtx){
		printf("Could not allocate resampler context\\n");
		return false;
	}

	/* set options */
	av_opt_set_int(_swrCtx, "in_channel_layout", src_ch_layout, 0);
	av_opt_set_int(_swrCtx, "in_sample_rate", src_rate, 0);
	av_opt_set_sample_fmt(_swrCtx, "in_sample_fmt", _codecCtx->sample_fmt, 0);

	av_opt_set_int(_swrCtx, "out_channel_layout", dst_ch_layout, 0);
	av_opt_set_int(_swrCtx, "out_sample_rate", dst_rate, 0);
	av_opt_set_sample_fmt(_swrCtx, "out_sample_fmt", out_sample_fmt, 0);

	/*用以上设置的数据初始化重采样信息*/
	if (swr_init(_swrCtx) < 0) {
		printf("Failed to initialize the resampling context\\n");
		return -1;
	}

	/*计算转换的样品数量:保证输出缓冲区至少能包含所有转换的输入样品*/
	max_dst_nb_samples = dst_nb_samples = av_rescale_rnd(src_nb_samples,
		dst_rate, src_rate, AV_ROUND_UP);
	if (max_dst_nb_samples <= 0){
		printf("av_rescale_rnd error \\n");
		return -1;
	}	

	int ret = 0;
	dst_nb_channels = av_get_channel_layout_nb_channels(dst_ch_layout);
	ret = av_samples_alloc_array_and_samples(&dst_data, &dst_linesize, dst_nb_channels,
		dst_nb_samples, (AVSampleFormat)out_sample_fmt, 0);
	if (ret < 0){
		printf("Could not allocate destination samples\\n");
		return -1;
	}

	return 0;
}


bool AACDecode::decodeAACAudio(char *buff, unsigned int buffLen, unsigned int &audioLen)
{
	AVPacket pkt;
	av_init_packet(&pkt);
	pkt.data = (unsigned char*)buff;
	pkt.size = buffLen;

	int got_picture_audio;
	int ret = avcodec_decode_audio4(_codecCtx, _outputFrame, &got_picture_audio, &pkt);
	av_packet_unref(&pkt);
	if (ret > 0)
	{	
		audioLen = AudioResampling();
		return true;
	}

	return false;
}

#if 1
int AACDecode::AudioResampling()
{
	int ret = 0;
	int resampled_buff_size;

	dst_nb_samples = av_rescale_rnd(swr_get_delay(_swrCtx, src_rate) +
		src_nb_samples, dst_rate, src_rate, AV_ROUND_UP);
	if (dst_nb_samples <= 0){
		printf("av_rescale_rnd error \\n");
		return -1;
	}
	if (dst_nb_samples > max_dst_nb_samples)
	{
		av_free(dst_data[0]);
		ret = av_samples_alloc(dst_data, &dst_linesize, dst_nb_channels,
			dst_nb_samples, (AVSampleFormat)out_sample_fmt, 1);
		max_dst_nb_samples = dst_nb_samples;
	}

	if (_swrCtx)
	{
		ret = swr_convert(_swrCtx, dst_data, dst_nb_samples,
			(const uint8_t **)_outputFrame->data, _outputFrame->nb_samples);
		if (ret < 0)
		{
			printf("swr_convert error \\n");
			return -1;
		}

		/* 计算解码出来的桢需要的缓冲大小 */
		resampled_buff_size = av_samples_get_buffer_size(&dst_linesize, dst_nb_channels,
			ret, (AVSampleFormat)out_sample_fmt, 1);
		if (resampled_buff_size < 0)
		{
			printf("Could not get sample buffer size \\n");
			return -1;
		}
	}
	else
	{
		printf("swr_ctx null error \\n");
		return -1;
	}

	return resampled_buff_size;
}
#endif


void AACDecode::DoUnInit()
{
	if (dst_data)
	{
		av_freep(&dst_data[0]);
	}
	av_freep(&dst_data);
	dst_data = NULL;
	//if (_audioChunk){
	//	_audioChunk = nullptr;
	//}
	//

	if (_swrCtx){
		swr_free(&_swrCtx);
	}

	av_frame_free(&_outputFrame);
}

其中所使用的ffmpeg封装线程锁

其中的锁实现读者自己实现即可。


#include <malloc.h>

#define STRCMPI  _strcmpi
#include <string.h>
//#include "../Common/Lock.h"

extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavdevice/avdevice.h>
#include <libavutil/audio_fifo.h>
#include <libavutil/avstring.h>
#include <libavutil/imgutils.h>
#include <libswresample/swresample.h>
#include <libswscale/swscale.h>
#include <libavutil/mathematics.h>
#include <libavutil/avutil.h>
}
#include <atomic>
using namespace std;

class FFMPEGLibrary 
{
  public:
    FFMPEGLibrary();
    ~FFMPEGLibrary();

    int Load();

    AVCodec *AvcodecFindDecoder(enum AVCodecID id);

	AVCodecContext *AvcodecAllocContext(const AVCodec* avcodec);
    
	AVFrame *AvcodecAllocFrame(void);
    
	int AvcodecOpen(AVCodecContext *ctx, AVCodec *codec);
    
	int AvcodecClose(AVCodecContext *ctx);
    
	int AvcodecDecodeVideo(AVCodecContext *ctx, AVFrame *pict, int *got_picture_ptr, BYTE *buf, int buf_size);
    
	void AvcodecFree(void * ptr);


    void AvLogSetLevel(int level);


    int IsLoaded();
	Lock processLock;

  protected:
    atomic<int> _isLoadedOK = 0;
};

extern FFMPEGLibrary FFMPEGLibraryInstance;
#include "FFMPEGLibrary.h"
FFMPEGLibrary FFMPEGLibraryInstance;
FFMPEGLibrary::FFMPEGLibrary()
{

}
FFMPEGLibrary::~FFMPEGLibrary()
{
}

int FFMPEGLibrary::Load()
{
	AutoLock m(processLock);      
	if (IsLoaded())
		return true;

//高版本已经不再需要
	//av_register_all();//注册库中所有可用的文件格式和编码器
	//avcodec_register_all();
	avformat_network_init();//注册网络接口

	_isLoadedOK = 1;
	return true;
}


AVCodec *FFMPEGLibrary::AvcodecFindDecoder(enum AVCodecID id)
{
	AutoLock m(processLock);
    return avcodec_find_decoder(id);
}

AVCodecContext *FFMPEGLibrary::AvcodecAllocContext(const AVCodec* avcodec)
{
	AutoLock m(processLock);
    return avcodec_alloc_context3(avcodec);
}

AVFrame *FFMPEGLibrary::AvcodecAllocFrame(void)
{
	return av_frame_alloc();
}

int FFMPEGLibrary::AvcodecOpen(AVCodecContext *ctx, AVCodec *codec)
{
    AutoLock m(processLock);
    return avcodec_open2(ctx, codec,NULL);	
}

int FFMPEGLibrary::AvcodecClose(AVCodecContext *ctx)
{
	AutoLock m(processLock);
    return avcodec_close(ctx);
}


int FFMPEGLibrary::AvcodecDecodeVideo(AVCodecContext *ctx, AVFrame *pict, int *got_picture_ptr, BYTE *buf, int buf_size)
{
	int bytesDecoded = 0;
	AVPacket pkt;
	av_init_packet(&pkt);
	pkt.data = buf;
	pkt.size = buf_size;
	bytesDecoded = avcodec_decode_video2(ctx, pict, got_picture_ptr, &pkt);
	//av_packet_unref(&pkt);
	if (bytesDecoded < 0)
	{
		return -1;
	}
	if (*got_picture_ptr)
		return 0;
	return -1;
}

void FFMPEGLibrary::AvcodecFree(void * ptr)
{

	AutoLock m(processLock);
    av_free(ptr);	
}


void FFMPEGLibrary::AvLogSetLevel(int level)
{
	av_log_set_level(level);
}



int FFMPEGLibrary::IsLoaded()
{
  return _isLoadedOK;
}

以上是关于AAC 音频解码类的主要内容,如果未能解决你的问题,请参考以下文章

Windows Media Foundation:获取 AAC 解码数据

解码aac,并生成wav文件

如何使用麦克风以 AAC 编解码器格式录制音频

音频压缩编码技术—AAC编解码器

音频压缩编码技术—AAC编解码器

通过 MFT 拆分 AAC 音频通道