Opus编解码练习

Wikipedia:Opus是一个有损声音编码的格式,由Xiph.Org基金会开发,之后由互联网工程任务(IETF)组进行标准化,目标是希望用单一格式包含声音和语音,取代Speex和Vorbis,且适用于网络上低延迟的实时语音频传输场景,标准格式定义于RFC 6716文件。Opus格式是一个开放格式,使用上没有任何专利或限制。

PCM数据编码之前,将数据混音成单声道数据,送入编码器进行编码

demo中的源PCM数据是48k采样率,16bit量化,双声道数据 双声道数据是以交织的方式进行存储,也就是是说,按左声道、右声道、左声道、右声道…的方式存放 16bit如果大小不够的话需要截断,注意跳变。

由于输入是双声道的,我先尝试如果编码时将声道设置为1,解码声道也设置为1

//channels: Number of channels (1 or 2) in input signal
encode_channel = 1;
decode_channel = 1;

直接这么合并后声音变得十分恐怖可怕,有杂音,女声都变成了男声!因为两个声道的数据直接被合并到了一个声道中。

我采取的是OPUS_SET_FORCE_CHANNELS()函数,编解码后声音很正常。

#define INPUT_CHANNEL 2
encode_channel = INPUT_CHANNEL;
decode_channel = 1;
opus_encoder_ctl(opus_encoder_handle, OPUS_SET_FORCE_CHANNELS(1));

可以在opus_defines.h中查看到此函数的说明

/** Configures mono/stereo forcing in the encoder.
* This can force the encoder to produce packets encoded as either mono or
* stereo, regardless of the format of the input audio. This is useful when
* the caller knows that the input signal is currently a mono source embedded
* in a stereo stream.
* @see OPUS_GET_FORCE_CHANNELS
* @param[in] x <tt>opus_int32</tt>: Allowed values:
* <dl>
* <dt>#OPUS_AUTO</dt><dd>Not forced (default)</dd>
* <dt>1</dt>         <dd>Forced mono</dd>
* <dt>2</dt>         <dd>Forced stereo</dd>
* </dl>
* @hideinitializer */
#define OPUS_SET_FORCE_CHANNELS(x) OPUS_SET_FORCE_CHANNELS_REQUEST, __opus_check_int(x)

opus的编码复杂度统计

通过opus接口将opus的编码复杂度分度设置为1和10,并做运算复杂度统计

相关函数为

/** Configures the encoder's computational complexity.
* The supported range is 0-10 inclusive with 10 representing the highest complexity.
* @see OPUS_GET_COMPLEXITY
* @param[in] x <tt>opus_int32</tt>: Allowed values: 0-10, inclusive.
*
* @hideinitializer */
#define OPUS_SET_COMPLEXITY(x) OPUS_SET_COMPLEXITY_REQUEST, __opus_check_int(x)

通过循环设定COMPLEXITY分别为0~10,使用计时方法为#include<ctime>clock()进行计时,详见代码。计时仅包括编码过程,最终结果为

Complexity=0. The run time is: 2.218s
Complexity=1. The run time is: 2.606s
Complexity=2. The run time is: 3.101s
Complexity=3. The run time is: 3.306s
Complexity=4. The run time is: 3.339s
Complexity=5. The run time is: 4.179s
Complexity=6. The run time is: 4.159s
Complexity=7. The run time is: 5.221s
Complexity=8. The run time is: 6.368s
Complexity=9. The run time is: 6.387s
Complexity=10. The run time is: 6.307s

评估48khz采样立体声序列不同码率条件下的质量

修改demo中的下面代码可以将48khz的opus文件解码为不同码率

encode_bitrate = 128000;
  • 码率: 32kbps
    • 声音的塑料感很严重,声音听起来有在颤抖的感觉。
  • 码率: 64kpbs
    • 较为清晰,基本感觉良好。
  • 码率: 128kbps
    • 非常清晰,犹如临场视听的感觉

