视频会议的混音算法

2024-02-26 21:08
文章标签 算法 混音 视频会议

本文主要是介绍视频会议的混音算法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在多媒体会议中,音频互动是基本的要素之一,它是多媒体会议中最基本的要素.由于在分组网络中没有QoS,所以网络的拥塞导致了端到端通信的语音丢包和延时抖动等问题同时,多个端点同时相互发送数据更进一步增加了网络传输的负担,并且增加语音通信中数据收发的随机性和波动性.而语音互动的实时性要求远远高于多媒体会议中的其他要素 ,比如视频和数据.因为视频和数据在相对较长的时延内的抖动都是可以被用户接受的,而音频部分如果时间稍长,就会产生很明显的断续感,以致用户根本无法分辨语音所承载的语义从而严重影响沟通.为了解决这一问题,使用多点处理单元(MCU)对语音信号进行混音,则降低了网络传输的负担,对于每个端点的处理能力的需求也大大降低. 但是在常见的处理算法中,一般会因为多路语音信号采样量化数据叠加后超出量化上限, 而导致不得不采用饱和运算将其变更为量化上限,这样就引入了新的噪声. 为确保混音输出音频流的波形尽量表现出各路输入音频流的波形包络, 降低失真度, 如何处理量化上限溢出是一个关键的问题. 在前一阵子的实践摸索中大致在这一方面有一些认识, 也搜集整理了一些资料, 故在此将一些原先零散的碎片集中, 方便以后的查阅和进一步的探索.
-
[注:以下内容系资料整理集中, 参考了《视频会议中混音后溢出问题的研究及解决方法》·马旋 王衡 汪国平 董士海 等]
-
一、最简单的混音算法
- 现在一般的软件混音算法是对输入的音频数据进行线性叠加, 即:
-------(1)
或者叠加以后再取平均值:
--------(2)
- 其中, m 为输入音频流的个数, n 为一帧的样本数目, ·[i] 为一帧中的第i 个样本, ·[j] 为第j 个音频流, 所以, output[i] 为混音后的一帧中第i 个样本, input[j][i] 为第j 个输入音频流当前帧的第i 个样本(若经过编码则输入音频流应在混音前通过解码等还原成线性的PCM音频流).通常的语音数据为16 bit(或者更少, 如8 bit), 即可以用C 语言中的short 类型表示, 其取值范围是-32768 采样值 32767, 可以预想到多个音频流直接线性叠加以后就有可能溢出, 所以式(1) 最后的结果可能会有溢出, 产生噪音.
- 两个连续平滑的波形叠加, 其结果也应该是平滑的. 所以产生噪音的地方就是由叠加溢出的地方引入的. 我们需要采用滤波来处理这些溢出部分, 改善由于溢出所造成的质量下降.为了解决溢出的问题, 一个常用的方法就是使用更多的位数来表示音频数据的一个样本, 在混音完毕以后,再使用一些算法来降低其振幅, 使其分布在16 bit 所能表示的范围之内, 这种方法叫做归一化(Normalize). 通常使用32 bit 来表示线性叠加以后的数据, 也就是C 语言中的int 类型, 实现简单, 运算也比较快, 更能满足很多路音频同时进行混音的需要. 式(2)对叠加的和值作平均, 解决了溢出的问题, 但是混音以后的声音会总体衰减,特别是某一路音频流的能量与其他路音频流的能量反差很大的情况下, 音量非常小, 效果非常不理想. 进行滤波处理的另外一种常用方法就是"箝位", 当发生上溢时, 箝位以后的值为所能表示的最大值, 当发生下溢时, 箝位后的值为所能表示的最小值, 如式(3) 所示:
-----(3)
其中, sample 为叠加以后的样本值, 为 32 bit, MAX 是最大输出值, 这里为32767, MIN 为最小输出值, 为-32768. 现在很多现有的论文和系统都是采用箝位方法, 因为实现简单, 快速, 效率很高. 但是可以看出, 这种箝位方法相当于在最大和最小的临界值处切强行切断波形, 非常生硬, 会造成较大的波形失真, 听觉上引起如嘈杂, 出现突发刺耳的爆破音等.采用时域叠加作为基本的处理手段, 由于数字音频信号存在量化上限和下限的问题,则因叠加运算肯定会造成结果溢出. 通常的处理手段是进行溢出检测, 然后再进行饱和运算(如 4 式的方法), 即超过上限的结果被置为上限值, 超过下限的值置为下限值. 这种运算本身破坏了语音信号原有的时域特征, 从而引入了噪声. 这就是出现爆破声和语音不连续现象的原因. 同时, 随着参与混音的人数增加, 出现溢出的频率也不断上升, 所以这类方法存在一个上限, 而且这个上限值很低, 实验证明, 采用这种时域直接叠加的方式进行混音, 一般不能突破 4 路输入音频流的限制, 否则将无法分辨语音流的内容了.
-
二、改进的混音算法
- 混音的时候, 还需要屏蔽某一路的本地音频数据, 这样就不会听到本地的声音, 只能听到其他 n - 1 路的声音, 也就是说, 对于第 t 路音频, 要发送给这个终端的混音后的数据如式(4):
----- (4)
-
- 以下提出的算法主要思想就是使用一个衰减因子, 对音频数据进行衰减, 衰减因子会随着数据而变化. 当溢出时, 衰减因子比较小, 使溢出的音频数据衰减以后处于临界值以内, 当没有溢出时, 衰减因子会慢慢增加, 尽量保持数据的平滑变化. 而不是对于整帧使用同一个衰减因子来进行, 这是不同于式(2) 和式(3) 的地方, 既保证了整体的声强不至于衰减太快, 又保证了较小的失真度.

