4  命令行编码器/解码器

        Speex最基本的是命令行编码器(speexenc)和解码器(speexdec)。这些工具产生并读取封装在Ogg容器内的Speex文件。尽管能在任意容器内封装Speex,但Ogg是文件命令行容器。这一部分介绍如何在Ogg中为Speex文件使用命令行工具。

4.1  speexenc

        speexenc的作用是从未加工的PCM文件或wave文件生成Speex文件。可通过如下调用:

                speexenc [options] input_file output_file

        input_file或output_file的‘-’值分别对应标准输入和标准输出。有效的选项有:

                -narrowband(-n)   告诉Speex默认将输入视为窄带(8kHz)

                -wideband(-n)  告诉Speex将输入视为宽带(16kHz)

                -ultra-wideband(-u)  告诉Speex将输入视为超宽带(32kHz)

                -quality n  设置编码质量(0-10),默认为8

                -bitrate n  编码比特率(比特率将小于等于n)

                -vbr n  启用VBR(可变比特率),默认禁用

                -abr n  启用ABR(平均比特率)为n kbps,默认禁用

                -vad  启用VAD(声音活动检测),默认禁用

                -dtx  启用DTX(断续传输),默认禁用

                -nrames n  每个Ogg数据包包含n帧(这在低比特率时能节省空间)

                -comp n  设置编码速度和质量的折中,n值越大,编码速度越慢(默认为3)

                -V    详细的操作,输出所使用的比特率

                -help(-h)  输出帮助

                -version(-v)  输出版本信息

        Speex注释

                -comment  增加给定的字符串为额外的注释,这可能花费几倍时间

                -author  声道作者

                -title  声道标题

        原始输入选项

                -rate n  原始输入的采样率

                -stereo  将原始输入视为立体声

                -le  原始输入为小头(little-endian,高位字节放在高地址单元)

                -be  原始输入为大头(big-endian,高位字节放在低地址单元)

                -8bit  原始输入为8位无符号数

                -16bit  原始输入为16位有符号数

4.2  speexdec 

        speexdec用于解码Speex文件,可通过如下调用

                speexdec [options] speex_file [output_file]

        input_file或output_file的值‘-’分别对应标准输入和标准输出。若没有指定output_file,则文件通过声卡播放。有效的选项有:

                -enh  启用后置滤波(默认)

                -no-enh  禁用后置滤波

                -force-nb  强制窄带解码

                -force-wb  强制宽带解码

                -force-uwb  强制超宽带解码

                -mono 强制单声道解码

                -stereo  强制立体声解码

                -rate n  强制解码采样率为n Hz

                -packet-loss n  模拟n%随机包丢失

                -V  详细操作,输出使用的比特率

                -help(-h)  输出帮助

               -version(-v)  输出版本信息

