如何采样率从AV_SAMPLE_FMT_FLTP 2 AV_SAMPLE_FMT_S16转换?(Ho

2019-08-17 02:17发布

我的AAC解码与avcodec_decode_audio3 FFMPEG为PCM。 然而,解码为AV_SAMPLE_FMT_FLTP样本格式(PCM支持32位浮点平面),我需要AV_SAMPLE_FMT_S16(PCM签署16位 - S16LE)。

我知道ffmpeg的可以用-sample_fmt很容易地做到这一点。 我想要做相同的代码,但我还是没弄明白。

audio_resample没有为工作的:它失败,错误消息:....转换失败。

Answer 1:

编辑2013年4月9日 :制定了如何使用libswresample做到这一点...快很多!

在过去的2 - 3年的某一点FFmpeg的AAC解码器的输出格式从AV_SAMPLE_FMT_S16改为AV_SAMPLE_FMT_FLTP。 这意味着,每个音频通道有它自己的缓冲器中,并且每个样本值被缩放从-1.0到1.0的32位浮点值。

而用AV_SAMPLE_FMT_S16的数据是在一个单一的缓冲器,与所述样本交错,并且每个样品来自-32767到32767有符号整数。

如果你真的需要你的声音作为AV_SAMPLE_FMT_S16,那么你必须自己做转换。 我想通了两种方法来做到这一点:

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);   

而这一切,你必须做的!

2.用手做它在C(原来的答案,不推荐)

因此,在你的解码循环,当你有一个音频包你这个样子对其进行解码:

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);

然后,如果你有音频的全画幅,你可以很容易将其转换:

    // 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!

我留下了几件事情出来清晰......在单路径夹紧最好应在立体声路径被复制。 和代码可以很容易地优化。



Answer 2:

我发现2二次采样函数从FFMPEG。 性能可能更好。

  1. avresample_convert() http://libav.org/doxygen/master/group__lavr.html
  2. swr_convert() http://spirton.com/svn/MPlayer-SB/ffmpeg/libswresample/swresample_test.c


Answer 3:

感谢鲁本为解决这个。 我也发现,当采用了直板的ffmpeg -i file.wav相比一些样本值均稍微偏离。 看来,在转换,他们用一个圆()上的值。

做转换,我做你修改力图为通道的任何数量的工作做了什么:

if (audioCodecContext->sample_fmt == AV_SAMPLE_FMT_FLTP)
{
    int nb_samples = decoded_frame->nb_samples;
    int channels = decoded_frame->channels;
    int outputBufferLen = nb_samples & channels * 2;
    short* outputBuffer = new short[outputBufferLen/2];

    for (int i = 0; i < nb_samples; i++)
    {
         for (int c = 0; c < channels; c++)
         {
             float* extended_data = (float*)decoded_frame->extended_data[c];
             float sample = extended_data[i];
             if (sample < -1.0f) sample = -1.0f;
             else if (sample > 1.0f) sample = 1.0f;
             outputBuffer[i * channels + c] = (short)round(sample * 32767.0f);
         }
    }

    // Do what you want with the data etc.

}

我从FFmpeg的0.11.1去 - > 1.1.3,发现样本格式恼人的变化。 我看了看设置request_sample_fmt到AV_SAMPLE_FMT_S16但是似乎AAC解码器不支持超过AV_SAMPLE_FMT_FLTP其他什么呢。



文章来源: How to convert sample rate from AV_SAMPLE_FMT_FLTP to AV_SAMPLE_FMT_S16?