zoukankan      html  css  js  c++  java
  • SILK编码语音转WAV格式

      SILK音频编码格式介绍、WAV文件封装格式介绍以及SILK音频编码到WAV的转换


    在语音相关的协议还原中,经常会遇到语音编码的问题,通常语音编码的数据无法直接展示,需要转换成WAV,MP3等格式,才能播放。这个转换过程,是首先将音频编码数据使用对应解码库解码为PCM流,然后再将PCM流根据封装格式的要求,进行编码封装,最后得到可供通用播放器支持的编码和格式。


    音频编码有很多,各有特色,本文首选介绍目前最流行的SILK编码。


    SILK编码最早在Skype中使用,它在编码效率和质量之间取得了很好的平衡,因此被广泛应用在互联网的音频相关产品中,目前广泛使用的是SILK V3。


    腾讯系产品,包括QQ、微信、小程序,在语音相关的实现中,也大量使用到SILK编码,并且,部分功能是直接让未加密的语音流在网络中传输,这是协议还原很感兴趣的部分。毕竟,腾讯的产品防守相当严密,不宜突破。


    WAV作为古老的音频文件格式,虽然有很多缺点,但使用仍然相当广泛,本文将对其关键点进行介绍,SILK编码音频文件解码并封装为WAV格式的方法。


    01

    SILK编码


    SILK采样率可为8、12、16或24 kHz,比特率可为6至40 kbit/s。对应到报文层面的直观印象,即SILK编码的语音数据每帧长度是不等的。


    SILK编码已经开源,目前可下载到的版本为V1.0.9,它是Opus编码的基础。因此可以在Opus编码的源文件中找到SILK编码的实现代码,下载地址如下:

    http://www.opus-codec.org/release/stable/2017/06/26/libopus-1_2_1.html


    当然,其它地方也能很容易找到SILK编码的实现,比如GitHub上:

    640?wx_fmt=png

    当前经常遇到的SILK V3的编码就是SILK编码,在SILK的V1.0.9版SDK中的编码就是SILK V3编码,另外SILK库版本差异对语音解码基本可以忽略。如果各位朋友需要下载SILK编码库,可关注本公众号后发送关键词“silk”获取。


    SILK编码库的功能是提供接口将SILK格式音频数据解码为PCM流以及将PCM流编码为SILk格式。在库内提供了编解码的例子,很容易懂。


    02


    WAV封装格式


    语音编码后,如果一个软件不支持该编码,则语音是无法解码的,因此,语音数据的播放,首先需要的是将编码数据解码。如上一部分中的SILK编码库,就是用来将语音的原始PCM数据编码为SILK编码数据,以及将SILK编码数据解码为PCM数据流的。


    各类通用的音视频播放器,对一个编码的支持,首先是根据文件名称后缀或者文件的内容进行封装格式识别,再根据封装格式中对编码的描述来进行编码的识别,如果编码被识别,并且集成了该编码库,则该编码的语音数据就可以被播放,也就是被支持了。


    在当前技术发展阶段,对音频播放器而言,WAV格式和MP3格式是最基本的封装格式,基本上都会被支持,WAV格式支持原始的音频流即PCM流,这是最简单的格式,只需要将所有语音编码数据解码保存,然后在文件头部加上WAV格式结构体,即可进行封装。


    当然,WAV格式缺点明显,其数据相当于未压缩,体积很大。


    WAV格式头共44字节,定义及描述如下:

    struct WAVHeader {     char Riff[4];     uint32 ChunkSize;     char Format[4];     char SubChunkID[4];     uint32 SubChunkSize;     uint16 AudioFormat;     uint16 NumChannels;     uint32 SampleRate;     uint32 ByteRate;     uint16 BlockAlign;     uint16 BitsPerSample;     char Data[4];     uint32 DataLen; };
    Riff:4字节,固定值“RIFF”。ChunkSize:4字节,整个文件不包含Riff及ChunkSize的8字节。Format:4字节,固定值“WAVE”。SubChunkID:4字节,固定值“fmt ”,注意最后1字节为空格0x20。SubChunkSize:4字节,对应WAV,值为0x10。AudioFormat:2字节,格式类型,线性PCM则值为1,其它值则为压缩的编码格式,如0x06为PCMA,0x07为PCMU。NumChannels:2字节,声道数,1或者2。SampleRate:4字节,采样频率,如11025,44100等。ByteRate:4字节,码率=采样频率*PCM采样位深/8*声道数。BlockAlign:2字节,采样一次占内存的长度=声道数*PCM采样位深/8。BitsPerSample:2字节,PCM采样位深,如8、16。Data:4字节,固定值“data”。DataLen:4字节,PCM数据总长度。

    一个典型的WAV头部数据如下:

    640?wx_fmt=png


    03


    SILK V3转换到WAV


    SILK编码到WAV的转换,当然要用到SILK编码库,供下载的SILK编码库内,提供了4个不同的平台版本,功能基本相同。


    在SILK编码库的SDK内,test目录下,有一个Decoder.c文件,是解码的示例文件,编译后它能够直接解码如下格式的SILK音频文件:

    640?wx_fmt=png

    如上图所示,SILK文件格式以"#!SILK_V3"开始,之后就是一帧帧的语音内容块,每帧的帧长占两字节,然后为帧内容,这是因为SILk编码是变长编码,每帧的长度是不同的。


    在各个test_vectorsitstream目录下的.bit文件,即为SILK格式文件,可以被解码程序Decoder.c支持。


    解码程序将SILK文件解码为PCM流文件,但缺少WAV头,无法直接用播放器播放。


    如果需要使解码后的PCM流能够播放,则需要PCM流前面添加WAV头。对微信语音短消息,WAV头赋值如下(pcmsize为PCM流的字节数):

    whead.DataLen = pcmsize;

    memcpy(whead.Riff,"RIFF",4);

    memcpy(whead.Format,"WAVE",4);

    memcpy(whead.SubChunkID,"fmt ",4);

    memcpy(whead.Data,"data",4);

    whead.ChunkSize =whead.DataLen+44-8;

    whead.SubChunkSize = 0x10;

    whead.AudioFormat = 1;

    whead.NumChannels = 1;

    whead.SampleRate = DecControl.API_sampleRate;

    whead.BitsPerSample = 16;

    whead.BlockAlign = whead.NumChannels*whead.BitsPerSample/8;

    whead.ByteRate = whead.SampleRate*whead.BlockAlign;


    其中NumChannels、SampleRate和BitsPerSample等参数需要根据具体情况进行填充,否则,声音会很怪异。


    对SILK编码转换为WAV语音文件,如果有疑惑,可以咨询我。


    640?wx_fmt=jpeg

    长按进行关注。





  • 相关阅读:
    《软件过程管理》阅读笔记3
    《软件过程管理》阅读笔记1
    《深度学习—智能时代的核心驱动力量》阅读笔记4
    《深度学习—智能时代的核心驱动力量》阅读笔记3
    《深度学习—智能时代的核心驱动力量》阅读笔记2
    《深度学习—智能时代的核心驱动力量》阅读笔记1
    软件杯赛题周总结(6)
    软件杯赛题周总结(5)
    esp32 arduino 蓝牙 使用uln2003 驱动四相五线步进电机备忘
    Oracle——在不安装oracle客户端的情况下,使用PLSQL
  • 原文地址:https://www.cnblogs.com/protosec/p/11673358.html
Copyright © 2011-2022 走看看