c++ aac转pcm

最开始使用的是ffmpeg

主要代码如下:

//注册所有的工具
	av_register_all();

	AVFormatContext *fmt_ctx = NULL;
	AVCodecContext  *cod_ctx = NULL;
	AVCodec         *cod   = NULL;

	//分配一个avformat
	fmt_ctx = avformat_alloc_context();
	if (fmt_ctx == NULL)
		printf("alloc fail");

	//打开文件,解封装
	if (avformat_open_input(&fmt_ctx, in_file, NULL, NULL) != 0)
		printf("open fail");

	//查找文件的相关流信息
	if (avformat_find_stream_info(fmt_ctx, NULL) < 0)
		printf("find stream fail");

	//输出格式信息
	av_dump_format(fmt_ctx, 0, in_file, 0);

	//查找解码信息
	int stream_index = -1;
	for (int i = 0; i < fmt_ctx->nb_streams; i++)
		if (fmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
			stream_index = i;
			break;
		}

		if (stream_index == -1)
			printf("find stream fail");

		//保存解码器
		cod_ctx = fmt_ctx->streams[stream_index]->codec;
		cod = avcodec_find_decoder(cod_ctx->codec_id);

		if (cod == NULL)
			printf("find codec fail");

		if (avcodec_open2(cod_ctx, cod, NULL) < 0)
			printf("can't open codec");

		FILE *out_fb = NULL;
		out_fb = fopen(out_file, "wb");

		//创建packet,用于存储解码前的数据
		AVPacket *packet = (AVPacket *)malloc(sizeof(AVPacket));
		av_init_packet(packet);

		//设置转码后输出相关参数
		//采样的布局方式
		uint64_t out_channel_layout = AV_CH_LAYOUT_MONO;
		//采样个数
		int out_nb_samples = 1024;
		//采样格式
		enum AVSampleFormat  sample_fmt = AV_SAMPLE_FMT_S16;
		//采样率
		int out_sample_rate = 16000;
		//通道数
		int out_channels = av_get_channel_layout_nb_channels(out_channel_layout);
		printf("%d\n",out_channels);
		//创建buffer
		int buffer_size = av_samples_get_buffer_size(NULL, out_channels, out_nb_samples, sample_fmt, 1);


		//注意要用av_malloc
		uint8_t *buffer = (uint8_t *)av_malloc(MAX_AUDIO_FRAME_SIZE * 2);


		//创建Frame,用于存储解码后的数据
		AVFrame *frame = av_frame_alloc();

		int got_picture;

		int64_t in_channel_layout = av_get_default_channel_layout(cod_ctx->channels);
		//打开转码器
		struct SwrContext *convert_ctx = swr_alloc();
		//设置转码参数
		convert_ctx = swr_alloc_set_opts(convert_ctx, out_channel_layout, sample_fmt, out_sample_rate, \
			in_channel_layout, cod_ctx->sample_fmt, cod_ctx->sample_rate, 0, NULL);
		//初始化转码器
		swr_init(convert_ctx);

		//while循环,每次读取一帧,并转码

		while (av_read_frame(fmt_ctx, packet) >= 0) {

			if (packet->stream_index == stream_index) {

				//解码声音
				if (avcodec_decode_audio4(cod_ctx, frame, &got_picture, packet) < 0) {
					printf("decode error");
					return -1;
				}

				if (got_picture > 0) {
					//转码
					swr_convert(convert_ctx, &buffer, MAX_AUDIO_FRAME_SIZE, (const uint8_t **)frame->data, frame->nb_samples);

					printf("pts:%10lld\t packet size:%d\n", packet->pts, packet->size);

					fwrite(buffer, 1, buffer_size, out_fb);
				}
				got_picture=0;
			}

			av_free_packet(packet);
		}

		swr_free(&convert_ctx);

		fclose(out_fb);

是从文件读取然后解码的,但是项目需要是从内存当中解码的,查了下资料,改动如下:

const char *in_file = "./qf2.aac";
const char *out_file = "./qf3.pcm";
FILE *infile = NULL;

int read_buffer(void *opaque, uint8_t *buf, int buf_size){
	if(!feof(infile)){
		int true_size=fread(buf,1,buf_size,infile);
		return true_size;
	}else{
		return -1;
	}
}


