ffmpeg 在 C++ 中将 AV_SAMPLE_FMT_S16 转换为 AV_SAMPLE_FMT_FLTP

ffmpeg convert AV_SAMPLE_FMT_S16 to AV_SAMPLE_FMT_FLTP in c++

我想使用 FFmpeg 4.2.2 将我的 Android 应用程序中的声音编码和解码为 Opus 格式。

问题是我的 Android 应用程序提供 AV_SAMPLE_FMT_S16 格式的原始 PCM 声音,但 FFmpeg opus 编码器只需要 AV_SAMPLE_FMT_FLTP。因此,我决定使用 FFmpeg swr_convert() 函数对声音进行重新采样,但它因 SIGSEGV 错误而崩溃,我不明白为什么。

我的代码如下所示:

swrContext = swr_alloc();

av_opt_set_int(swrContext, "in_channel_layout", (int64_t) codecContext->channel_layouts, 0);
av_opt_set_int(swrContext, "out_channel_layout", (int64_t) codecContext->channel_layouts,  0);
av_opt_set_int(swrContext, "in_sample_rate", 8000, 0);
av_opt_set_int(swrContext, "out_sample_rate", 48000, 0);

av_opt_set_sample_fmt(swrContext, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0);
av_opt_set_sample_fmt(swrContext, "out_sample_fmt", AV_SAMPLE_FMT_FLTP,  0);

swr_init(swrContext);

memcpy(frame->data[0], data, dataSize); 

uint8_t *outBuffer = (uint8_t *) malloc(sizeof(uint8_t) * frame->nb_samples);

swr_convert(swrContext, &outBuffer, frame->nb_samples, (const uint8_t **)frame->data, frame->nb_samples);

我是 C++ 的新手,如果我犯了一些错误,我深表歉意。

以下是您需要注意的几件事:

确保 frame->data[0] 包含足够的内存(至少等于 dataSize)以便在此调用中复制 data

memcpy( frame->data[0], data, dataSize );

此外,您需要相应地设置frame->nb_samples。也许,您已经拥有,但您发布的代码中没有任何迹象。

您还需要使用 av_samples_alloc 分配样本缓冲区,并在使用后释放它,包括所有其他分配的内存,这样就不会出现任何内存泄漏。

这是一个示例(添加 out_num_channels 的值):

const int in_sample_rate = 8000;
const int out_sample_rate = 48000;

swrContext = swr_alloc();
av_opt_set_int(swrContext, "in_channel_layout", (int64_t) codecContext->channel_layouts, 0);
av_opt_set_int(swrContext, "out_channel_layout", (int64_t) codecContext->channel_layouts,  0);
av_opt_set_int(swrContext, "in_sample_rate", in_sample_rate, 0);
av_opt_set_int(swrContext, "out_sample_rate", out_sample_rate, 0);
av_opt_set_sample_fmt(swrContext, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0);
av_opt_set_sample_fmt(swrContext, "out_sample_fmt", AV_SAMPLE_FMT_FLTP,  0);
swr_init(swrContext);

memcpy(frame->data[0], data, dataSize); // frame->nb_samples ???

const int out_num_samples = av_rescale_rnd(swr_get_delay(swrContext, in_sample_rate) + frame->nb_samples, out_sample_rate, in_sample_rate, AV_ROUND_UP);

uint8_t* out_samples = NULL;
av_samples_alloc(&out_samples, NULL, out_num_channels, out_num_samples, AV_SAMPLE_FMT_FLTP, 0);

out_num_samples = swr_convert(swrContext, &out_samples, out_num_samples, &frame->data[0], frame->nb_samples);

av_freep(&out_samples);    // free after use
swr_free(&swrContext);     // free after use

您可能想根据自己的要求修改 out_sample_rate。我建议使用 ffmpeg 命令在命令行上转换您的文件,并使用稍后在您的代码中使用的参数。代码迭代会更少,并且您可以更灵活地在命令行上工作。请参阅有关使用命令行 ffmpeg 实用程序的 this and this 主题。

希望对您有所帮助!