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编码状态:
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解码状态:
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型)