ffmpeg 解码amr音频 到pcm文件有噪音

wangsky2 2013-07-03 09:47:09
最近在用ffmpeg解码amr音频文件,能够正常解码,但是存储问pcm文件,打开pcm文件全是噪声,同样的代码如果用来接mp3文件,存储为pcm文件,就能正常播放。
分析了下,amr音频采样编码为AV_SAMPLE_FMT_FLT,而MP3音频文件采样编码为AV_SAMPLE_FMT_S16P
网上查了下,说是要用swr_convert函数转换,但是转换了还是不对。请高手给看看啊
代码如下:


char *outfilename="D:/cvsroot/ffmpeg/ffmpegDecodeAndEncode/Debug/3.pcm";

FILE* pcm;
pcm = fopen(outfilename,"wb");

av_register_all();

AVFrame* frame = avcodec_alloc_frame();
if (!frame)
{
printf( "Error allocating the frame" );
return 1;
}

AVFormatContext* formatContext = NULL;
//if (avformat_open_input(&formatContext, "D:/cvsroot/ffmpeg/ffmpegDecodeAndEncode/Debug/1.mp3", NULL, NULL) != 0)
if (avformat_open_input(&formatContext, "D:/cvsroot/ffmpeg/ffmpegDecodeAndEncode/Debug/1.amr", NULL, NULL) != 0)
{
av_free(frame);
printf( "Error opening the file" );
return 1;
}

if (avformat_find_stream_info(formatContext, NULL) < 0)
{
av_free(frame);
av_close_input_file(formatContext);
printf( "Error finding the stream info" );
return 1;
}

AVStream* audioStream = NULL;
for (unsigned int i = 0; i < formatContext->nb_streams; ++i)
{
if (formatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
{
audioStream = formatContext->streams[i];
break;
}
}

if (audioStream == NULL)
{
av_free(frame);
av_close_input_file(formatContext);
printf( "Could not find any audio stream in the file" );
return 1;
}

AVCodecContext* codecContext = audioStream->codec;

codecContext->codec = avcodec_find_decoder(codecContext->codec_id);
if (codecContext->codec == NULL)
{
av_free(frame);
av_close_input_file(formatContext);
printf( "Couldn't find a proper decoder" );
return 1;
}
else if (avcodec_open2(codecContext, codecContext->codec, NULL) != 0)
{
av_free(frame);
av_close_input_file(formatContext);
printf( "Couldn't open the context with the decoder" );
return 1;
}

SwrContext* swrContext = NULL;

swrContext = swr_alloc_set_opts(swrContext,
codecContext->channel_layout, // out channel layout
codecContext->sample_fmt, // out sample format
codecContext->sample_rate, // out sample rate
codecContext->channel_layout, // in channel layout
codecContext->sample_fmt, // in sample format
codecContext->sample_rate, // in sample rate
0, // log offset
NULL); // log context
swr_init(swrContext);




if(codecContext->sample_fmt==AV_SAMPLE_FMT_S16)
{
swrContext = swr_alloc_set_opts(swrContext,
codecContext->channel_layout,
AV_SAMPLE_FMT_S16P,
codecContext->sample_rate,
codecContext->channel_layout,
AV_SAMPLE_FMT_S16,
codecContext->sample_rate,
0,
0);
if(swr_init(swrContext)<0)
{
printf("swr_init() for AV_SAMPLE_FMT_S16P fail");
return 0;
}
}
else if(codecContext->sample_fmt==AV_SAMPLE_FMT_FLT)
{
swrContext = swr_alloc_set_opts(swrContext,
codecContext->channel_layout,
AV_SAMPLE_FMT_S16P,
codecContext->sample_rate,
codecContext->channel_layout,
AV_SAMPLE_FMT_FLT,
codecContext->sample_rate,
0,
0);
if(swr_init(swrContext)<0)
{
printf("swr_init() for AV_SAMPLE_FMT_S16P fail");
return 0;
}
}


if (!swrContext)
{
av_free(frame);
avcodec_close(codecContext);
av_close_input_file(formatContext);
printf( "Couldn't allocate and set the resampling context" );
return 1;
}

printf(" bit_rate = %d \r\n", codecContext->bit_rate);
printf(" sample_rate = %d \r\n", codecContext->sample_rate);
printf(" channels = %d \r\n", codecContext->channels);
printf(" code_name = %s \r\n", codecContext->codec->name);

int bufSize = av_samples_get_buffer_size(NULL, codecContext->channels, codecContext->sample_rate, codecContext->sample_fmt, 0);
uint8_t* buf = new uint8_t[bufSize];

AVPacket packet;
av_init_packet(&packet);

int packetCount = 0;
int decodedFrameCount = 0;

static uint8_t audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];
uint8_t *out[]={audio_buf};
uint8_t *pktdata;
int pktsize,flush_complete=0;
while (av_read_frame(formatContext, &packet) == 0)
{
++packetCount;
if (packet.stream_index == audioStream->index)
{
pktdata = packet.data;
pktsize = packet.size;
int frameFinished = 0;
avcodec_decode_audio4(codecContext, frame, &frameFinished, &packet);

if (frameFinished)
{
pktsize -= len;
pktdata += len;
int data_size = av_samples_get_buffer_size(NULL,codecContext->channels,frame->nb_samples,codecContext->sample_fmt, 1);

/*****************************************************
以下代码使用swr_convert函数进行转换,但是转换后的文件连mp3到pcm文件都不能播放了,所以注释了
const uint8_t *in[] = {frame->data[0]};

int len=swr_convert(swrContext,out,sizeof(audio_buf)/codecContext->channels/av_get_bytes_per_sample(AV_SAMPLE_FMT_S16P),
in,frame->linesize[0]/codecContext->channels/av_get_bytes_per_sample(codecContext->sample_fmt));

len=len*codecContext->channels*av_get_bytes_per_sample(AV_SAMPLE_FMT_S16P);

if (len < 0) {
fprintf(stderr, "audio_resample() failed\n");
break;
}
if (len == sizeof(audio_buf) / codecContext->channels / av_get_bytes_per_sample(AV_SAMPLE_FMT_S16P)) {
fprintf(stderr, "warning: audio buffer is probably too small\n");
swr_init(swrContext);
}
*****************************************************/

char *data = (char *)malloc(data_size);
short *sample_buffer = (short *)frame->data[0];
for (int i = 0; i < data_size/2; i++)
{
data[i*2] = (char)(sample_buffer[i/2] & 0xFF);
data[i*2+1] = (char)((sample_buffer[i/2] >>8) & 0xFF);

}
fwrite(data, data_size, 1, pcm);
fflush(pcm);


}
}

av_free_packet(&packet);
}

