当前位置: 首页 > news >正文

音频格式解码之opus

opus是一种有损编码格式,与Vorbis同率属于Xiph.Org基金会,并且也进行了标准化。当前opus不仅取代了Vorbis,还成为了webrtc的标准音频格式。opus也基于ogg,ogg的介绍请参考音频格式之OGG-CSDN博客 , 本文主要介绍opus格式。

一、opus 在ogg中的格式

1.1 opus ogg 流

Page 0 Pages 1 ... n Pages (n+1) ... +------------+ +---+ +---+ ... +---+ +-----------+ +---------+ +-- | | | | | | | | | | | | | |+----------+| |+-----------------+| |+-------------------+ +----- |||ID Header|| || Comment Header || ||Audio Data Packet 1| | ... |+----------+| |+-----------------+| |+-------------------+ +----- | | | | | | | | | | | | | +------------+ +---+ +---+ ... +---+ +-----------+ +---------+ +-- ^ ^ ^ | | | | | Mandatory Page Break | | | ID header is contained on a single page | 'Beginning Of Stream'

opus的ogg流,主要由ID Header、 Comment Header和AudioData Packet组成,

ID Header:是 Ogg Opus 文件格式的第一个数据包,用于唯一标识一个流为 Opus 音频。它包含了解码 Opus 音频所需的基本元数据。

Comment Header:是 Ogg Opus 文件格式的第二个必需数据包,包含用户提供的元数据信息。它采用与 Ogg Vorbis 评论头相同的格式(但没有 Vorbis 规范中规定的最终"帧位")。

Audio Data Packet:是 Ogg Opus 流中包含实际音频数据的数据包。在 ID Header 和 Comment Header 之后,所有后续的页面都包含音频数据。

1.2ID Header

根据 RFC 7845(Ogg Opus Encapsulation)规范,ID Header 的二进制结构如下:

0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 'O' | 'p' | 'u' | 's' | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 'H' | 'e' | 'a' | 'd' | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Version = 1 | Channel Count | Pre-skip | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Input Sample Rate (Hz) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Output Gain (Q7.8 in dB) | Mapping Family| | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ : | | : Optional Channel Mapping Table... : | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

1.2.1 属性介绍

字段含义
Magic64Opus 文件标识"OpusHead"
Version8版本 ,固定为1
Channel Count8声道数
Pre-skip16无预跳过
Input Sample Rate32采样率,这是原始输入(编码前)的采样率,单位为赫兹。这个字段并不是用于播放编码数据的采样率。
Output Gain16增益调整,

sample *= pow(10, output_gain/(20.0*256))

Mapping Family8标准立体声(无映射表)

Channel Mapping Table

NMapping Family > 0时才有,从编码流到输出通道的映射

1,channel count

这是输出通道的数量。这可能与编码通道的数量不同,编码通道数量可能会在每个数据包中变化。这个值不能为零。最大允许值取决于通道映射类型,并可能大到 255

2,Pre-skip

这是在开始播放时需要从解码器输出丢弃的样本数(48 kHz),同时也是计算页面 PCM 样本位置时需要从页面颗粒位置中减去的数值。在裁剪已有的 Ogg Opus 流的开头时,建议预跳至少 3,840 个样本(80 毫秒),以确保解码器完全收敛。

3,Input Sample Rate

这是原始输入的采样率(编码前),单位是赫兹。这个字段_不是_用于播放编码后数据的采样率。

Opus 可以在 4、6、8、12 和 20 kHz 的内部音频带宽之间切换。流中的每个数据包可以有不同的音频带宽。无论音频带宽如何,参考解码器都支持以 8、12、16、24 或 48 kHz 的采样率解码任何流。传递给编码器的音频的原始采样率不会通过有损压缩被保留。

4,Output Gain

这是在解码时要应用的增益。它是将解码器输出缩放到期望播放音量的因子的 20*log10 值,以 16 位有符号二进制补码定点值存储,带有 8 位小数(Q-表示法)

5,Mapping Family

家族值定义

家族值名称说明
0默认映射单声道或立体声,无映射表
1环绕声映射支持多通道环绕声格式
2Ambisonics支持 Ambisonics 格式

家族 0(默认映射)

最简单的映射方式,无需显式映射表:

输出通道数 CStream Count NCoupled Count M通道含义
11(默认)0(默认)单声道
21(默认)1(默认)立体声(左、右)

家族 1(环绕声映射)

支持标准环绕声配置:

通道数配置名称通道顺序
3立体声 + 低频效果 (LFE)FL, FR, LFE
4四声道FL, FR, BL, BR
55.0FL, FR, FC, BL, BR
65.1FL, FR, FC, LFE, BL, BR
76.1FL, FR, FC, LFE, BL, BR, BC
87.1FL, FR, FC, LFE, BL, BR, SL, SR

6,Channel Mapping Table