int main()
{
	//注册所有的工具
	av_register_all();

	AVFormatContext *fmt_ctx = NULL;
	AVCodecContext  *cod_ctx = NULL;
	AVCodec         *cod   = NULL;

	infile = fopen(in_file, "rb");	//视频源文件 

	//分配一个avformat
	fmt_ctx = avformat_alloc_context();
	if (fmt_ctx == NULL)
		printf("alloc fail");

	AVFormatContext *ic = NULL;
	ic = avformat_alloc_context();
	unsigned char * iobuffer=(unsigned char *)av_malloc(327680);
	AVIOContext *avio =avio_alloc_context(iobuffer, 327680,0,NULL,read_buffer,NULL,NULL);
	ic->pb=avio;
	int err = avformat_open_input(&ic, "nothing", NULL, NULL);

	fmt_ctx->pb=avio; 
	fmt_ctx->flags=AVFMT_FLAG_CUSTOM_IO;
	//打开文件,解封装
	if (avformat_open_input(&fmt_ctx, "nothing",NULL, NULL) != 0)
		printf("open fail");

	//查找文件的相关流信息
	if (avformat_find_stream_info(fmt_ctx, NULL) < 0)
		printf("find stream fail");

	//查找解码信息
	int stream_index = 0;

	//保存解码器
	cod_ctx = fmt_ctx->streams[stream_index]->codec;
	cod = avcodec_find_decoder(cod_ctx->codec_id);

	if (cod == NULL)
		printf("find codec fail");

	if (avcodec_open2(cod_ctx, cod, NULL) < 0)
		printf("can't open codec");

	FILE *out_fb = NULL;
	out_fb = fopen(out_file, "wb");

	//创建packet,用于存储解码前的数据
	AVPacket *packet = (AVPacket *)malloc(sizeof(AVPacket));
	av_init_packet(packet);

	//设置转码后输出相关参数
	//采样的布局方式
	uint64_t out_channel_layout = AV_CH_LAYOUT_STEREO;
	//采样个数
	int out_nb_samples = 1024;
	//采样格式
	enum AVSampleFormat  sample_fmt = AV_SAMPLE_FMT_S16;
	//采样率
	int out_sample_rate = 44100;
	//通道数
	int out_channels = av_get_channel_layout_nb_channels(out_channel_layout);
	//创建buffer
	int buffer_size = av_samples_get_buffer_size(NULL, out_channels, out_nb_samples, sample_fmt, 1);


	//注意要用av_malloc
	uint8_t *buffer = (uint8_t *)av_malloc(MAX_AUDIO_FRAME_SIZE * 2);


	//创建Frame,用于存储解码后的数据
	AVFrame *frame = av_frame_alloc();

	int got_picture;

	int64_t in_channel_layout = av_get_default_channel_layout(cod_ctx->channels);
	//打开转码器
	struct SwrContext *convert_ctx = swr_alloc();
	//设置转码参数
	convert_ctx = swr_alloc_set_opts(convert_ctx, out_channel_layout, sample_fmt, out_sample_rate, \
		in_channel_layout, cod_ctx->sample_fmt, cod_ctx->sample_rate, 0, NULL);
	//初始化转码器
	swr_init(convert_ctx);

	printf("informat:%d,%d,%d\n", cod_ctx->sample_rate, cod_ctx->sample_fmt, cod_ctx->channels);
	printf("outformat:%d,%d,1\n", out_sample_rate,sample_fmt);

	//while循环,每次读取一帧,并转码

	while (av_read_frame(fmt_ctx, packet) >= 0) {

		if (packet->stream_index == stream_index) {

			//解码声音
			if (avcodec_decode_audio4(cod_ctx, frame, &got_picture, packet) < 0) {
				printf("decode error");
				return -1;
			}

			if (got_picture > 0) {
				//转码
				swr_convert(convert_ctx, &buffer, MAX_AUDIO_FRAME_SIZE, (const uint8_t **)frame->data, frame->nb_samples);

				printf("pts:%10lld\t packet size:%d, out pts:%10lld\t size:%d\n", packet->pts, packet->size, frame->pkt_pts, frame->linesize[0]);

				fwrite(buffer, 1, buffer_size, out_fb);
			}
			got_picture=0;
		}

		av_free_packet(packet);
	}

	swr_free(&convert_ctx);

	fclose(out_fb);

	return 0;
}