算法如下所述:
1. f 初始化为1.
2. 对于一帧中的样本按顺序处理:
---(a) output[i] = mixing[i] × f.
--- (b) 如果output[i] > MAX, 求得最大的 f0 满足 output[i] × f 0 < MAX, 然后 f = f0, output[i] = MAX.
--- (c) 如果output[i] < MIN, 求得最大的 f0 满足 output[i]×f0 > MIN, 然后 f = f0, output[i] = MIN.
3. 如果f < 1, 则f = f + STEPSIZE. 继续处理下一帧, 转2.

--其中f 为衰减因子, f0 为新的衰减因子; mixing[] 为所有音频流的某一帧线性叠加值, 实际实现的时候如式(4) 所示; output[] 为归一化以后的输出帧. MAX 为正的最大值; MIN 为负的最大值. STEPSIZE 为f 变化的步长, 通常取为 (1 - f)/16 或者 (1 - f)/32.
-特别的, 就是在衰减以后的值溢出的情况下, 求新的衰减因子 f0 的方法不同, 新的 f0 需要满足 output[i] × f0 < MAX 或者 output[i] × f0 > MIN, 而不是直接使用mixing[i]. 也就是说, 使用衰减以后的值output[i] 来计算f0, 而不是原始值mixing[i], 这样将使得衰减因子的变化更为平滑.
- 用数学来表达, S 为溢出的一个样本值, 在S × f 仍然溢出的情况下, 可以比较一下计算出来的新衰减因子的大小:假设是上溢, forig 是原始算法计算出的新的衰减因子, 则f`orig < (MAX/S) , 我们改进的算法得出的新衰减因子 f` new < (MAX/(S×f)) , 因为 S > (S × f), 所以(MAX/S) < (MAX/(S×f)) , 那么 f`new 很大程度上要大于f`orig. 衰减因子大了(更接近1), 相邻的数据变化不会特别大, 所以跳跃的现象不会特别明显.
-
- 上述改进过的混音方案在实测中,与常规的混音算法(直接线性叠加的方式)比较, 常规算法在混入 4 路音频流的结果, 已经明显听到背景噪音, 波形会突变失真, 出现比较轻微的爆破音, 少量出现语音不可以辨认的情况; 如果混入 5 路或者 5 路以上的音频流, 则输出的音频流质量已经不能从听觉上接受, 语声模糊并且爆破音明显, 噪音大, 难以辨别语音内容. 采用衰减因子的方式进行调整以后, 混入 4 路音频流从听觉上基本感觉不到背景噪音, 混入 5 路的情况下, 仍然能清晰辨别各路的语音内容, 不出现爆破音; 混入 6 路到 9 路的情况下仍然能保证语音质量, 不会发生突变的爆破音, 能够满足视频会议的要求.
- 从算法执行效率上看, 与常规的混音算法比较, 其时间复杂度并没有增加而具有同等的时间复杂度, 只是调和系数法在计算过程中叠加时需要进行一次额外的乘法运算(如上述算法描述的 2.a), 并且发生溢出的情况下需要重新计算新的调和系数(整数除法运算), 最后在算法的第三步需要进行一次加法运算(浮点数加法). 因为涉及的数值不会很大, 同时音频流的数据量较之视频等要小得很多, 在视频会议的应用中, 采用调和系数方法进行混音完全在 MCU 承载的能力范围内, 实测与常规混音算法比较, 格式为 linear PCM raw, 16 bit, 单声道, 采样率为8000 HZ, 时间30 秒, 帧长30 毫秒的情况下, 其差别不会超过 17ms , 并不会由此产生很大的延迟, 其实时性仍然得到保证, 而从混音的质量来说较常规混音算法要好很多.

