HYBRID-mode decode is not bit-exact vs libopus (SNR 18–54 dB; SILK-only path is bit-exact)
Summary
Differential testing against C libopus 1.6.1 on real speech shows that opus-rs 0.1.23 decodes HYBRID-mode (SWB/FB) packets approximately: after compensating a constant −3-sample offset (see "alignment" below), correlation with libopus output is 0.99–1.0 but SNR is only 18–54 dB, i.e. the output is audibly close but not conformance-grade. For comparison, the SILK-only path in the same build is bit-exact (infinite SNR) against libopus on identical source material, so the divergence appears to live in the CELT layer that hybrid frames add on top of SILK.
Environment
- opus-rs 0.1.23 (crates.io tarball, sha256
1cc978697f3ada0ad98b323b9d85e85c6b08d478830148636c19b6d5f2ac9b85, verified against the sparse index; used as a path dep with identical content)
- rustc 1.96.0, macOS aarch64 (Apple Silicon), release build
- ffmpeg 8.1.1 with libopus 1.6.1 (reference encoder + decoder)
- Source speech: Russian speech WAV (16 kHz mono), from the Golos corpus
Reproduction
-
Generate a hybrid-mode file (48 kHz mono 32 kbps maps almost entirely to hybrid packets):
ffmpeg -y -i speech.wav -c:a libopus -ar 48000 -ac 1 -b:a 32k hybrid.ogg
# reference decode with C libopus:
ffmpeg -y -c:a libopus -i hybrid.ogg -f f32le -acodec pcm_f32le -ar 48000 ref.f32
-
Decode the same packets with opus-rs (packets.bin = [u16le len][packet]… audio packets in stream order, extracted from the ogg with the ~15-line demuxer in "Reproduction assets" below; ref.f32 comes from the ffmpeg reference command above):
use opus_rs::OpusDecoder;
fn main() {
let a: Vec<String> = std::env::args().collect();
let raw = std::fs::read(&a[1]).unwrap(); // packets.bin
let refr: Vec<f32> = std::fs::read(&a[2]).unwrap() // ref.f32
.chunks_exact(4).map(|c| f32::from_le_bytes(c.try_into().unwrap())).collect();
let mut dec = OpusDecoder::new(48000, 1).unwrap();
let mut out: Vec<f32> = Vec::new();
let mut pos = 0;
while pos + 2 <= raw.len() {
let n = u16::from_le_bytes([raw[pos], raw[pos + 1]]) as usize;
pos += 2;
let pkt = &raw[pos..pos + n];
pos += n;
let mut buf = vec![0.0f32; 960]; // every packet here is 20 ms @ 48 kHz
let got = dec.decode(pkt, 960, &mut buf).unwrap();
out.extend_from_slice(&buf[..got]);
}
let out = &out[312..]; // OpusHead pre-skip
let n = out.len().min(refr.len());
let (mut dot, mut ex, mut ey, mut sx, mut sy) = (0f64, 0f64, 0f64, 0f64, 0f64);
for i in 0..n {
let (o, r) = (out[i] as f64, refr[i] as f64);
dot += o * r; ex += (o - r).powi(2); ey += r * r; sx += o * o; sy += r * r;
}
println!("corr={:.4} snr_db={:.1}", dot / (sx.sqrt() * sy.sqrt()), 10.0 * (ey / ex).log10());
}
-
Optionally compensate the constant −3-sample offset (opus-rs SILK/hybrid output leads libopus by 3 samples @ 48 kHz) before comparing — e.g. out = &out[..n-3]; refr = &refr[3..n];.
Expected vs actual
For a faithful port of libopus 1.6, decoding the same packets should be bit-identical (or within float rounding, SNR > 80 dB).
Actual on 4 different speech files (48 kHz mono 32 kbps, hybrid packets; opus-rs vs libopus 1.6.1):
| file |
corr raw |
SNR raw |
best lag |
corr@lag |
SNR@lag |
| golos_00 |
0.8936 |
6.7 dB |
−3 |
0.9997 |
31.8 dB |
| golos_01 |
0.9862 |
15.6 dB |
−3 |
1.0000 |
53.5 dB |
| golos_02 |
0.9883 |
16.3 dB |
−1 |
0.9921 |
18.0 dB |
| golos_03 |
0.9116 |
7.5 dB |
−3 |
0.9999 |
37.6 dB |
Fresh reproduction run (golos_00): samples=192000 corr=0.8936 snr_db=6.7 raw; corr=0.9997 SNR=31.8 dB at lag −3.
Control: SILK-only encodes of the same sources (16 kHz mono 24 kbps, 8 kHz mono 16 kbps) decode bit-exactly (infinite SNR at lag −3/−6), so the harness and alignment are sound — the gap is specific to the CELT layer inside hybrid frames.
Suspected root cause
SILK-only output is bit-exact, so the divergence is most likely in the CELT decoder path used for the high bands of hybrid frames (src/celt.rs, src/bands.rs, src/pvq.rs in 0.1.23) — e.g. PVQ/band-energy quantization or the final anti-collapse/comb-filter steps differing from libopus's float build. No single-line candidate identified; flagging the mode-specific conformance gap with a reproducer.
Impact
Any consumer decoding real-world Ogg/Opus (voice notes, music, WebRTC recordings at ≥ ~24 kbps) gets hybrid/CELT content; non-conformance-grade output means degraded (if only slightly) and unverifiable audio, and it blocks using opus-rs where bit-exact behavior vs libopus is required (transcoding pipelines, conformance testing, archival).
Related: #2/#3 ("Hybrid mode produces broken output", fixed) and #4 ("degraded audio quality", fixed) — as of 0.1.23 hybrid output is no longer broken, this issue tracks the remaining gap to bit-exactness.
Reproduction assets
Self-contained: the ffmpeg command above generates the input file; packets.bin and ref.f32 are derived from it with any Ogg demuxer. The exact extractor used for this report (~15 lines, Python):
import struct, sys
data = open(sys.argv[1], 'rb').read() # hybrid.ogg
out, pos, partial, n = open(sys.argv[2], 'wb'), 0, b'', 0
while True:
i = data.find(b'OggS', pos)
if i < 0 or i + 27 > len(data): break
nseg = data[i + 26]
segs = data[i + 27:i + 27 + nseg]
p = i + 27 + nseg
for s in segs:
partial += data[p:p + s]; p += s
if s < 255:
if n >= 2: # skip OpusHead / OpusTags
out.write(struct.pack('<H', len(partial))); out.write(partial)
n += 1; partial = b''
pos = p
(Pre-generated binary inputs — the .ogg, packets.bin, ref.f32 used for the numbers above — are kept as repro-01.zip; happy to attach or link them on request.)
HYBRID-mode decode is not bit-exact vs libopus (SNR 18–54 dB; SILK-only path is bit-exact)
Summary
Differential testing against C libopus 1.6.1 on real speech shows that opus-rs 0.1.23 decodes HYBRID-mode (SWB/FB) packets approximately: after compensating a constant −3-sample offset (see "alignment" below), correlation with libopus output is 0.99–1.0 but SNR is only 18–54 dB, i.e. the output is audibly close but not conformance-grade. For comparison, the SILK-only path in the same build is bit-exact (infinite SNR) against libopus on identical source material, so the divergence appears to live in the CELT layer that hybrid frames add on top of SILK.
Environment
1cc978697f3ada0ad98b323b9d85e85c6b08d478830148636c19b6d5f2ac9b85, verified against the sparse index; used as a path dep with identical content)Reproduction
Generate a hybrid-mode file (48 kHz mono 32 kbps maps almost entirely to hybrid packets):
ffmpeg -y -i speech.wav -c:a libopus -ar 48000 -ac 1 -b:a 32k hybrid.ogg # reference decode with C libopus: ffmpeg -y -c:a libopus -i hybrid.ogg -f f32le -acodec pcm_f32le -ar 48000 ref.f32Decode the same packets with opus-rs (
packets.bin=[u16le len][packet]…audio packets in stream order, extracted from the ogg with the ~15-line demuxer in "Reproduction assets" below;ref.f32comes from the ffmpeg reference command above):Optionally compensate the constant −3-sample offset (opus-rs SILK/hybrid output leads libopus by 3 samples @ 48 kHz) before comparing — e.g.
out = &out[..n-3]; refr = &refr[3..n];.Expected vs actual
For a faithful port of libopus 1.6, decoding the same packets should be bit-identical (or within float rounding, SNR > 80 dB).
Actual on 4 different speech files (48 kHz mono 32 kbps, hybrid packets; opus-rs vs libopus 1.6.1):
Fresh reproduction run (golos_00):
samples=192000 corr=0.8936 snr_db=6.7raw;corr=0.9997 SNR=31.8 dBat lag −3.Control: SILK-only encodes of the same sources (16 kHz mono 24 kbps, 8 kHz mono 16 kbps) decode bit-exactly (infinite SNR at lag −3/−6), so the harness and alignment are sound — the gap is specific to the CELT layer inside hybrid frames.
Suspected root cause
SILK-only output is bit-exact, so the divergence is most likely in the CELT decoder path used for the high bands of hybrid frames (
src/celt.rs,src/bands.rs,src/pvq.rsin 0.1.23) — e.g. PVQ/band-energy quantization or the final anti-collapse/comb-filter steps differing from libopus's float build. No single-line candidate identified; flagging the mode-specific conformance gap with a reproducer.Impact
Any consumer decoding real-world Ogg/Opus (voice notes, music, WebRTC recordings at ≥ ~24 kbps) gets hybrid/CELT content; non-conformance-grade output means degraded (if only slightly) and unverifiable audio, and it blocks using opus-rs where bit-exact behavior vs libopus is required (transcoding pipelines, conformance testing, archival).
Related: #2/#3 ("Hybrid mode produces broken output", fixed) and #4 ("degraded audio quality", fixed) — as of 0.1.23 hybrid output is no longer broken, this issue tracks the remaining gap to bit-exactness.
Reproduction assets
Self-contained: the ffmpeg command above generates the input file;
packets.binandref.f32are derived from it with any Ogg demuxer. The exact extractor used for this report (~15 lines, Python):(Pre-generated binary inputs — the
.ogg,packets.bin,ref.f32used for the numbers above — are kept asrepro-01.zip; happy to attach or link them on request.)