delete [] buf;
swr_free(&swrContext);
av_free(frame);
avcodec_close(codecContext);
av_close_input_file(formatContext);
fclose(pcm);
...全文
3185 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
小宇宙响叮当 2015-07-16
  • 打赏
  • 举报
回复
这代码很多地方处理不好,最明显的地方就是解码的时候,没有考虑到解一包要解多次的情况。据我经验,解这种格式的音频文件,能一次就解出来才怪呢,所以你保存进文件的PCM数据是不全的!
firebolt2002 2014-08-02
  • 打赏
  • 举报
回复
刚好也碰到类似问题,找到你的帖子了。 估计你已经解决问题了,希望能帮到后来的朋友。 AV_SAMPLE_FMT_S16P格式数据是每个声道分开存储的。 对应到frame->data[0] 右声道; frame->data[1]左声道。 转换成 AV_SAMPLE_FMT_S16 格式只需要复制左右声道数据就可以了。 下面修改了一下你的代码,应该没问题了。

                    short *data = (char *)malloc(frame->nb_samples);
                    short *sample_buffer = (short *)frame->data[0];
                    short *sample_buffer1=(short*)frame->data[1];
                    for (int i = 0; i < frame->nb_samples; i++)
                    {
                        data[i*2] = sample_buffer[i];
                        data[i*2+1] = sample_buffer1[i];       
                    }
destiny_m 2013-11-26
  • 打赏
  • 举报
回复
引用 9 楼 wlizhang 的回复:
[quote=引用 7 楼 mlkiller 的回复:] 全是杂音的原因是,解码出来的pcm是32位浮点数的,你用16位定点数的打开,所以全是杂音。
我遇到同样的问题,用32位打开,虽然有声音出来但夹了杂音啊,不知道有没有大神解决了呢[/quote] 首先你看看原始的声音是否有杂音,其次我的是对wma格式的有用,其他的我没有一一实验,你可以通过加一些打印看看decode时候的格式。
simen-wang 2013-11-19
  • 打赏
  • 举报
回复
引用 7 楼 mlkiller 的回复:
全是杂音的原因是,解码出来的pcm是32位浮点数的,你用16位定点数的打开,所以全是杂音。
我遇到同样的问题,用32位打开,虽然有声音出来但夹了杂音啊,不知道有没有大神解决了呢
neuredfox 2013-10-25
  • 打赏
  • 举报
回复
引用 7 楼 mlkiller 的回复:
全是杂音的原因是,解码出来的pcm是32位浮点数的,你用16位定点数的打开,所以全是杂音。
是不是这个问题呢,我最近也在搞ape软解成pcm。mark一下。
destiny_m 2013-10-10
  • 打赏
  • 举报
回复
全是杂音的原因是,解码出来的pcm是32位浮点数的,你用16位定点数的打开,所以全是杂音。
wangsky2 2013-09-27
  • 打赏
  • 举报
回复
还是没有找到原因
fs_pie 2013-09-06
  • 打赏
  • 举报
回复
你这个其实就是官网上tutorial03的例子吧,我也碰到这个问题,我在ubuntu下运行,也是出现噪音,但是用ffplay播放就没问题,不知道是哪里的原因,请问你找到原因了吗?
wangsky2 2013-07-24
  • 打赏
  • 举报
回复
问题还是没有解决呢。不过发现了一个新的东西opencore-amr,编译然后在用,效果就是播放的比较快,最近忙其他的,没有研究。
wohenbuhaoa 2013-07-23
  • 打赏
  • 举报
回复
我也遇到了同样的问题,不知楼主问题解决了没有?
wwdunfeng 2013-07-05
  • 打赏
  • 举报
回复
问题解决了吗?
沈小夕 2013-07-03
  • 打赏
  • 举报
回复

19,469

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 图形处理/算法
社区管理员
  • 图形处理/算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