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 主题。
希望对您有所帮助!
我想使用 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 主题。
希望对您有所帮助!