音频格式解码之opus

📅 2026/6/26 22:45:19
音频格式解码之opus
opus是一种有损编码格式与Vorbis同率属于Xiph.Org基金会并且也进行了标准化。当前opus不仅取代了Vorbis还成为了webrtc的标准音频格式。opus也基于oggogg的介绍请参考音频格式之OGG-CSDN博客 本文主要介绍opus格式。一、opus 在ogg中的格式1.1 opus ogg 流Page 0 Pages 1 ... n Pages (n1) ... ------------ --- --- ... --- ----------- --------- -- | | | | | | | | | | | | | |----------| |-----------------| |------------------- ----- |||ID Header|| || Comment Header || ||Audio Data Packet 1| | ... |----------| |-----------------| |------------------- ----- | | | | | | | | | | | | | ------------ --- --- ... --- ----------- --------- -- ^ ^ ^ | | | | | Mandatory Page Break | | | ID header is contained on a single page | Beginning Of Streamopus的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 7845Ogg 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 文件标识OpusHeadVersion8版本 固定为1Channel Count8声道数Pre-skip16无预跳过Input Sample Rate32采样率这是原始输入编码前的采样率单位为赫兹。这个字段并不是用于播放编码数据的采样率。Output Gain16增益调整sample * pow(10, output_gain/(20.0*256))Mapping Family8标准立体声无映射表Channel Mapping TableNMapping Family 0时才有从编码流到输出通道的映射1channel count这是输出通道的数量。这可能与编码通道的数量不同编码通道数量可能会在每个数据包中变化。这个值不能为零。最大允许值取决于通道映射类型并可能大到 2552Pre-skip这是在开始播放时需要从解码器输出丢弃的样本数48 kHz同时也是计算页面 PCM 样本位置时需要从页面颗粒位置中减去的数值。在裁剪已有的 Ogg Opus 流的开头时建议预跳至少 3,840 个样本80 毫秒以确保解码器完全收敛。3Input Sample Rate这是原始输入的采样率编码前单位是赫兹。这个字段_不是_用于播放编码后数据的采样率。Opus 可以在 4、6、8、12 和 20 kHz 的内部音频带宽之间切换。流中的每个数据包可以有不同的音频带宽。无论音频带宽如何参考解码器都支持以 8、12、16、24 或 48 kHz 的采样率解码任何流。传递给编码器的音频的原始采样率不会通过有损压缩被保留。4Output Gain这是在解码时要应用的增益。它是将解码器输出缩放到期望播放音量的因子的 20*log10 值以 16 位有符号二进制补码定点值存储带有 8 位小数Q-表示法5Mapping Family家族值定义家族值名称说明0默认映射单声道或立体声无映射表1环绕声映射支持多通道环绕声格式2Ambisonics支持 Ambisonics 格式家族 0默认映射最简单的映射方式无需显式映射表输出通道数 CStream Count NCoupled Count M通道含义11默认0默认单声道21默认1默认立体声左、右家族 1环绕声映射支持标准环绕声配置通道数配置名称通道顺序3立体声 低频效果 (LFE)FL, FR, LFE4四声道FL, FR, BL, BR55.0FL, FR, FC, BL, BR65.1FL, FR, FC, LFE, BL, BR76.1FL, FR, FC, LFE, BL, BR, BC87.1FL, FR, FC, LFE, BL, BR, SL, SR6Channel Mapping TableChannel 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值范围含义0到2M-1立体声流的通道偶数左奇数右2M到MN-1单声道流的通道255静音通道Mapping Family决定通道语义单声道/立体声/环绕声/AmbisonicsStream Count (N)和Coupled Count (M)定义编码流结构Channel Mapping Table定义从解码通道到输出通道的映射关系支持灵活的通道配置和静音通道处理1.3 Comment Header0 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 | -------------------------------- : :字段位值举例说明Magic64OpusTags标识Vendor Length320x0000000C 12Vendor 字符串长度Vendor StringNLibOpus 1.4Vendor Length决定长度编码器信息Comment Count320x00000002 2Comment 的数量决定后面Comment Block的数量Comment 0 Length320x0000000C 12第一个评论长度Comment 0NTITLE听妈妈的话标题Comment 1 Length320x0000000E 14第二个评论长度Comment 1NARTIST周杰伦艺术家这个主要储存相关记录信息 具体可以参考“标准元数据标签” 介绍TITLE/ARTIST/DATE等 元数据。 本章节不赘述这些元数据都是通用格式。二opus格式opus音频数据的格式对应OGG中 audio data packetogg打包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.1TOC字节 1字节根据opus源码解析TOC 字节是 Opus 包的第一个字节包含了关键的编码参数TOC 8位格式 0 1 2 3 4 5 6 7 -------------------------------- | frame Count | channels | bandwidth | mode --------------------------------位字段含义7-5mode编码模式0SILK, 1HYBRID, 2CELT, 3保留4-3bandwidth带宽 与模式共同计算如2channels通道数0单声道, 1立体声1-0frame_count帧数量指示符1frame_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; }2bandwidt 音频带宽带宽的解析取决于编码模式如 SILK 模式Mode 0值带宽名称频率范围0Narrowband (NB)4 kHz1Mediumband (MB)6 kHz2Wideband (WB)8 kHz3Superwideband (SWB)12 kHz3mode 编码模式值模式名称说明0SILK_ONLY纯 SILK 模式适用于语音1HYBRID混合模式同时使用 SILK 和 CELT2CELT_ONLY纯 CELT 模式适用于音乐3保留未使用2.2 解码流程┌─────────────────────┐ │ 输入 Opus 数据包 │ └──────────┬──────────┘ │ ┌──────────▼──────────┐ │ 读取 TOC 字节 │ │ (解析 Mode/BW/C/F) │ └──────────┬──────────┘ │ ┌──────────▼──────────┐ │ 判断帧结构类型 │ │ (F0/1/2/3) │ └──────────┬──────────┘ │ ┌──────────────────────┼──────────────────────┐ ▼ ▼ ▼ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ F0 │ │ F1/2 │ │ F3 │ │ 单帧 │ │ 双帧 │ │ 多帧 │ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ │ │ ▼ ▼ ▼ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ 直接解码 │ │ 解析大小 │ │ 解析帧头 │ │ 单帧 │ │ 后解码 │ │ 大小 │ └──────────┘ └──────────┘ └────┬─────┘ │ ▼ ┌──────────┐ │ 解码所有帧│ └──────────┘帧的长度通过ogg等容器格式获取就是这整个opus packet包的大小opus-packet size -1 len;2.2.1 单帧模式F0这种结构最简单整个剩余数据就是一帧数据。只需要解码这一帧就好。Single Frame Packet ┌─────────────────┐ │ TOC (1 byte) │ │ Audio Data len-1 │ └─────────────────┘2.2.2 双帧 CBR 模式F1两帧大小相等无需显式编码 两个帧的长度分别占总长度的一半Two CBR Frames Packet ┌─────────────────────────┐ │ TOC (1 byte) │ │ Frame 1 Data │ │ Frame 2 Data │ (大小 (len-1) / 2)两帧等长无显式大小信息 └─────────────────────────┘2.2.3 双帧 VBR 模式F2Two 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 多帧模式F3Multi-Frame Packet ┌────────────────────────────────────────┐ │ TOC (1 byte) │ │ Frame Info (1 byte) │ │ - bits 0-5: 帧数量 N │ │ - bit 6: 填充标志 │ │ - bit 7: CBR/VBR标志 (0VBR) │ │ 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标志 (0VBR)2.2.5 扩展数据ExtensionsOpus 包末尾可以包含扩展数据如 LBRR低比特率冗余和 DRED解码器冗余扩展类型ID类型说明0填充无意义填充字节1帧分隔符标记帧边界2重复指示符后续帧重复相同扩展3-31短扩展载荷长度 0-1 字节32-127长扩展载荷长度可变