pcm音频混音

原因:由于涉及到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中算法:可以看出音频存在衰减.通过测试没有发现溢出.

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

 

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


版权声明:本文为u013692429原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。