首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >FFmpeg -从AV_SAMPLE_FMT_FLTP重采样到AV_SAMPLE_FMT_S16的声音质量很差(慢,不调,噪音)

FFmpeg -从AV_SAMPLE_FMT_FLTP重采样到AV_SAMPLE_FMT_S16的声音质量很差(慢,不调,噪音)
EN

Stack Overflow用户
提问于 2014-04-02 20:37:17
回答 3查看 15K关注 0票数 9

我很困惑于在新的芬伯里重采样的结果。我将AAC音频解码为PCM,ffmpeg将音频信息显示为:

代码语言:javascript
运行
复制
Stream #0:0: Audio: aac, 44100 Hz, stereo, fltp, 122 kb/s

在新的ffmpeg中,输出示例是fltp格式,所以我必须将它从AV_SAMPLE_FMT_FLTP转换为AV_SAMPLE_FMT_S16。

PS:在旧的ffmpeg作为libavcodec 54.12.100,它是直接S16,所以不需要重采样和没有任何音质问题的

然后我尝试了三种重采样方法,

  1. 使用swr_convert
  2. 使用avresample_convert
  3. 改信

但它们都产生了同样的效果,声音质量真的很差,非常慢,不合拍,还有一些噪音。

我的重采样代码如下:

代码语言:javascript
运行
复制
void resampling(AVFrame* frame_, AVCodecContext* pCodecCtx, int64_t want_sample_rate, uint8_t* outbuf){
    SwrContext      *swrCtx_ = 0;
    AVAudioResampleContext *avr = 0;

    // Initializing the sample rate convert. We only really use it to convert float output into int.
    int64_t wanted_channel_layout = AV_CH_LAYOUT_STEREO;

#ifdef AV_SAMPLEING
    avr = avresample_alloc_context();
    av_opt_set_int(avr, "in_channel_layout", frame_->channel_layout, 0);
    av_opt_set_int(avr, "out_channel_layout", wanted_channel_layout, 0);
    av_opt_set_int(avr, "in_sample_rate", frame_->sample_rate, 0);
    av_opt_set_int(avr, "out_sample_rate", 44100, 0);
    av_opt_set_int(avr, "in_sample_fmt", pCodecCtx->sample_fmt, 0); //AV_SAMPLE_FMT_FLTP
    av_opt_set_int(avr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);
    av_opt_set_int(avr, "internal_sample_fmt", pCodecCtx->sample_fmt, 0);
    avresample_open(avr);
    avresample_convert(avr, &outbuf, frame_->linesize[0], frame_->nb_samples, frame_->extended_data, frame_->linesize[0], frame_->nb_samples);
    avresample_close(avr);
    return;
#endif

#ifdef USER_SAMPLEING
    if (pCodecCtx->sample_fmt == AV_SAMPLE_FMT_FLTP)
    {
            int nb_samples = frame_->nb_samples;
            int channels = frame_->channels;
            int outputBufferLen = nb_samples & channels * 2;
            auto outputBuffer = (int16_t*)outbuf;

            for (int i = 0; i < nb_samples; i++)
            {
                    for (int c = 0; c < channels; c++)
                    {
                            float* extended_data = (float*)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] = (int16_t)round(sample * 32767.0f);
                    }
            }
            return;
    }
#endif
    swrCtx_ = swr_alloc_set_opts(
            NULL, //swrCtx_,
            wanted_channel_layout,
            AV_SAMPLE_FMT_S16,
            want_sample_rate,
            pCodecCtx->channel_layout,
            pCodecCtx->sample_fmt,
            pCodecCtx->sample_rate,
            0,
            NULL);

    if (!swrCtx_ || swr_init(swrCtx_) < 0) {
            printf("swr_init: Failed to initialize the resampling context");
            return;
    }

    // convert audio to AV_SAMPLE_FMT_S16
    int swrRet = swr_convert(swrCtx_, &outbuf, frame_->nb_samples, (const uint8_t **)frame_->extended_data, frame_->nb_samples);
    if (swrRet < 0) {
            printf("swr_convert: Error while converting %d", swrRet);
            return;
    }
}

该怎么办呢?

PS1:玩嬉戏很好。

PS2:将重采样的S16 PCM保存到文件中,并播放它将有相同的声音质量问题。

非常感谢您的帮助和建议!

我还注意到,在旧的ffmpeg中,aac被重新定义为FLT格式,并直接解码为16位PCM,而在新的ffmpeg中,aac被计算为FLTP格式,并产生32位IEEE浮点输出。

因此,相同的代码将产生与不同版本的ffmpeg完全不同的输出。那么,,我想问一下,在新版本中,将AAC音频转换为16位PCM的正确方法是什么?

提前谢谢!

EN

回答 3

Stack Overflow用户

发布于 2014-04-29 03:40:51

您需要记住,AV_SAMPLE_FMT_FLTP是一个平面模式。如果您的代码期望AV_SAMPLE_FMT_S16 (交错模式)输出,则需要在转换后重新排序示例。考虑两个音频通道,采用交错模式,样本排序为"c0,c1,.“。平面模式为"c0,.,c1,.“。

类似问题:S16?

详细信息:8h.html

票数 5
EN

Stack Overflow用户

发布于 2014-11-18 18:17:45

我也很幸运做了类似的事。在您的代码块上

代码语言:javascript
运行
复制
int nb_samples = frame_->nb_samples;
int channels = frame_->channels;
int outputBufferLen = nb_samples & channels * 2;
auto outputBuffer = (int16_t*)outbuf;

for (int i = 0; i < nb_samples; i++) {
   for (int c = 0; c < channels; c++) {
      float* extended_data = (float*)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] = (int16_t)round(sample * 32767.0f);
   }

}

试着用以下方法替换:

代码语言:javascript
运行
复制
int nb_samples = frame_->nb_samples;
int channels = frame_->channels;
int outputBufferLen = nb_samples & channels * 2;
auto outputBuffer = (int16_t*)outbuf;

for(int i=0; i < nb_samples; i++) {
   for(int c=0; c < channels; c++) {
      outputBuffer[i*channels+c] = (int16_t)(((float *)frame_->extended_data[c]) * 32767.0f);
   }
}
票数 2
EN

Stack Overflow用户

发布于 2015-01-13 00:42:12

只有当你转换成不同的样本率时,你才需要重新采样。如果采样率相同,则只需将浮点平面格式转换为固定的16交错格式。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22822515

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档