最开始使用的是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;
}