• 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之后,确实能提高包的到达率,能在有限的延时下把通信的质量提高。 来源:音视频抗丢包技术综述,面向不可靠传输网络的抗丢包编解码器

  • 相关阅读:
    ElasticSearch 2 (23)
    ElasticSearch 2 (22)
    微信小程序框架模板部署:mpvue2.x+typescript+webpack3.x
    mpvue添加对scss的支持
    mpvue 封装axios请求方法
    Vue中qs插件的使用
    在微信小程序中使用less/sass
    微信小程序封装request请求
    VSCode --tsc : 无法加载文件
    Vue项目中的RSA加解密
  • 原文地址:https://www.cnblogs.com/smileglaze/p/13943228.html
Copyright © 2020-2023  润新知