使用 ffmpeg api 调用将 3gp (amr) 转换为 mp3
我尝试使用 libavformat (ffmpeg) 构建我自己的函数,将 3gp 音频文件(使用 android 移动设备录制)转换为 mp3 文件。
我使用 av_read_frame() 从输入文件中读取帧,并使用 avcodec_decode_audio3() 将数据解码到缓冲区中,并使用此缓冲区将数据编码为带有 avcodec_encode_audio 的 mp3。这似乎给了我一个正确的结果,可以将 wav 转换为 mp3 和 mp3 转换为 wav(或解码一个 mp3 并编码为另一个 mp3),但不能将 amr 转换为 mp3。我生成的 mp3 文件似乎具有正确的长度,但仅包含噪音。
在另一篇文章中,我读到 amr-decoder 不使用与 mp3 相同的样本格式。AMR 使用 FLT 和 mp3 S16 或 S32 以及我必须重新采样。因此,我为每个已解码的帧调用 av_audio_resample_init() 和 audio_resample。但这并不能完全解决我的问题。现在我可以听到我录制的声音并且听不懂我在说什么,但是质量非常低,并且仍然有很多噪音。我不确定我是否正确设置了 av_audio_resample 的参数,尤其是最后 4 个参数(我认为不是),或者我是否错过了其他东西。
ReSampleContext* reSampleContext = av_audio_resample_init(1, 1, 44100, 8000, AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_FLT, 0, 0, 0, 0.0);
while(1)
{
if(av_read_frame(ic, &avpkt) < 0)
{
break;
}
out_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
int count;
count = avcodec_decode_audio3(audio_stream->codec, (short *)decodedBuffer, &out_size, &avpkt);
if(count < 0)
{
break;
}
if((audio_resample(reSampleContext, (short *)resampledBuffer, (short *)decodedBuffer, out_size / 4)) < 0)
{
fprintf(stderr, "Error\n");
exit(1);
}
out_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
pktOut.size = avcodec_encode_audio(c, outbuf, out_size, (short *)resampledBuffer);
if(c->coded_frame && c->coded_frame->pts != AV_NOPTS_VALUE)
{
pktOut.pts = av_rescale_q(c->coded_frame->pts, c->time_base, outStream->time_base);
//av_res
}
pktOut.pts = AV_NOPTS_VALUE;
pktOut.dts = AV_NOPTS_VALUE;
pktOut.flags |= AV_PKT_FLAG_KEY;
pktOut.stream_index = audio_stream->index;
pktOut.data = outbuf;
if(av_write_frame(oc, &pktOut) != 0)
{
fprintf(stderr, "Error while writing audio frame\n");
exit(1);
}
}