ps:这个按键自动播放音频真的吓人。

评估48khz采样立体声序列不同模式条件下的质量

个人理解:opus支持恒定码率CBR和变码率VBR以及受约束码率CVBR三种编码方式。一般流媒体使用CBR,voip场景使用VBR。VBR编码效率较高,在网络条件好的情况下可以选用CVBR模式。

  • audio模式@48kbps、CBR模式对应设置为

      encode_bitrate = 48000;
      //set audio
      opus_encoder_handle = opus_encoder_create(encode_sample_rate, encode_channel, OPUS_APPLICATION_AUDIO, &error);
      //set cbr bitrate
      /*0 Hard CBR.
      * 1 VBR (default).The exact type of VBR may be retrieved via 
      * #OPUS_GET_VBR_CONSTRAINT.*/
      opus_encoder_ctl(opus_encoder_handle, OPUS_SET_VBR(0));
    
  • voip模式@ 32kbps、CVBR模式对应设置为

      encode_bitrate = 32000;
      //set voip
      opus_encoder_handle = opus_encoder_create(encode_sample_rate, encode_channel, OPUS_APPLICATION_VOIP, &error);
      //set cvbr
      /*0 Hard CBR.
      * 1 VBR (default).The exact type of VBR may be retrieved via 
      * #OPUS_GET_VBR_CONSTRAINT.*/
      opus_encoder_ctl(opus_encoder_handle, OPUS_SET_VBR(1));
      /*0 Unconstrained VBR.
      * 1 Constrained VBR (default).*/
      opus_encoder_ctl(opus_encoder_handle, OPUS_SET_VBR_CONSTRAINT(1));
    

    比较起来确实是第一种配置更为清晰,毕竟第二种更注重压缩效率。

评价不同丢包率条件下解码质量的差异

使用64kbps、cvbr模式

encode_bitrate = 64000;
//set cvbr
/*0 Hard CBR.
* 1 VBR (default).The exact type of VBR may be retrieved via 
* #OPUS_GET_VBR_CONSTRAINT.*/
opus_encoder_ctl(opus_encoder_handle, OPUS_SET_VBR(1));
/*0 Unconstrained VBR.
* 1 Constrained VBR (default).*/
opus_encoder_ctl(opus_encoder_handle, OPUS_SET_VBR_CONSTRAINT(1));

参照opus源码中opus_demo.c代码逻辑,设置不同的packet_loss_perc即可

fprintf(stderr, "-loss <perc>         : simulate packet loss, in percent (0-100); default: 0
" );
int packet_loss_perc;
packet_loss_perc = 0; //丢包率0%/10%/30%
opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(packet_loss_perc));
lost = len[toggle]==0 || (packet_loss_perc>0 && rand()%100 < packet_loss_perc);
if (lost)
    opus_decoder_ctl(dec, OPUS_GET_LAST_PACKET_DURATION(&output_samples));
else
    output_samples = max_frame_size;
  • 丢包率: 0%

    正常情况

  • 丢包率:10%

    轻微的声音缺失,有顿感

  • 丢包率:30%

    能够听出来卡卡的,不过还是能靠人类自身的能力想象缺失的部分(人脑插值,毕竟听了那么多遍了)。这也说明opus抗丢包能力还不错。

查到的一些说明:

Opus和Silk的编码器提出一种新方法,采用了下降码率的做法,类似于两个8kbps。在16kbps的音频流中,有4kbps的小包来对前一帧补偿。一旦大的包丢了,就使用小包来进行恢复,但是带来的问题是音频质量下降了。FEC是一种很好的抗丢包方法,但是它的问题是有可能会浪费带宽。使用FEC之后,确实能提高包的到达率,能在有限的延时下把通信的质量提高。 来源:音视频抗丢包技术综述,面向不可靠传输网络的抗丢包编解码器

原文地址:https://www.cnblogs.com/smileglaze/p/13943228.html