原因:由于涉及到pcm的音频混音,故创建一个Demo进行混音测试,主要使用方法为归一化(自适应混音加权),平均调整权重法,自动对齐算法,及有人说的newlc中的一段算法,以上算法有可能名称叫法不同。
平均调整权重法(平均法):不同的会话成员具有相同的权重,该方法虽然不会引入噪声,但是随着会话成员的增多,各路语音的衰减将愈加严重.
自适应混音加权:使用可变的衰减因子对语音进行衰减,该衰减因子代表了语音的权重,该衰减因子随着数据的变化而变化,当数据溢出时,则相应的使衰减因子变小,使后续的数据在衰减后处于临界值以内,没有溢出时,让衰减因子慢慢增大,使数据变化相对平滑。(随着会话成员增多也会出现溢出问题)
自动对齐算法:考虑参与混音的多路音视频信号自身特点,以它们自身的比例作为权重,从而决定它们在合成后的输出中所占比重。(测试发现高频信号损失严重)
箝位算法:时域叠加,进行溢出检测,然后进行饱和运算.(一般通用使用,但是容易溢出).
混音原理简单说一下:声音是由于物体的振动对周围的空气产生压力而传播的一种压力波,转成电信号后经过抽样,量化,仍然是连续平滑的波形信号,量化后的波形信号的频率与声音的频率对应,振幅与声音的音量对应,量化的语音信号的叠加等价于空气中声波的叠加,所以当采样率一致时,混音可以实现为将各对应信号的采样数据线性叠加。而问题的关键就是如何处理叠加后溢出问题。
测试验证如下:
首先使用FFmpeg生成pcm文件和FFpaly进行播放命令行如下:
ffmepg -i .mp3 -f s16le -ar 441000 -ac 2 out.pcm
ffplay -ar 44100 -ac 2 -f s16le -i out.pcm通过FFmpeg的amix进行混音命令行如下:
ffmpeg -f s16le -ar 44100 -ac 2 -i 1.pcm -f s16le -ar 44100 -ac 2 -i 2.pcm -f s16le -ar 44100 -ac 2 -i 3.pcm -filter_complex amix=inputs=3:duration=frist:dropout_transition=0 -f s16le -ar 44100 -ac 2 mix.pcm如果需要调整混音音量的话命令行如下:
ffmpeg -f s16le -ar 44100 -ac 2 -i 1.pcm -f s16le -ar 44100 -ac 2 -i 2.pcm -f s16le -ar 44100 -ac 2 -i 3.pcm -filter_complex "[0:a]volume=0.8[a0]; [1:a]volume=0.8[a1]; [2:a]volume=2[a2]; [a0][a1][a2]amix=inputs=3[a]" -map “[a]” -f s16le -ar 44100 -ac 2 mix.pcm
0.8表示原始声音的0.8倍.分析FFmpeg的amix filter混音实现原理代码如下:通过代码可以看出amix内部的实现可以简单理解为通过平均权重算法,即每个会话的权重都是相同的.该算法的弊端在于多路会话时,如果某一路的声音较低,则最终mix后有可能会听不到声音.
static void calculate_scales(MixContext *s, int nb_samples)
{
int i;
if (s->scale_norm > s->active_inputs) {
s->scale_norm -= nb_samples / (s->dropout_transition * s->sample_rate);
s->scale_norm = FFMAX(s->scale_norm, s->active_inputs);
}
for (i = 0; i < s->nb_inputs; i++) {
if (s->input_state[i] & INPUT_ON)
s->input_scale[i] = 1.0f / s->scale_norm;
else
s->input_scale[i] = 0.0f;
}
}
static int output_frame(AVFilterLink *outlink)
{
for (i = 0; i < s->nb_inputs; i++) {
if (s->input_state[i] & INPUT_ON) {
int planes, plane_size, p;
av_audio_fifo_read(s->fifos[i], (void **)in_buf->extended_data,
nb_samples);
planes = s->planar ? s->nb_channels : 1;
plane_size = nb_samples * (s->planar ? 1 : s->nb_channels);
plane_size = FFALIGN(plane_size, 16);
if (out_buf->format == AV_SAMPLE_FMT_FLT ||
out_buf->format == AV_SAMPLE_FMT_FLTP) {
for (p = 0; p < planes; p++) {
s->fdsp->vector_fmac_scalar((float *)out_buf->extended_data[p],
(float *) in_buf->extended_data[p],
s->input_scale[i], plane_size);
}
} else {
for (p = 0; p < planes; p++) {
s->fdsp->vector_dmac_scalar((double *)out_buf->extended_data[p],
(double *) in_buf->extended_data[p],
s->input_scale[i], plane_size);
}
}
}
}
}
static void vector_fmac_scalar_c(float *dst, const float *src, float mul,
int len)
{
int i;
for (i = 0; i < len; i++)
dst[i] += src[i] * mul;
}通过查看pcm波形进行对比各算法如下:
平均权重算法:可以看出音量衰减严重,但是不会引入噪声.

自适应混音算法:可以看出声音没有明显衰减.数据保存相对完整.

newlc中算法:可以看出音频存在衰减.通过测试没有发现溢出.

自动对齐算法:高频损失严重,噪声明显.

总结:以上只是简单的几个算法测试,目前还在继续研究其他一些更好地算法.测试代码也已经上传.