如何采样率从AV_SAMPLE_FMT_FLTP转换为AV_SAMPLE_FMT_S16? [英] How to convert sample rate from AV_SAMPLE_FMT_FLTP to AV_SAMPLE_FMT_S16?
问题描述
我的AAC解码与AV codec_de code_audio3的ffmpeg为PCM。然而,德codeS到AV_SAMPLE_FMT_FLTP样本格式(PCM支持32位浮点平面的),我需要AV_SAMPLE_FMT_S16(PCM 16位有符号 - S16LE)。
I am decoding aac to pcm with ffmpeg with avcodec_decode_audio3. However it decodes into AV_SAMPLE_FMT_FLTP sample format (PCM 32bit Float Planar) and i need AV_SAMPLE_FMT_S16 (PCM 16 bit signed - S16LE).
我知道ffmpeg的可以用-sample_fmt很容易做到这一点。我想要做同样的code,但我还是没能弄清楚。
I know that ffmpeg can do this easily with -sample_fmt. I want to do the same with the code but i still couldn't figure it out.
audio_resample没有为工作的:它失败,错误消息:....转换失败
audio_resample did not work for: it fails with error message: .... conversion failed.
推荐答案
修改2013年4月9日:制定了如何使用libswresample做到这一点...更快
EDIT 9th April 2013: Worked out how to use libswresample to do this... much faster!
在过去的2 - 3年内某些时候FFmpeg的AAC德codeR的输出格式从AV_SAMPLE_FMT_S16改为AV_SAMPLE_FMT_FLTP。这意味着,每个音频信道具有它自己的缓冲器,并且每个采样值是从-1.0缩放+1.0 32位浮点值。
At some point in the last 2-3 years FFmpeg's AAC decoder's output format changed from AV_SAMPLE_FMT_S16 to AV_SAMPLE_FMT_FLTP. This means that each audio channel has it's own buffer, and each sample value is a 32-bit floating point value scaled from -1.0 to +1.0.
而与AV_SAMPLE_FMT_S16数据是在一个单一的缓冲器,与样品交错,并且每个样本是从-32767到+32767一个符号整数。
Whereas with AV_SAMPLE_FMT_S16 the data is in a single buffer, with the samples interleaved, and each sample is a signed integer from -32767 to +32767.
如果你真的需要你的音频作为AV_SAMPLE_FMT_S16,那么你必须自己做转换。我想通了两种方式来做到这一点:
And if you really need your audio as AV_SAMPLE_FMT_S16, then you have to do the conversion yourself. I figured out two ways to do it:
1。使用libswresample (推荐)
#include "libswresample/swresample.h"
...
SwrContext *swr;
...
// Set up SWR context once you've got codec information
swr = swr_alloc();
av_opt_set_int(swr, "in_channel_layout", audioCodec->channel_layout, 0);
av_opt_set_int(swr, "out_channel_layout", audioCodec->channel_layout, 0);
av_opt_set_int(swr, "in_sample_rate", audioCodec->sample_rate, 0);
av_opt_set_int(swr, "out_sample_rate", audioCodec->sample_rate, 0);
av_opt_set_sample_fmt(swr, "in_sample_fmt", AV_SAMPLE_FMT_FLTP, 0);
av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);
swr_init(swr);
...
// In your decoder loop, after decoding an audio frame:
AVFrame *audioFrame = ...;
int16_t* outputBuffer = ...;
swr_convert(&outputBuffer, audioFrame->nb_samples, audioFrame->extended_data, audioFrame->nb_samples);
这就是所有你需要做的!
And that's all you have to do!
2。做手工在C (原来的答案,不推荐)
2. Do it by hand in C (original answer, not recommended)
因此,在你去code循环,当你有一个音频数据包,你去code这样的:
So in your decode loop, when you've got an audio packet you decode it like this:
AVCodecContext *audioCodec; // init'd elsewhere
AVFrame *audioFrame; // init'd elsewhere
AVPacket packet; // init'd elsewhere
int16_t* outputBuffer; // init'd elsewhere
int out_size = 0;
...
int len = avcodec_decode_audio4(audioCodec, audioFrame, &out_size, &packet);
然后,如果你有声音的完整框架,可以很容易将其转换:
And then, if you've got a full frame of audio, you can convert it fairly easily:
// Convert from AV_SAMPLE_FMT_FLTP to AV_SAMPLE_FMT_S16
int in_samples = audioFrame->nb_samples;
int in_linesize = audioFrame->linesize[0];
int i=0;
float* inputChannel0 = (float*)audioFrame->extended_data[0];
// Mono
if (audioFrame->channels==1) {
for (i=0 ; i<in_samples ; i++) {
float sample = *inputChannel0++;
if (sample<-1.0f) sample=-1.0f; else if (sample>1.0f) sample=1.0f;
outputBuffer[i] = (int16_t) (sample * 32767.0f);
}
}
// Stereo
else {
float* inputChannel1 = (float*)audioFrame->extended_data[1];
for (i=0 ; i<in_samples ; i++) {
outputBuffer[i*2] = (int16_t) ((*inputChannel0++) * 32767.0f);
outputBuffer[i*2+1] = (int16_t) ((*inputChannel1++) * 32767.0f);
}
}
// outputBuffer now contains 16-bit PCM!
我留下了几件事情出清晰......在单路夹紧最好应在立体声路径复制。而code可以很容易地优化。
I've left a couple of things out for clarity... the clamping in the mono path should ideally be duplicated in the stereo path. And the code can be easily optimized.
这篇关于如何采样率从AV_SAMPLE_FMT_FLTP转换为AV_SAMPLE_FMT_S16?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!