Channel Mapping Table 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+ | Stream Count | N +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Coupled Count | Channel Mapping... : M + C bytes +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
字段大小说明
Stream Count (N)1 字节编码流总数
Coupled Count (M)1 字节立体声流数量(前 M 个流为立体声)
Channel MappingC 字节输出通道到解码通道的映射表
Channel Mapping值范围含义
02M-1立体声流的通道(偶数=左,奇数=右)
2MM+N-1单声道流的通道
255静音通道
  • Mapping Family决定通道语义(单声道/立体声/环绕声/Ambisonics)
  • Stream Count (N)Coupled Count (M)定义编码流结构
  • Channel Mapping Table定义从解码通道到输出通道的映射关系
  • 支持灵活的通道配置和静音通道处理

1.3 Comment Header

0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 'O' | 'p' | 'u' | 's' | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 'T' | 'a' | 'g' | 's' | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Vendor String Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | : Vendor String... : | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | User Comment List Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | User Comment #0 String Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | : User Comment #0 String... : | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | User Comment #1 String Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ : :
字段值举例说明
Magic64"OpusTags"标识
Vendor Length320x0000000C = 12Vendor 字符串长度
Vendor StringN"LibOpus 1.4"Vendor Length决定长度,编码器信息
Comment Count320x00000002 = 2Comment 的数量,决定后面Comment Block的数量
Comment 0 Length320x0000000C = 12第一个评论长度
Comment 0N"TITLE=听妈妈的话"标题
Comment 1 Length320x0000000E = 14第二个评论长度
Comment 1N"ARTIST=周杰伦"艺术家:

这个主要储存相关记录信息, 具体可以参考“标准元数据标签” 介绍TITLE/ARTIST/DATE等 元数据。 本章节不赘述,这些元数据都是通用格式。

二,opus格式

opus音频数据的格式,对应OGG中 audio data packet,ogg打包opus的音频数据。opus包的大小在内部没有存储,因此需要外部封装的容器存储,或者自己扩展一个opus packet的长度字节。

Opus Packet Structure ┌──────────────────────────────────────────────────────────────────────┐ │ TOC Byte │ Frame Size(s) │ Audio Data │ Extensions │ │ (1 byte) │ (0-2 bytes) │ (variable) │ (可选) │ └──────────────────────────────────────────────────────────────────────┘ │ │ │ │ ▼ ▼ ▼ ▼ 编码模式/带宽 帧大小信息 压缩音频数据 LBRR/DRED等 /通道数/帧数 (VBR模式) 扩展数据

2.1,TOC字节 1字节(根据opus源码解析)

TOC 字节是 Opus 包的第一个字节,包含了关键的编码参数

TOC 8位格式 0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | frame Count | channels | bandwidth | mode +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
字段含义
7-5mode编码模式(0=SILK, 1=HYBRID, 2=CELT, 3=保留)
4-3bandwidth带宽 与模式共同计算如
2channels通道数(0=单声道, 1=立体声)
1-0frame_count帧数量指示符

1,frame_count(帧数量指示)