再改进一下:


int DecodeAudio::audioInit(AVCodecID codec_id, AVSampleFormat sample_fmt, int sample_rate, int channels)
{
	av_register_all();
	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;
	}
    //如果是aac解码,无论sample_fmt设置什么都是AV_SAMPLE_FMT_FLTP
	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;*/

	pPacketAudio = (AVPacket *)malloc(sizeof(AVPacket));
	av_init_packet(pPacketAudio);
	
	pFrameAudio = av_frame_alloc();
	if (NULL == pFrameAudio)
		return -1;

	/*AVFormatContext *ic = NULL;
	ic = avformat_alloc_context();
	unsigned char * iobuffer=(unsigned char *)malloc(32768);

	AVIOContext *avio =avio_alloc_context(iobuffer, 32768,0,NULL,fill_iobuffer,NULL,NULL);
	ic->pb=avio;
	int err = avformat_open_input(&ic, "nothing", NULL, NULL); */
	buffer = (uint8_t *)av_malloc(192000 * 2);

    //使用ffmpeg2.8.1, aac解码后是AV_SAMPLE_FMT_FLTP
    //需要使用swcontext转换成AV_SAMPLE_FMT_S16
    //否则声音一直杂音
	convert_ctx = swr_alloc();
	//设置转码参数
	convert_ctx = swr_alloc_set_opts(convert_ctx, AV_CH_LAYOUT_MONO, sample_fmt, sample_rate, \
		pCodecCtxAudio->channels, pCodecCtxAudio->sample_fmt, pCodecCtxAudio->sample_rate, 0, NULL);
	//初始化转码器
	swr_init(convert_ctx);

	return 0;
}


int DecodeAudio::decode(char *data, int datalen, char *outdata, int &outlen)
{
	int ret = 0;
	int got_picture = 0;
	outlen = 0;

	pPacketAudio->size = datalen;
	pPacketAudio->data = (uint8_t *)av_malloc(pPacketAudio->size);
	memcpy(pPacketAudio->data, data, datalen);

	ret = avcodec_decode_audio4(pCodecCtxAudio, pFrameAudio, &got_picture, pPacketAudio);
	if (ret < 0) {
		printf("decode error:%d\n", ret);
		av_free(pPacketAudio->data);
		return -1;
	}

	if (got_picture > 0) {
		//转码
		int outsize = 0;
		int outsamples = swr_convert(convert_ctx, &buffer, pFrameAudio->nb_samples, (const uint8_t **)pFrameAudio->data, pFrameAudio->nb_samples);
        //获取输出sample大小,以s16为例
        int bytesPerSample = av_get_bytes_per_sample(AV_SAMPLE_FMT_S16);
		//printf("pts:%10lld\t packet size:%d\n", packet->pts, packet->size);
		memcpy(outdata, buffer, outsamples * bytesPerSample );
		outlen = pFrameAudio->linesize[0];
		//fwrite(buffer, 1, outsize, out_fb);
	}
	got_picture=0;

	av_free(pPacketAudio->data);
	return 0;
}

最后,再来一版用faad2解码aac的,这个比较简单,推荐

// faacd2test.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

/**
 * faaddec.c
 * use faad library to decode AAC, only can decode frame with ADTS head 
 */
#include <stdio.h>
#include <memory.h>
#include "faad.h"
 
#define FRAME_MAX_LEN 1024*50 
#define BUFFER_MAX_LEN 1024*1024*4
 
void show_usage()
{
    printf("usage\nfaaddec src_file dst_file");
}
 
/**
 * fetch one ADTS frame
 */
