如何使用FFmpeg将立体声音频转换为单声道?

48

我在一个个人项目中使用FFmpeg库,需要关于一件事情的帮助。我有一个立体声音乐文件,想要将其转换为单声道音乐。这个库是否可以实现?是否有内置函数可以完成这项工作?我的项目是用C/C++编写的。

我在FFmpeg官网上的Doxygen文档和论坛中搜索过,但没有找到有趣的内容。

谢谢阅读!


据我记得,没有这样的函数,但是你可以通过将两个流计算在一起来轻松地自己转换它。 - user1810087
你有任何示例代码可以提供吗? - Meugiwara
3个回答

95

2
谢谢,帮了我很多!顺便说一下,如果有人需要像我一样批量转换文件:find . -name '*.mp4' -exec ./convert.sh {} \; - Marco Arruda
然后,在 convert.sh 文件内: - Marco Arruda
1
ffmpeg -i $1 -ac 1 $1.mono.mp4 - Marco Arruda
5
ж‚ЁеЏҮд»Өз›өжҺӨи°ѓз”ЁffmpegпәЊи·іиү‡convert.sh文件пәЊе‘Ң令如下пәљ find . -name '*.mp4' -exec ffmpeg -i '{}' -ac 1 '{}.mono.mp4' \;гЂ‚иҮӨе‘Ң令将жџӨж‰ң所有扩展еђҚдёғ.mp4的文件пәЊе№¶й’€еҮ№жҮЏдёҒ文件иүђиҰЊffmpegе‘Ң令пәЊд»Өе°†е…¶иҢ¬жҚұдёғеҚ•еӘ°йЃ“ж әеәЏ{}.mono.mp4гЂ‚ - joshtch
6
请注意,-ac 1会将立体声混音为单声道,这可能不是您想要的,特别是如果它只是“错误地以立体声录制的单声源”。在这种情况下,可以像这样丢弃一个通道:ffmpeg -i INPUT -filter_complex '[0:a]channelsplit=channel_layout=stereo:channels=FL[left]' -map '[left]' OUTPUT (当然,请替换INPUTOUTPUT)。这将选择左声道,如果您想要右声道,请使用FR[right] - scy
显示剩余2条评论

8
使用来自libswresample的swr_convert进行格式转换。类似这样的操作:
#include "libswresample/swresample.h"

au_convert_ctx = swr_alloc();

out_channel_layout = AV_CH_LAYOUT_MONO;
out_sample_fmt = AV_SAMPLE_FMT_S16;
out_sample_rate = 44100;
out_channels = av_get_channel_layout_nb_channels(out_channel_layout);

in_sample_fmt = pCodecCtx->sample_fmt;
in_channel_layout=av_get_default_channel_layout(pCodecCtx->channels);

au_convert_ctx=swr_alloc_set_opts(au_convert_ctx,out_channel_layout, out_sample_fmt, out_sample_rate,
            in_channel_layout, in_sample_fmt, pCodecCtx->sample_rate, 0, NULL);
swr_init(au_convert_ctx);
//Generate your frame of original audio, then use swr_convert to convert to mono,
//converted number of samples will now be in out_buffer.
int converted = swr_convert(au_convert_ctx, &out_buffer, MAX_AUDIO_FRAME_SIZE, (const uint8_t **)&pFrame->data , pFrame->nb_samples);
//...
swr_free(&au_convert_ctx);

以下是一些可以帮助您入门的内容。这将把原始格式转换为44100kHz单声道。您也可以使用pCodecCtx->sample_rate作为输出采样率。

这是最灵活、最简便的解决方案。


1

正如我在评论中提到的,您可以自行重新采样。这取决于您已经拥有什么以及使用的格式是什么。我无法为您提供立即可用的代码,但会给您一个示例(伪/真代码混合)。

在编码帧之后,并完成必须要做的事情后,您的数据缓冲区将填充音频。现在这取决于您的格式是什么(参见此处)以及您有多少声道。让我们假设它是有符号16位立体声,则您的缓冲区将如下所示:

+-----+-----+-----+-----+-----+
| LS1 | RS1 | LS2 | RS2 | ... |
+-----+-----+-----+-----+-----+
// LS = LEFT SAMPLE 16 Bit
// RS = RIGHT SAMPLE 16 Bit

现在迭代缓冲区并计算左右采样值。
for(int i=0; i<sample_size; i+=2) {
    auto r = (static_cast<int32_t>(buffer[i]) + buffer[i+1]) / 2;
    buffer[i] = buffer[i+1] = r;
}

2
这并不是一个好的策略,音频信号中的数字不仅仅是数字,它们代表着一个涉及到这些数字变化的信号,而不仅仅是这些数字本身...比如,如果你有一个正弦波,左右声道相位差为180度,那么在单声道混音中就没有信号。 - Grady Player

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接