5  Speex编解码器API(libspeex)

        libspeex库包含所有使用Speex编解码器对语音编码和解码的函数。若在UNIX系统中链接,需要在编译器命令行中加入-lspeex -lm。注意libspeex的调用时可重入的,但不是线程安全的。这意味着可以在多个线程中条用,但多个线程间对同一状态的调用需要互斥锁保护。代码示例参见附录A,完整的API文档可在Speex网站的文档部分找到(http://www.speex.org/)。

5.1 编码

        在用Speex编码语音之前,首先需要包括头文件:

                #include <speex/speex.h>

        然后在代码中,必须声明一个Speex位封装结构和一个Speex编码状态:

                SpeexBits bits;

                void *enc_state;

       然后需要两个初始化:

                speex_bits_init(&bits);

                enc_state = speex_encoder_init(&speex_nb_mode);

对于宽带编码,speex_nb_mode替换为speex_wb_mode。大多数情况下,你需要知道所使用采样率的帧长,可通过变量frame_size获得(单位是样本数,而不是字节):

                speex_encoder_ctl(enc_state,SPEEX_GET_FRAME_SIZE,&frame_size);

实际应用中,当用8,16或32kHz采样率是frame_size通常为20ms。Speex编码器可设置许多参数,但最有用的是控制质量和比特率折中的质量参数:

                speex_encoder_ctl(enc_state,SPEEX_SET_QUALITY,&quality);

其中quality是一个0到10之间的整数(包含10)。图9.2描述了窄带时质量和比特率之间的关系。

        初始化之后1,对于每一输入帧:

                speex_bits_reset(&bits);

                speex_encode_int(enc_state,input_frame,&bits);

                nbBytes = speex_bits_write(&bits,byte_ptr,MAX_NB_BYTES);

其中input_fram是一个short *指针,只想一个语音帧的开始位置;byte_ptr是一个char *指针,指向将被写的已编码帧;MAX_NB_BYTES是在无溢出情况下能写到byte_ptr的最大字节数;nbBytes是实际写到byte_pte的字节数(已经编码的字节数)。在调用speex_bits_wrtie之前,可通过调用speex_bits_nbytes(&bits)获得需要被写的字节数,返回这一字节数。

        也可以使用speex_encode()函数,返回一个指向音频的float *指针。然而这将使得没有FPU的平台(如ARM)最后端口更难懂。在内部,speex_encode()和speex_encode_int()是以相同的方式处理的。编码器是否使用定点版本仅由编译时间标志决定,而不是API级别。

       在完成编码之后,释放资源:

                speex_bits_destroy(&bits);

                speex_encode_deatroy(enc_state);

        以上是编码器部分。

5.2  解码器

        在用Speex解码语音之前,首先需要头文件:

                #include <speex/speex.h>

        你也需要声明一个Speex位封装结构和一个Speex解码状态:

                SpeexBitsbits;

                void * dec_state;

        然后进行初始化:

                speex_bits_init(&bits);

                dec_state = speex_decoder_int(&speex_nb_mode);

对于宽带解码,speex_nb_mode替换为speex_wb_mode。若需要获得解码器将使用的帧大小,可通过变量frame_size(单位是样本数,而不是字节数)获得:

                speex_decoder_ctl(dec_state,SPEEX_GET_FRAME_SIZE,&frame_size);

         解码器同样有一个参数可以设置:是否启用知觉增强:

                speex_decoder_ctl(dec_state,SPEEX_SET_ENH,&enh);

其中enh初始化为0则禁用知觉增强,值为1则启用。对于1.2-beta 1版本,默认启用知觉增强。

         解码初始化后,对每一输入帧:

                 speex_bits_read_from(&bits,input_bytes,nbBytes);

                 speex_decode_int(dec_state,&bits,output_frame);

其中input_bytes是一个包含一帧接收到的比特流数据的char *指针;nbBytes是比特流的大小(字节);output_frame是一个short*型指针,指向解码语音将被写入的区域。若第二个参数值为NULL,则表明当前帧没有比特。当有一帧丢失时,Speex解码器将尽量“猜测”正确的信号。

         跟编码器一样,speex_decode()函数也可以使用,返回一个指向输出音频的float*型指针。在完成解码后,要释放资源:

                  speex_bits_destroy(&bits);

                  speex_decoder_destrpy(dec_state);

5.3  编解码器选项(speex_*_ctl)

        Speex编码器和解码器支持许多选项,可通过speex_encoder_ctl和speex_decoder_ctl函数设置。这些函数类似于输入输出系统函数调用,他们的原型是:

                void speex_encoder_ctl(void *encoder,int request,void *ptr);

                void speex_decoder_ctl(void *decoder,int request,void *ptr);

        尽管有许多设置函数,但是对于许多应用默认设置一般足够,仅当使用者理解了这些设置并需要时才需设置选项。一个常见错误是设置了许多没必要的设置。

        以下是一个允许请求设置值得列表,其中一些仅适用于编码器或解码器。由于最后一个参数是void *型的,所以_ctl()函数不是类型安全的,需要小心使用。类型spx_int32_t同等于C99中的类型int32_t。

                SPEEX_SET_ENH:设置知觉增强为开(1)或关(2)(spx_int32_t型,默认为开,仅用于解码器)

                SPEEX_GET_ENH:获取知觉增强状态(spx_int32_t型,仅用于解码器)

                SPEEX_GET_FRAME_SIZE:获取当前模式下每帧的样本数(spx_int32_t型)

                SPEEX_SET_QUALITY:设置编码器语音质量(spx_int32_t型,从0到10,默认为8,仅用于编码器)

                SPEEX_GET_QUALITY:获取当前编码器语音质量(spz_int32_t型,从0到10,仅用于编码器)

                SPEEX_SET_MODE:设置模型数字,同RTP规格里指定(spx_int32_t型,仅用于编码器)

                SPEEX_GET_MODE:获取当前模型数字,同RTP规格里指定(spx_int32_t型,仅用于编码器)

                SPEEX_SET_VBR:设置变比特率(VBR)为开(1)或关(0)(spx_int32_t型,默认为关,仅用于编码器)

                SPEEX_GET_VBR:获取变比特率(VBR)状态(spx_int32_t型,仅用于编码器)

                SPEEX_SET_VBR_QUALITY:设置编码器VBR语音质量(浮点型,从0.0到10.0,默认为8.0,仅用于编码器)

                SPEEX_GET_VBR_QUALITY:获取当前编码器VBR语音质量(浮点型,从0.0到10.0,仅用于编码器)

                SPEEX_SET_COMPLEXITY:设置分配给编码器的CPU资源(spx_int32_t型,从1到10,默认为2,仅用于编码器)

                SPEEX_GEY_COMPLEXITY:获取分配给编码器的CPU资源(spx_int32_t型,从1到10,默认为2,仅用于编码器)

                SPEEX_SET_BITRATE:设置比特率为不超过参数的最近整数值(SPX_INT32_t型,单位比特每秒,仅用于编码器)

                SPEEX_GET_BITRATE:获取当前比特率(spx_int32_t型,单位比特每秒,仅用于编码器)

                SPEEX_SET_SAMPLING_RATE:设置实际采样率(spx_int32_t型,单位Hz)

                SPEEX_GET_SAMPLING_RATE:获取实际采样率(spx_int32_t型,单位Hz)

                SPEEX_RESET_STATE:重置编码器/解码器状态为初始状态,清空所有内存(不推荐)

                SPEEX_SET_VAD:设置声音活动检测(VAD)为开(1)或关(0)(spx_int32_t型,默认为关,仅用于编码器)

                SPEEX_GET_VAD:获取声音活动检测(VAD)状态(spx_int32_t型,仅用于编码器)

                SPEEX_SET_DTX:设置断续传输(DTX)为开(1)或关(0)(spx_int32_t型,默认为关,仅用于编码器)

                SPEEX_GET_DTX:获取断续传输(DTX)状态(spx_int32_t型,仅用于编码器)

                SPEEX_SET_ABR:设置平均比特率(ABR)为n(spx_int32_t型,单位比特每秒,仅用于编码器)

                SPEEX_GET_ABR:获取平均比特率(ABR)设置(spx_int32_t型,单位比特每秒,仅用于编码器)

                SPEEX_SET_PLC_TUNING:告诉编码器对一个包丢失百分比进行优化编码(spx_int32_t型,百分数,仅用于编码器)

                SPEEX_GET_PLC_TUNING:获取PLC编码的当前调谐(spx_int32_t型,百分数,仅用于编码器)

                SPEEX_SET_VBR_MAX_BITRATE:设置VBR操作中允许的最大比特率(spx_int32_t型,单位比特每秒,仅用于编码器)

                SPEEX_GET_VBR_MAX_BITRATE:获取当前VBR操作中允许的最大比特率(spx_int32_t型,单位比特每秒,仅用于编码器)

                SPEEX_SET_HIGHPASS:设置高通滤波器为开(1)或关(0)(spx_int32_t型,默认为开)

                SPEEX_GET_HIGHPASS:获取当前高通滤波器状态(spx_int32_t型)


Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