<script type="text/javascript"> google_ad_client = "pub-2416224910262877"; google_ad_width = 728; google_ad_height = 90; google_ad_format = "728x90_as"; google_ad_channel = ""; google_color_border = "E1771E"; google_color_bg = "FFFFFF"; google_color_link = "0000FF"; google_color_text = "000000"; google_color_url = "008000"; </script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script>

这篇关于视频会议的混音算法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/750159

相关文章

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

康拓展开(hash算法中会用到)

康拓展开是一个全排列到一个自然数的双射(也就是某个全排列与某个自然数一一对应) 公式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。(a[i]在不同应用中的含义不同); 典型应用: 计算当前排列在所有由小到大全排列中的顺序,也就是说求当前排列是第

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

秋招最新大模型算法面试,熬夜都要肝完它

💥大家在面试大模型LLM这个板块的时候,不知道面试完会不会复盘、总结,做笔记的习惯,这份大模型算法岗面试八股笔记也帮助不少人拿到过offer ✨对于面试大模型算法工程师会有一定的帮助,都附有完整答案,熬夜也要看完,祝大家一臂之力 这份《大模型算法工程师面试题》已经上传CSDN,还有完整版的大模型 AI 学习资料,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

dp算法练习题【8】

不同二叉搜索树 96. 不同的二叉搜索树 给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。 示例 1: 输入:n = 3输出:5 示例 2: 输入:n = 1输出:1 class Solution {public int numTrees(int n) {int[] dp = new int

Codeforces Round #240 (Div. 2) E分治算法探究1

Codeforces Round #240 (Div. 2) E  http://codeforces.com/contest/415/problem/E 2^n个数,每次操作将其分成2^q份,对于每一份内部的数进行翻转(逆序),每次操作完后输出操作后新序列的逆序对数。 图一:  划分子问题。 图二: 分而治之,=>  合并 。 图三: 回溯:

最大公因数:欧几里得算法

简述         求两个数字 m和n 的最大公因数,假设r是m%n的余数,只要n不等于0,就一直执行 m=n,n=r 举例 以18和12为例 m n r18 % 12 = 612 % 6 = 06 0所以最大公因数为:6 代码实现 #include<iostream>using namespace std;/