use crate::{Error, SampleRate};
use super::coding::compute_quantizer;
use super::rdovae_dec;
use super::{DRED_EXPERIMENTAL_BYTES, DRED_EXPERIMENTAL_VERSION, DRED_EXTENSION_ID, DRED_NUM_REDUNDANCY_FRAMES};
use crate::dnn::DnnBlob;
use crate::dnn::holder::DredDecoderDnn;
use crate::dnn::models::dred_rdovae_stats::{
DRED_LATENT_DIM, DRED_LATENT_P0_Q8, DRED_LATENT_QUANT_SCALES_Q8, DRED_LATENT_R_Q8, DRED_NUM_FEATURES,
DRED_STATE_DIM, DRED_STATE_P0_Q8, DRED_STATE_QUANT_SCALES_Q8, DRED_STATE_R_Q8,
};
use crate::extensions::ExtensionIterator;
use crate::packet;
use crate::range_coder::RangeCoder;
const FEC_FEATURES: usize = 2 * DRED_NUM_REDUNDANCY_FRAMES * DRED_NUM_FEATURES;
const LATENTS: usize = (DRED_NUM_REDUNDANCY_FRAMES / 2) * (DRED_LATENT_DIM + 1);
#[derive(Clone)]
pub struct OpusDred {
pub(crate) fec_features: [f32; FEC_FEATURES],
pub(crate) state: [f32; DRED_STATE_DIM],
pub(crate) latents: [f32; LATENTS],
pub(crate) nb_latents: i32,
pub(crate) process_stage: i32,
pub(crate) dred_offset: i32,
}
impl OpusDred {
pub fn new() -> Self {
OpusDred {
fec_features: [0.0; FEC_FEATURES],
state: [0.0; DRED_STATE_DIM],
latents: [0.0; LATENTS],
nb_latents: 0,
process_stage: -1,
dred_offset: 0,
}
}
pub fn nb_latents(&self) -> usize {
self.nb_latents.max(0) as usize
}
pub fn dred_offset(&self) -> i32 {
self.dred_offset
}
pub fn is_parsed(&self) -> bool {
self.process_stage == 1 || self.process_stage == 2
}
pub fn is_processed(&self) -> bool {
self.process_stage == 2
}
pub fn features(&self) -> &[f32] {
&self.fec_features[..4 * self.nb_latents() * DRED_NUM_FEATURES]
}
pub fn state(&self) -> &[f32; DRED_STATE_DIM] {
&self.state
}
pub fn latents(&self) -> &[f32] {
&self.latents[..self.nb_latents() * (DRED_LATENT_DIM + 1)]
}
}
impl Default for OpusDred {
fn default() -> Self {
OpusDred::new()
}
}
impl core::fmt::Debug for OpusDred {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("OpusDred")
.field("parsed", &self.is_parsed())
.field("processed", &self.is_processed())
.field("nb_latents", &self.nb_latents())
.field("dred_offset", &self.dred_offset)
.finish_non_exhaustive()
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
#[non_exhaustive]
pub struct DredParse {
pub samples: i32,
pub end: i32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum DredProcessing {
Now,
Deferred,
}
pub struct OpusDredDecoder {
dnn: DredDecoderDnn,
}
impl core::fmt::Debug for OpusDredDecoder {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("OpusDredDecoder").field("loaded", &self.is_loaded()).finish_non_exhaustive()
}
}
impl OpusDredDecoder {
pub fn new() -> Self {
OpusDredDecoder { dnn: DredDecoderDnn::new() }
}
pub fn set_dnn_blob(&mut self, blob: &DnnBlob) -> Result<crate::DnnModels, Error> {
self.dnn.load(blob)
}
pub fn is_loaded(&self) -> bool {
self.dnn.model().is_some()
}
pub fn parse(
&self,
dred: &mut OpusDred,
data: &[u8],
max_dred_samples: i32,
sampling_rate: SampleRate,
processing: DredProcessing,
) -> Result<DredParse, Error> {
if !self.is_loaded() {
return Err(Error::UNIMPLEMENTED);
}
dred.process_stage = -1;
let sampling_rate = sampling_rate.hz() as i32;
let Some((payload, dred_frame_offset)) = find_payload(data)? else {
return Ok(DredParse::default());
};
let offset = 100i32.wrapping_mul(max_dred_samples) / sampling_rate;
let min_feature_frames = 2i32.wrapping_add(offset).min(2 * DRED_NUM_REDUNDANCY_FRAMES as i32);
ec_decode(dred, payload, min_feature_frames, dred_frame_offset);
if processing == DredProcessing::Now {
self.process_in_place(dred)?;
}
let end = (-dred.dred_offset).wrapping_mul(sampling_rate) / 400;
let samples = (dred.nb_latents.wrapping_mul(sampling_rate) / 25)
.wrapping_sub(dred.dred_offset.wrapping_mul(sampling_rate) / 400);
Ok(DredParse { samples: samples.max(0), end: end.max(0) })
}
pub fn process_in_place(&self, dred: &mut OpusDred) -> Result<(), Error> {
if !dred.is_parsed() {
return Err(Error::BAD_ARG);
}
let Some(model) = self.dnn.model() else {
return Err(Error::UNIMPLEMENTED);
};
if dred.process_stage == 2 {
return Ok(());
}
rdovae_dec::decode_all(
model,
&mut dred.fec_features,
&dred.state,
&dred.latents,
dred.nb_latents.max(0) as usize,
self.dnn.arch(),
);
dred.process_stage = 2;
Ok(())
}
pub fn process(&self, src: &OpusDred, dst: &mut OpusDred) -> Result<(), Error> {
if !src.is_parsed() {
return Err(Error::BAD_ARG);
}
if !self.is_loaded() {
return Err(Error::UNIMPLEMENTED);
}
dst.clone_from(src);
self.process_in_place(dst)
}
}
impl Default for OpusDredDecoder {
fn default() -> Self {
OpusDredDecoder::new()
}
}
fn find_payload(data: &[u8]) -> Result<Option<(&[u8], i32)>, Error> {
let parsed = packet::parse(data, packet::Framing::Normal)?;
let frame_size = packet::samples_per_frame(parsed.toc(), SampleRate::Hz48000);
let mut iter = ExtensionIterator::new(parsed.padding(data), parsed.nb_frames());
while let Some(ext) = iter.find_id(DRED_EXTENSION_ID)? {
let dred_frame_offset = (ext.frame * frame_size / 120) as i32;
if ext.data.len() > DRED_EXPERIMENTAL_BYTES && ext.data[0] == b'D' && ext.data[1] == DRED_EXPERIMENTAL_VERSION {
return Ok(Some((&ext.data[DRED_EXPERIMENTAL_BYTES..], dred_frame_offset)));
}
}
Ok(None)
}
fn decode_latents(ec: &mut RangeCoder, x: &mut [f32], scale: &[u8], r: &[u8], p0: &[u8]) {
for (i, x) in x.iter_mut().enumerate() {
let q = if r[i] == 0 || p0[i] == 255 {
0
} else {
ec.laplace_decode_p0((p0[i] as u16) << 7, (r[i] as u16) << 7)
};
let s = if scale[i] == 0 { 1 } else { scale[i] };
*x = q as f32 * 256.0 / s as f32;
}
}
pub(crate) fn ec_decode(dred: &mut OpusDred, bytes: &[u8], min_feature_frames: i32, dred_frame_offset: i32) -> i32 {
let mut ec = RangeCoder::new_decoder(bytes);
let q0 = ec.dec_uint(16) as i32;
let dq = ec.dec_uint(8) as i32;
let extra_offset = if ec.dec_uint(2) != 0 { 32 * ec.dec_uint(256) as i32 } else { 0 };
dred.dred_offset = 16 - ec.dec_uint(32) as i32 - extra_offset + dred_frame_offset;
let mut qmax = 15;
if q0 < 14 && dq > 0 {
let nvals = 15 - (q0 + 1);
let ft = (2 * nvals) as u32;
let s = ec.decode(ft) as i32;
if s >= nvals {
qmax = q0 + (s - nvals) + 1;
ec.update(s as u32, s as u32 + 1, ft);
} else {
ec.update(0, nvals as u32, ft);
}
}
let state_qoffset = q0 as usize * DRED_STATE_DIM;
let state_tables = state_qoffset..state_qoffset + DRED_STATE_DIM;
decode_latents(
&mut ec,
&mut dred.state,
&DRED_STATE_QUANT_SCALES_Q8[state_tables.clone()],
&DRED_STATE_R_Q8[state_tables.clone()],
&DRED_STATE_P0_Q8[state_tables],
);
let total_bits = 8 * bytes.len() as i64;
let limit = (DRED_NUM_REDUNDANCY_FRAMES as i32).min((min_feature_frames.wrapping_add(1)) / 2);
let mut i = 0i32;
while i < limit {
if total_bits - ec.tell() as i64 <= 7 {
break;
}
let q_level = compute_quantizer(q0, dq as usize, qmax, i / 2);
let offset = q_level as usize * DRED_LATENT_DIM;
let tables = offset..offset + DRED_LATENT_DIM;
let base = (i / 2) as usize * (DRED_LATENT_DIM + 1);
decode_latents(
&mut ec,
&mut dred.latents[base..base + DRED_LATENT_DIM],
&DRED_LATENT_QUANT_SCALES_Q8[tables.clone()],
&DRED_LATENT_R_Q8[tables.clone()],
&DRED_LATENT_P0_Q8[tables],
);
dred.latents[base + DRED_LATENT_DIM] = (q_level as f64 * 0.125 - 1.0) as f32;
i += 2;
}
dred.process_stage = 1;
dred.nb_latents = i / 2;
i / 2
}