// opus_packet.mbt
//
// RFC 6716 §3:Opus 音频包的 TOC 解析与帧打包布局。
// 本模块只解析包的自描述结构(模式/带宽/帧时长/帧数/帧长/VBR/填充),
// 不触碰任何压缩系数;畸形包按 §3.4 摘要的 [R1]–[R7] 约束分类返回 Err,
// 调用方(解码器)据此丢弃或做丢包隐藏。
///|
/// 三种工作模式(RFC 6716 §3.1):SILK-only / Hybrid / CELT-only。
pub enum OpusMode {
Silk
Hybrid
Celt
}
///|
/// 五档音频带宽(RFC 6716 §3.1 Table 2):NB / MB / WB / SWB / FB。
pub enum OpusBandwidth {
Nb
Mb
Wb
Swb
Fb
}
///|
/// 解析后的 Opus 音频包结构。
pub struct OpusPacket {
config : Int
stereo : Bool
mode : OpusMode
bandwidth : OpusBandwidth
frame_samples : Int
frame_count : Int
frame_lengths : Array[Int]
is_vbr : Bool
padding_bytes : Int
}
///|
/// Table 2 帧时长换算到 48 kHz 采样数。
/// SILK-only(配置 0..11):10/20/40/60 ms → 480/960/1920/2880。
fn silk_frame_samples(i : Int) -> Int {
if i == 0 {
480
} else if i == 1 {
960
} else if i == 2 {
1920
} else {
2880
}
}
///|
/// CELT-only(配置 16..31):2.5/5/10/20 ms → 120/240/480/960。
fn celt_frame_samples(i : Int) -> Int {
if i == 0 {
120
} else if i == 1 {
240
} else if i == 2 {
480
} else {
960
}
}
///|
/// RFC 6716 §3.1 Table 2:配置号 → (模式, 带宽, 每帧 48 kHz 采样数)。
/// 同区间内的配置号按帧尺寸同序对应(如 0→10 ms、3→60 ms)。
fn opus_config_params(config : Int) -> (OpusMode, OpusBandwidth, Int) {
if config < 12 {
let bw = if config < 4 {
OpusBandwidth::Nb
} else if config < 8 {
OpusBandwidth::Mb
} else {
OpusBandwidth::Wb
}
(OpusMode::Silk, bw, silk_frame_samples(config % 4))
} else if config < 16 {
// Hybrid:12..13 SWB、14..15 FB,各只有 10/20 ms 两档
let bw = if config < 14 { OpusBandwidth::Swb } else { OpusBandwidth::Fb }
(OpusMode::Hybrid, bw, if config % 2 == 0 { 480 } else { 960 })
} else {
let bw = if config < 20 {
OpusBandwidth::Nb
} else if config < 24 {
OpusBandwidth::Wb
} else if config < 28 {
OpusBandwidth::Swb
} else {
OpusBandwidth::Fb
}
(OpusMode::Celt, bw, celt_frame_samples(config % 4))
}
}
///|
/// §3.2.1 帧长编码:0 → 零长帧(DTX);1..251 → 单字节;
/// 252..255 → 需第二字节,总长 = second*4 + first(最大 1275)。
/// 返回 (帧长, 消耗字节数);字节不足时返回 Err。
fn decode_frame_length(
data : Bytes,
pos : Int,
end : Int,
) -> Result[(Int, Int), String] {
if pos >= end {
return Err("truncated frame length")
}
let b1 = data.unsafe_get(pos).to_int()
if b1 < 252 {
return Ok((b1, 1))
}
if pos + 1 >= end {
return Err("frame length needs a second byte")
}
let b2 = data.unsafe_get(pos + 1).to_int()
Ok((b2 * 4 + b1, 2))
}
///|
/// 解析一个 Opus 音频包的结构(RFC 6716 §3.1–§3.2)。
///
/// 畸形包按 §3.4 的 [R1]–[R7] 约束拒绝:
/// * [R1] 至少 1 字节;
/// * [R2] 隐式/显式帧长不超过 1275 字节;
/// * [R3] code 1 包总长必须为奇数;
/// * [R4] code 2 首帧长字段完整且不超过剩余字节;
/// * [R5] code 3 至少 1 帧、总时长不超过 120 ms;
/// * [R6] code 3 CBR:≥2 字节、填充开销 P ≤ N-2、R 是 M 的整数倍;
/// * [R7] code 3 VBR:头部与显式帧长之和不超过包长。
pub fn parse_opus_packet(data : Bytes) -> Result[OpusPacket, String] {
let n = data.length()
if n == 0 {
return Err("malformed packet [R1]: empty packet")
}
let toc = data.unsafe_get(0).to_int()
let config = toc >> 3
let stereo = (toc & 4) != 0
let code = toc & 3
let (mode, bandwidth, frame_samples) = opus_config_params(config)
let frame_lengths : Array[Int] = []
let mut frame_count = 0
let mut is_vbr = false
let mut padding_bytes = 0
if code == 0 {
// §3.2.2:TOC 之后全部是唯一一帧的数据
if n - 1 > 1275 {
return Err("malformed packet [R2]: implicit frame exceeds 1275 bytes")
}
frame_count = 1
frame_lengths.push(n - 1)
} else if code == 1 {
// §3.2.3:[R3] N 必须为奇数,两帧各 (N-1)/2 字节
if n % 2 == 0 {
return Err("malformed packet [R3]: code 1 packet length must be odd")
}
let half = (n - 1) / 2
if half > 1275 {
return Err("malformed packet [R2]: implicit frame exceeds 1275 bytes")
}
frame_count = 2
frame_lengths.push(half)
frame_lengths.push(half)
} else if code == 2 {
// §3.2.4:[R4] 需足以解出首帧长,且首帧长不超过剩余字节
if n < 2 {
return Err(
"malformed packet [R4]: code 2 packet too short for a frame length",
)
}
let (n1, used) = match decode_frame_length(data, 1, n) {
Ok(v) => v
Err(e) => return Err("malformed packet [R4]: \{e}")
}
let rest = n - 1 - used
if n1 > rest {
return Err(
"malformed packet [R4]: first frame length exceeds remaining bytes",
)
}
let second = rest - n1
if second > 1275 {
return Err("malformed packet [R2]: implicit frame exceeds 1275 bytes")
}
frame_count = 2
frame_lengths.push(n1)
frame_lengths.push(second)
is_vbr = true
} else {
// §3.2.5:code 3 —— 帧数字节 (v|p|M) + 可选填充 + CBR/VBR 帧数据
if n < 2 {
return Err(
"malformed packet [R6]: code 3 packet needs a frame count byte",
)
}
let fcb = data.unsafe_get(1).to_int()
let vbr = (fcb & 1) != 0
let has_padding = (fcb & 2) != 0
let m = fcb >> 2
if m == 0 {
return Err("malformed packet [R5]: frame count must not be zero")
}
// [R5] 总时长 ≤ 120 ms = 5760 采样 @48 kHz
if m * frame_samples > 5760 {
return Err("malformed packet [R5]: packet longer than 120 ms")
}
let mut pos = 2
if has_padding {
if pos >= n {
return Err("malformed packet [R6]: missing padding length")
}
let first = data.unsafe_get(pos).to_int()
pos += 1
if first < 255 {
padding_bytes = first
} else {
if pos >= n {
return Err(
"malformed packet [R6]: missing second padding length byte",
)
}
padding_bytes = 254 + data.unsafe_get(pos).to_int()
pos += 1
}
// [R6] P = 填充长度头字节 + 尾部填充字节 ≤ N-2
if pos - 2 + padding_bytes > n - 2 {
return Err("malformed packet [R6]: padding exceeds packet bounds")
}
}
let content_end = n - padding_bytes
// 上面的 P ≤ N-2 已保证 content_end ≥ pos
if vbr {
// [R7] M-1 个显式帧长;总和不得超过解码后的剩余字节
let mut sum = 0
for _ in 1.. v
Err(e) => return Err("malformed packet [R7]: \{e}")
}
pos += used
sum += len
frame_lengths.push(len)
}
if sum > content_end - pos {
return Err(
"malformed packet [R7]: explicit frame lengths exceed packet",
)
}
// pos 此时越过的是长度字段区;前 M-1 帧的数据还要再占 sum 字节,
// 末帧吃掉填充之前的剩余全部(§3.2.5)
let last = content_end - pos - sum
if last > 1275 {
return Err("malformed packet [R2]: implicit frame exceeds 1275 bytes")
}
frame_lengths.push(last)
is_vbr = true
} else {
// [R6] R = N-2-P 必须是非负整数倍的 M(R ≥ 0 由 P ≤ N-2 保证)
let r = content_end - pos
if r % m != 0 {
return Err(
"malformed packet [R6]: CBR payload is not a multiple of the frame count",
)
}
let flen = r / m
if flen > 1275 {
return Err("malformed packet [R2]: implicit frame exceeds 1275 bytes")
}
for _ in 0.. Int {
self.config
}
///|
/// 立体声标志(TOC 的 s 位)。
pub fn OpusPacket::stereo(self : OpusPacket) -> Bool {
self.stereo
}
///|
/// 工作模式。
pub fn OpusPacket::mode(self : OpusPacket) -> OpusMode {
self.mode
}
///|
/// 音频带宽。
pub fn OpusPacket::bandwidth(self : OpusPacket) -> OpusBandwidth {
self.bandwidth
}
///|
/// 每帧时长(48 kHz 采样数;2.5 ms=120 … 60 ms=2880)。
pub fn OpusPacket::frame_samples(self : OpusPacket) -> Int {
self.frame_samples
}
///|
/// 包内帧数(code 0/1/2 为 1/2/2,code 3 为 M)。
pub fn OpusPacket::frame_count(self : OpusPacket) -> Int {
self.frame_count
}
///|
/// 第 `i` 帧的压缩字节长;越界返回 `None`。
pub fn OpusPacket::frame_length(self : OpusPacket, i : Int) -> Int? {
if i < 0 || i >= self.frame_lengths.length() {
None
} else {
Some(self.frame_lengths[i])
}
}
///|
/// 是否为变码率打包(code 2,或 code 3 的 v 位)。
pub fn OpusPacket::is_vbr(self : OpusPacket) -> Bool {
self.is_vbr
}
///|
/// Opus 层尾部填充字节数(无填充时为 0)。
pub fn OpusPacket::padding_bytes(self : OpusPacket) -> Int {
self.padding_bytes
}
///|
/// 包内音频总时长(48 kHz 采样数)。
pub fn OpusPacket::duration_48k(self : OpusPacket) -> Int {
self.frame_count * self.frame_samples
}