int get_one_ADTS_frame(unsigned char* buffer, size_t buf_size, unsigned char* data ,size_t* data_size)
{
    size_t size = 0;
 
    if(!buffer || !data || !data_size )
    {
        return -1;
    }
 
    while(1)
    {
        if(buf_size  < 7 )
        {
            return -1;
        }
 
        if((buffer[0] == 0xff) && ((buffer[1] & 0xf0) == 0xf0) )
        {
            size |= ((buffer[3] & 0x03) <<11);     //high 2 bit
            size |= buffer[4]<<3;                //middle 8 bit
            size |= ((buffer[5] & 0xe0)>>5);        //low 3bit
            break;
        }
        --buf_size;
        ++buffer;
    }
 
    if(buf_size < size)
    {
        return -1;
    }
 
    memcpy(data, buffer, size);
    *data_size = size;
    
    return 0;
}
 
int main(int argc, char* argv[])
{
    static unsigned char frame[FRAME_MAX_LEN];
    static unsigned char buffer[BUFFER_MAX_LEN] = {0};
 
    char src_file[128] = "qf2.aac";
    char dst_file[128] = "out.pcm";
 
    unsigned long samplerate;
    unsigned char channels;
    NeAACDecHandle decoder = 0;
 
    size_t data_size = 0;
    size_t size = 0;
 
    NeAACDecFrameInfo frame_info;
    unsigned char* input_data = buffer;
    unsigned char* pcm_data = NULL;
 
 
    FILE *ifile = fopen(src_file, "rb");
    FILE *ofile = fopen(dst_file, "wb");
    if(!ifile || !ofile)
    {
        printf("source or destination file");
        return -1;
    }

	fseek(ifile,0L,SEEK_END);
	size=ftell(ifile);
	fseek(ifile,0L,SEEK_SET);
 
     data_size = fread(buffer, 1, 1024, ifile);

	 decoder = NeAACDecOpen();    
	 if(get_one_ADTS_frame(buffer, data_size, frame, &data_size) < 0)
	 {
		 return -1;
	 }

	 NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration(decoder);
	 conf->defObjectType = LC;
	 conf->defSampleRate = 44100;
	 conf->outputFormat = FAAD_FMT_16BIT;
	 conf->dontUpSampleImplicitSBR = 1;
	 NeAACDecSetConfiguration(decoder, conf);

	 //initialize decoder
	 NeAACDecInit(decoder, frame, data_size, &samplerate, &channels);
	 printf("samplerate %d, channels %d\n", samplerate, channels);

	 int dataSendPerSecond = 1024;
	 fseek(ifile,0L,SEEK_SET);
	 char tmp[4096] = {0};
	 int pos = 0;
	 data_size = 0;
	 while (size > 0)
	 {
		 if (size <= dataSendPerSecond)
		 {
			 dataSendPerSecond = size;
		 }
		 int read_len = fread(buffer + pos,1,dataSendPerSecond,ifile);
		 if (read_len)
		 {
			 int len = read_len + pos;
			 pos = 0;
			 unsigned char *pbuffer = buffer;

			 while(get_one_ADTS_frame(pbuffer, len, frame, &data_size) == 0)
			 {
				 //decode ADTS frame
				 pcm_data = (unsigned char*)NeAACDecDecode(decoder, &frame_info, frame, data_size); 

				 if(frame_info.error > 0)
				 {
					 printf("%s\n",NeAACDecGetErrorMessage(frame_info.error));
				 }
				 else if(pcm_data && frame_info.samples > 0)
				 {
					 printf("frame info: bytesconsumed %d, channels %d, header_type %d,object_type %d, samples %d, samplerate %d\n", 
							frame_info.bytesconsumed, 
							frame_info.channels, frame_info.header_type, 
							frame_info.object_type, frame_info.samples, 
							frame_info.samplerate);

					 fwrite(pcm_data, 1, frame_info.samples * frame_info.channels, ofile);      //2个通道
					 fflush(ofile);
				 }        
				 len -= data_size;
				 pbuffer += data_size;
			 }
			 printf("res len:%d\n", len);
 			 if (len > 0)
			 {
				 unsigned char *tmpbuffer = buffer;
				 for (int i = 0; i < len; i++)
				 {
					 *tmpbuffer++ = *pbuffer++;
				 }
				 pos = len;
			 }
			 size -= read_len;
		 }
	 }

    NeAACDecClose(decoder);
 
    fclose(ifile);
    fclose(ofile);
 
	return 0;
}

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值