gpt4 book ai didi

android-ndk - 如何将采样率从 AV_SAMPLE_FMT_FLTP 转换为 AV_SAMPLE_FMT_S16?

转载 作者:行者123 更新时间:2023-12-04 02:31:23 24 4
gpt4 key购买 nike

我正在使用带有avcodec_decode_audio3的ffmpeg将aac解码为pcm。但是它解码为 AV_SAMPLE_FMT_FLTP 样本格式(PCM 32 位浮点平面),我需要 AV_SAMPLE_FMT_S16(PCM 16 位签名 - S16LE)。

我知道 ffmpeg 可以使用 -sample_fmt 轻松做到这一点。我想对代码做同样的事情,但我仍然无法弄清楚。

audio_resample 不适用于:它失败并显示错误消息:.... 转换失败。

最佳答案

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

在过去 2-3 年的某个时间点,FFmpeg 的 AAC 解码器的输出格式从 AV_SAMPLE_FMT_S16 更改为 AV_SAMPLE_FMT_FLTP。这意味着每个音频 channel 都有自己的缓冲区,每个样本值都是一个 32 位浮点值,从 -1.0 缩放到 +1.0。

而对于 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!

为了清楚起见,我留下了一些东西......单声道路径中的钳位理想情况下应该在立体声路径中复制。并且可以轻松优化代码。

关于android-ndk - 如何将采样率从 AV_SAMPLE_FMT_FLTP 转换为 AV_SAMPLE_FMT_S16?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14989397/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com