实时音频编解码之十五 Opus编码-CELT编码

Posted shichaog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了实时音频编解码之十五 Opus编码-CELT编码相关的知识,希望对你有一定的参考价值。

本文谢绝任何形式转载,谢谢。

4.3.1 基频预滤波

对预加重之后信号预滤波,其和解码器的后滤波相反,基频周期搜索应根据以下标准优化:

1.连续性,对于连续帧,基频周期通常不会突变;

2.避免基频倍数,当使用的周期是实际周期的倍数时,后滤波器失去了大部分降低噪声的能力。

4.3.2 带宽和归一化

最小帧长为2.5ms,其他为2.5ms倍数,这些帧信号经过MDCT后输出分为多个频带,这些频带和耳朵的听觉灵敏度相匹配,编码器计算各个频带的,各频带能量使用为量化能量的均方根归一化,能量的计算和归一化分别实现于ompute_band_energies() 函数和normalise_bands() 函数(bands.c)。

4.3.3 能量包络归一化

能量量化包括粗量化和细量化两种类型,对于所有有用的比特率,粗量化选择使每个频带误差最小化的量化的对数能量。只有在非常低的比特率下,编码器才可能允许更大的误差以最大限度降低编码比特率,在CPU算力允许条件下,可以使用带帧间预测和不带帧间预测两种方式编码粗粒度能量以便选择最佳的预测模式。最佳的编码模式取决于编码帧长、编码比特率以及当前丢包率。

由于细粒度能量量化只取决于编码比特率而非编码信号,因而细粒度能量量化总是选择使每个频带误差最小化的量化的对数能量。

4.3.4 比特分配

有三种用于调节编码端帧间比特率的机制,分别是频带增强(band boost)、比特位分配微调(allocation trim)以及频带舍弃(band skipping)。

4.3.5 频带增强

当一个频带能量比相邻频带明显多时,编码器会增强一个频带能量。假设 E j E_j Ej是频带j的对数能量,则定义其和相邻频带对数能量差为:
D j = 2 ∗ E j − E j − 1 − E j + 1 D_j = 2*E_j - E_j-1-E_j+1 Dj=2EjEj1Ej+1
D j > t 1 D_j>t1 Dj>t1 D j > t 2 D_j>t2 Dj>t2时对频带 j j j增强,对于 L M > = 1 LM>=1 LM>=1时, t 1 = 2 , t 2 = 4 t1=2,t2=4 t1=2,t2=4,当 L M < = 1 LM<=1 LM<=1时, t 1 = 3 , t 2 = 5 t1=3,t2=5 t1=3,t2=5

4.3.6 分配微调

比特位分配微调是一个位于[0,10]之间的一个值,该值控制着高低频之间频带分配,编码器端缺省值为5,有两种方式微调该值,一种方式是根据输入信号的spectral tilt以5为中心上下调节正负2,对于低频具有更信息的信号向上调,对于高频具有更多信息的信号向下调,对于立体声输入,当低频段(前8个频带)的通道间相关性大时,该值最大可以向下调节到1。

4.3.7 频带舍弃

频带形状只在每个样本至少有1/2个比特位可用于PVQ。

4.3.8 时频判决

时频分辨率的选择基于比特率-失真(RD),失真是考虑了每种时频分辨率下所有频带的L1范数(所有频带能量的绝对值之和),使用L1范数的原因是其表示了信源为拉普拉斯分布的熵,两个频带使用相同的时频分辨率需要的编码比特率比使用不同时频分辨率要低,RD最优使用维特比方法计算, 实现于celt/celt.c中tf_analysis()函数。

4.3.9 Spreading值决策

表59中的spreading值影响CELT模块引入的编码噪声,f_r越大,变换(rotation)的影响越小,信号含有的tonal越多,tonal噪声也越多,tonality估计基于每个频带的离散概率密度(4个频点直方图),具有大量小值的波段被视为更具音调,并通过组合具有8个以上样本的所有波段来做出决定。实现于celt/bands.c中spreading_decision()函数。

4.3.10 球面矢量量化

CELT使用Pyramid Vector Quantizer (PVQ)量化还未基频预测器预测的每个频带谱,PVQ码本是由所有有符号脉冲(长度为N)累加之和为K的脉冲组成,脉冲满足同一位置具有相同符号。因此,码本包所有括满足和为k的N维整数码向量y,在比特位充分的频带,PVQ用于编码归一化的单位向量。对于给定的码向量y,单位向量 X = y ∣ ∣ y ∣ ∣ X=\\fracy||y|| X=yy,其中 ∣ ∣ ⋅ ∣ ∣ ||\\cdot|| 是L2范数。

4.3.11 PVQ搜索

最优码向量y的搜索实现于vq.c(alg_quant())函数,根据质量和复杂度的不同有多种搜索方法,参考实现通过将归一化谱X映射到金字塔码本K-1得到初始的码字:

y0 = truncate_towards_zero( (K-1) * X / sum(abs(X)))

根据输入信号以及参数N,K不同,初始码字的K个值有可能均非零,除了最后一个脉冲,剩下的脉冲使用最小化y和X之间的归一化相关性的贪心算法搜索,最小化相关性的公式如下:
J = − X T ∗ y ∣ ∣ y ∣ ∣ J=\\frac-X^T * y||y|| J=yXTy
也可以使用其它搜索算法,如alg_quant() celt/vq.c。

4.3.12 PVQ编码

编码向量X转换为索引i,0 <= i < V(N,K) ,所搜过程如下:

i=0,k=0;
for j=(N-1) to 0:
  if k > 0:
  	i = i + (V(N-j-1,k-1) + V(N-j,k-1))/2
  k = k + abs(X[j])
  if X[j] < 0:
    i = i + (V(N-j-1,k) + V(N-j,k))/2
    ```
    

以上是关于实时音频编解码之十五 Opus编码-CELT编码的主要内容,如果未能解决你的问题,请参考以下文章

实时音频编解码之十八 Opus解码 CELT解码

实时音频编解码之十 CELT编码器

实时音频编解码之十七 Opus解码 SILK解码

实时音频编解码之十七 Opus解码 SILK解码

实时音频编解码之十八 Opus解码 CELT解码

实时音频编解码之十 CELT编码器