初识 Speex 语音压缩

本文介绍了Speex,一种用于网络电话和在线广播的声音编码格式,强调其与Opus的区别,以及在JNI中的实现。Speex是基于CELP的有损格式,尽管已被Opus取代,但仍然适用于临时解决方案。
摘要由CSDN通过智能技术生成

初识 Speex 语音压缩

Speex 简介

Speex 是一个声音编码格式,目标是用于网络电话、在线广播使用的语音编码,基于 CELP(一种语音编码算法)开发,Speex 宣称可以免费使用,以 BSD 授权条款开放源代码。

Speex 的开发者将这个格式视为 Vorbis(通用音频压缩格式)的补充。

Speex 是一种有损格式,这意味着使用此格式的音频,质量将会永久性地降低以减少文件的大小。

开发 Speex 的 Xiph.org 基金会已经宣布废弃 Speex,建议改用 Opus 取代。

Speex 是针对网际协议通话技术(VoIP)和基于文件的压缩。Speex 的设计目标是开发一个保有高质量语音的同时降低其比特率(bit rate)的编码器。 为了实现前述目标,Speex 编码器使用多位比特率(multiple bit rates),并支持超宽频 (32 kHz 采样率),宽带 (16 kHz 采样率) 和窄带 (电话通话质量,8 kHz 采样率)。 由于 Speex 是设计用于 VoIP 而不是手机,因此 Speex 编码器必须能容忍丢失数据包(lost packets),但不能数据包是损坏的。基于上述的要求,选择 CELP 算法作为 Speex 的编码技术。使用 CELP 的主要原因之一是,CELP 早已证明,它可以同时做到低比特率和高比特率。

Speex 的主要特性归纳如下:

  • 自由软件 / 开源,无专利保护且使用无需版税。
  • 集窄带和宽带在同一比特流(bit-stream)。
  • 比特率可选择的范围很广 (从 2 kbit/s 至 44 kbit/s)。
  • 动态交换的比特率和可变比特率 (VBR, variable bit-rate)。
  • 语音动态的检测 (VAD,与 VBR 集成)(1.2 版开始废弃)。

Speex 性能

目前只测了部分压缩的性能(设备:一加3T【高通骁龙821】)

Speex 性能(一加3T)

Speex 与 Opus

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

Opus 集成了两种声音编码的技术:以语音编码为导向的 SILK 和低延迟的 CELT。Opus 可以无缝调节高低 比特率。在编码器内部它在较低比特率时使用线性预测编码在高比特率时候使用变换编码(在高低比特率交界处也使用两者结合的编码方式)。Opus 具有非常低的算法延迟(默认为 22.5 ms)[3],非常适合用于低延迟语音通话的编码,像是网络上的即时声音流、即时同步声音旁白等等,此外 Opus 也可以透过降低编码比特率,达成更低的算法延迟,最低可以到 5 ms。在多个听觉盲测中,Opus 都比 MP3、AAC、HE-AAC 等常见格式,有更低的延迟和更好的声音压缩率。

比较不同声音编码格式的比特率、采样率与延迟性

Opus 与其他流行音频格式之间的编码效率比较

所以,临时用用可以考虑 Speex。如果要正式上线,还是考虑使用 Opus

Speex 的 JNI 实现

Speex 代码可以从 Speex 官网 下载,目前最新版本为 v1.2.0 (可能以后都不会更新了)

Speex 源码是 C 语音版本的。

自己使用的时候,加了一套 API 方便调用。

// speex_codec.h
#include "speex/speex.h"

namespace speex {
   
    class SpeexCodec {
   
    public:
        enum CodecMode {
   
            ENCODE,         // 编码,压缩
            DECODE,         // 解码,解压
        };

        enum Quality {
   
            // [1 - 15]
            QUALITY_START,
            QUALITY_1,  QUALITY_2,  QUALITY_3,  QUALITY_4,  QUALITY_5,
            QUALITY_6,  QUALITY_7,  QUALITY_8,  QUALITY_9,  QUALITY_10,
            QUALITY_11, QUALITY_12, QUALITY_13, QUALITY_14, QUALITY_15,
            QUALITY_END,
        };

        enum Complexity {
   
            // [1 - 8]
            COMPLEXITY_START,
            COMPLEXITY_1, COMPLEXITY_2, COMPLEXITY_3, COMPLEXITY_4,
            COMPLEXITY_5, COMPLEXITY_6, COMPLEXITY_7, COMPLEXITY_8,
            COMPLEXITY_END,
        };

        enum ModeId {
   
            MODEID_NB  = SPEEX_MODEID_NB,   // narrowband 窄宽带模式
            MODEID_WB  = SPEEX_MODEID_WB,   // wideband 宽带模式
            MODEID_UWB = SPEEX_MODEID_UWB,  // wideband 超宽带模式
        };

        SpeexCodec(CodecMode  codecMode,
                   int        decSize,
                   int        encSize,
                   Quality    quality,
                   Complexity complexity,
                   ModeId     modeId);
        ~SpeexCodec();

        int encode(short * dec, int decSize, int * useDecSize, char * enc);
        int decode(char * enc, int encSize, int * useEncSize, short * dec);
        void reset();

        CodecMode  getCodecMode();
        Quality    getQuality();
        Complexity getComplexity();
        ModeId     getModeId();
        int        getDecSize();
        int        getEncSize();

    private:
        SpeexCodec(){
   }
        SpeexCodec(const SpeexCodec&){
   }
        SpeexCodec(const SpeexCodec&&){
   }
        SpeexCodec& operator = (const SpeexCodec&){
    return *this; }

        CodecMode  mCodecMode;
        Quality    mQuality;
        Complexity mComplexity;
        ModeId     mModeId;
        int        mDecSize;
        int        mEncSize;
        void *     mState;
        SpeexBits  mBits;
    };
}
// speex_codec.cpp
#include "speex_codec.h"

namespace speex {
   
    SpeexCodec::SpeexCodec(CodecMode  codecMode,
                           int        decSize,
                           int        encSize,
                           Quality    quality,
                           Complexity complexity,
                           ModeId     modeId) {
   
        this->mCodecMode  = codecMode;
        this->mDecSize    = decSize;
        this->mEncSize    = encSize;
        this->mQuality    = quality;
        this->mComplexity = complexity;
        this->mModeId     = modeId;

        if ((this
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值