switch (toc & 0x3) { case 0: // 00: 1个帧 count = 1; break; case 1: // 01: 2个CBR帧 count = 2; cbr = 1; break; case 2: // 10: 2个VBR帧 count = 2; // 需要解析帧大小 break; case 3: // 11: 多个帧(0-120ms) // 第二个字节包含帧数和标志 break; }

2,bandwidt 音频带宽

带宽的解析取决于编码模式:

如: SILK 模式(Mode = 0):

带宽名称频率范围
0Narrowband (NB)4 kHz
1Mediumband (MB)6 kHz
2Wideband (WB)8 kHz
3Superwideband (SWB)12 kHz

3,mode 编码模式

模式名称说明
0SILK_ONLY纯 SILK 模式,适用于语音
1HYBRID混合模式,同时使用 SILK 和 CELT
2CELT_ONLY纯 CELT 模式,适用于音乐
3保留未使用

2.2, 解码流程

┌─────────────────────┐ │ 输入 Opus 数据包 │ └──────────┬──────────┘ │ ┌──────────▼──────────┐ │ 读取 TOC 字节 │ │ (解析 Mode/BW/C/F) │ └──────────┬──────────┘ │ ┌──────────▼──────────┐ │ 判断帧结构类型 │ │ (F=0/1/2/3) │ └──────────┬──────────┘ │ ┌──────────────────────┼──────────────────────┐ ▼ ▼ ▼ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ F=0 │ │ F=1/2 │ │ F=3 │ │ 单帧 │ │ 双帧 │ │ 多帧 │ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ │ │ ▼ ▼ ▼ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ 直接解码 │ │ 解析大小 │ │ 解析帧头 │ │ 单帧 │ │ 后解码 │ │ +大小 │ └──────────┘ └──────────┘ └────┬─────┘ │ ▼ ┌──────────┐ │ 解码所有帧│ └──────────┘

帧的长度通过,ogg等容器格式获取,就是这整个opus packet包的大小;

opus-packet size -1 = len;

2.2.1 单帧模式(F=0)

这种结构最简单,整个剩余数据就是一帧数据。只需要解码这一帧就好。

Single Frame Packet ┌─────────────────┐ │ TOC (1 byte) │ │ Audio Data len-1 │ └─────────────────┘

2.2.2 双帧 CBR 模式(F=1)

两帧大小相等,无需显式编码, 两个帧的长度分别占总长度的一半;

Two CBR Frames Packet ┌─────────────────────────┐ │ TOC (1 byte) │ │ Frame 1 Data │ │ Frame 2 Data │ (大小 = (len-1) / 2)两帧等长,无显式大小信息: └─────────────────────────┘

2.2.3 双帧 VBR 模式(F=2)

Two VBR Frames Packet ┌─────────────────────────┐ │ TOC (1 byte) │ │ Size 1 (1-2 bytes) │ │ Frame 1 Data 第一帧大小通过计算获取 │ │ Frame 2 Data │ (大小 = 剩余长度) └─────────────────────────┘

第一帧大小显式编码,第二帧占剩余空间,Opus 使用可变长度编码(VLE)来表示帧大小,第一帧的计算公式为:

static int parse_size(const unsigned char *data, opus_int32 len, opus_int16 *size) { if (len < 1) { *size = -1; return -1; } else if (data[0] < 252) { // 单字节编码:0-251 *size = data[0]; return 1; } else if (len < 2) { *size = -1; return -1; } else { // 双字节编码:252-1275 *size = 4 * data[1] + data[0]; return 2; } }
范围编码方式字节数
0-251直接编码1 字节
252-12754 * data[1] + data[0]2 字节

2.2.4 多帧模式(F=3)

Multi-Frame Packet ┌────────────────────────────────────────┐ │ TOC (1 byte) │ │ Frame Info (1 byte) │ │ - bits 0-5: 帧数量 N │ │ - bit 6: 填充标志 │ │ - bit 7: CBR/VBR标志 (0=VBR) │ │ Padding Bytes (if padded) │ │ Size 1 (VBR only, 1-2 bytes) │ │ ... │ │ Size N-1 (VBR only, 1-2 bytes) │ │ Frame 1 Data │ │ ... │ │ Frame N Data │ │ Extensions (可选) len -以上所有字节 │ └────────────────────────────────────────┘

1 Frame Info

这种模式新增了一个Frame Info, 用于获取帧数量,和帧格式标志。

Frame Info (1 byte) │ │ - bits 0-5: 帧数量 N │ │ - bit 6: 填充标志 │ │ - bit 7: CBR/VBR标志 (0=VBR)

2.2.5 扩展数据(Extensions)

Opus 包末尾可以包含扩展数据,如 LBRR(低比特率冗余)和 DRED(解码器冗余):

扩展类型

ID类型说明
0填充无意义填充字节
1帧分隔符标记帧边界
2重复指示符后续帧重复相同扩展
3-31短扩展载荷长度 0-1 字节
32-127长扩展载荷长度可变
http://www.jsqmd.com/news/1084140/

相关文章:

  • 泉州市柱状活性炭报价
  • chemdraw软件安装步骤(附安装包)ChemDraw 2023 超详细下载安装教程
  • 信安毕设最新课题指导
  • k6:写代码一样做性能测试
  • 孤能子视角:同AI分角色对话试验
  • Cesium 夜间教程
  • 无人值守道闸怎么选?对比设备免费送方案优劣
  • Java基础(11) | JVM 基础:内存结构、类加载与垃圾回收
  • 太原街道岗亭
  • SQL注入漏洞复现:从手工测试到自动化利用的实战指南
  • GCGR靶点深度解析:从糖代谢枢纽到多靶点代谢治疗的关键协同受体
  • LÖVE:用 Lua 写 2D 游戏的开源框架
  • ComfyUI-Impact-Pack V8:解决AI图像细节模糊的5大核心技术方案
  • Adobe-GenP 3.0终极指南:5步快速免费激活Adobe全家桶
  • 超维空间镜像 打造营区全场景物理空间透明化数智中枢 技术解析白皮书
  • 【第二部分】STM32CubeMX 创建 STM32F103CBT6 完整标准流程
  • 基于Fisher-Kolmogorov方程与几何简化的大脑疾病蛋白传播动力学建模
  • 开源网盘直链下载助手完整指南:告别限速困扰
  • 四川设备搬迁找他们,真的能省心又高效吗?
  • 化工厂跨厂区设备无线通信物联网方案
  • 开源4G GPS定位器开发与优化实践
  • 文艺复兴元素服饰库存周转测算程序,判断复古艺术款最优生产备货量。
  • 带你认识NSE
  • 【2026】超详细Maple 2025安装保姆级教程,数学代数系统环境配置和使用指南,看完这一篇就够了
  • Serverless 架构与自动化发布流水线:从冷启动优化到 GitOps 的工程实战
  • 2026填志愿用的资料,我帮你打包好了,直接拿
  • IPXWrapper实战指南:让经典游戏在Win10/11重获联机生命
  • 客户服务AI智能体采用率飙升:70%组织60天见成效,新定价模式加速企业应用
  • 3步精准定位:Windows热键冲突终极侦探工具揭秘
  • 如何零成本解锁Grammarly Premium:终极免费使用指南