Skip to content

Commit

Permalink
opus: implement range decoder.
Browse files Browse the repository at this point in the history
  • Loading branch information
thinking-tower committed Mar 15, 2022
1 parent e1a7009 commit 2dac5c9
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 0 deletions.
45 changes: 45 additions & 0 deletions symphonia-codec-opus/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ use symphonia_core::formats::Packet;
use symphonia_core::io::{BufReader, ReadBytes};
use symphonia_core::support_codec;

mod range_decoder;
use range_decoder::RangeDecoder;

#[allow(dead_code)]
pub struct OpusDecoder {
ident_header: IdentificationHeader,
Expand All @@ -43,6 +46,21 @@ enum Mode {
Hybrid,
}

/// The bandwidth of the current audio packet.
/// See RFC 6716 Section 2 Table 1 and RFC 6716 Section 4.3 Table 55.
enum Bandwidth {
/// 4 kHz, index 12
NarrowBand,
/// 6 kHz, index 16
MediumBand,
/// 8 kHz, index 16
WideBand,
/// 12 kHz, index 18
SuperWideBand,
/// 20 kHz, index 20
FullBand,
}

impl Decoder for OpusDecoder {
fn try_new(params: &CodecParameters, _: &DecoderOptions) -> Result<Self> {
let extra_data = match params.extra_data.as_ref() {
Expand Down Expand Up @@ -82,9 +100,36 @@ impl Decoder for OpusDecoder {
16..=31 => Mode::Celt,
_ => unreachable!(),
};
let bandwidth = match config {
0..=3 => Bandwidth::NarrowBand,
4..=7 => Bandwidth::MediumBand,
8..=11 => Bandwidth::WideBand,
12..=13 => Bandwidth::SuperWideBand,
14..=15 => Bandwidth::FullBand,
16..=19 => Bandwidth::NarrowBand,
20..=23 => Bandwidth::WideBand,
24..=27 => Bandwidth::SuperWideBand,
28..=31 => Bandwidth::FullBand,
_ => unreachable!(),
};

let stereo_flag = toc & 0b00000100;
let frame_count_code = toc & 0b00000011;

// RFC 7845 state that samples are counted "assumming a 48 khz decoding rate".
// RFC 6716 record frame sizes in milliseconds.
// 48000Hz == 48000/(1second) == 48000/(1000millseconds) == 48/(1millisecond).
// See RFC 6716 Section 3.1 Table 2 and RFC 7845 Section 4.
let frame_size = match config {
0..=11 => [10 * 48, 20 * 48, 40 * 48, 60 * 48][(config % 4) as usize],
12..=15 => [10 * 48, 20 * 48][(config % 2) as usize],
// Separate 2.5 * 48 into 2 * 48 + 0.5 * 48 to avoid float and division.
16..=31 => [2 * 48 + 48 >> 1, 5 * 48, 10 * 48, 20 * 48][(config % 4) as usize],
_ => unreachable!(),
};

let mut range_decoder = RangeDecoder::try_new(&mut reader);

Ok(self.buffer.as_audio_buffer_ref())
}

Expand Down
104 changes: 104 additions & 0 deletions symphonia-codec-opus/src/range_decoder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Symphonia
// Copyright (c) 2019-2021 The Project Symphonia Developers.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

#![warn(rust_2018_idioms)]
#![forbid(unsafe_code)]
// The following lints are allowed in all Symphonia crates. Please see clippy.toml for their
// justification.
#![allow(clippy::comparison_chain)]
#![allow(clippy::excessive_precision)]
#![allow(clippy::identity_op)]
#![allow(clippy::manual_range_contains)]
// Disable to better express the specification.
#![allow(clippy::collapsible_else_if)]

use symphonia_core::errors::Result;
use symphonia_core::io::{BufReader, ReadBytes};

/// The range decoder for the Opus Decoder.
/// See RFC 6716 Section 4.1, https://tools.ietf.org/pdf/rfc7845.pdf.
pub struct RangeDecoder<'a> {
range: u32,
value: u32,
number_of_bits: u32,
reader: &'a mut BufReader<'a>,
previous_byte: u8,
}

impl RangeDecoder<'_> {
/// Create a new range decoder that reads from a `BufReader`.
/// See RFC 6716 Section 4.1.1.
pub fn try_new<'a>(reader: &'a mut BufReader<'a>) -> Result<RangeDecoder<'a>> {
let previous_byte = reader.read_byte()?;
let range = 128;
let value: u32 = 127u32 - u32::from(previous_byte >> 1);

// number_of_bits can also be initialised to 33 after the first renormalization.
// See RFC 6716 Section 4.1.6.
let mut range_decoder =
RangeDecoder { range, value, number_of_bits: 9, reader, previous_byte };
range_decoder.normalize();
Ok(range_decoder)
}

/// Decodes the current symbol given a frequency table and the sum of that frequency table.
/// See RFC 6716 Section 4.1.2.
fn decode_symbol(&mut self, symbol_frequencies: &[u32], total: u32) -> u32 {
use std::cmp;

// current_symbol_frequency == fs.
// lower_symbol_frequency_threshold = fl.
// higher_symbol_frequency_threshold = fh.
// index_of_current_symbol = k.
// See RFC 6716 Section 4.1.2 for more details on fs, fl, fh and k.
let current_symbol_frequency =
total - cmp::min(self.value / (self.range / total) + 1, total);
let mut lower_symbol_frequency_threshold = 0;
let mut higher_symbol_frequency_threshold = 0;
let mut index_of_current_symbol = 0;
for frequency in symbol_frequencies {
higher_symbol_frequency_threshold = lower_symbol_frequency_threshold + frequency;
if lower_symbol_frequency_threshold <= current_symbol_frequency
&& current_symbol_frequency < lower_symbol_frequency_threshold + frequency
{
break;
}
lower_symbol_frequency_threshold += frequency;
index_of_current_symbol += 1;
}

self.value = self.value - self.range / total * (total - higher_symbol_frequency_threshold);
if lower_symbol_frequency_threshold > 0 {
self.range = self.range / total
* (higher_symbol_frequency_threshold - lower_symbol_frequency_threshold);
}
else {
self.range =
self.range - self.range / total * (total - higher_symbol_frequency_threshold);
}

self.normalize();

index_of_current_symbol
}

// Normalizes the range decoder's range.
// See RFC 6716 Section 4.1.2.1.
fn normalize(&mut self) -> Result<()> {
while self.range <= (1 << 23) {
self.number_of_bits += 8;
self.range <<= 8;
let carry_bit = self.previous_byte & 1;
let current_byte = self.reader.read_byte()?;
self.value = ((self.value << 8)
+ u32::from(255 - (carry_bit << 7) | current_byte >> 1))
& 0x7FFFFFF;
self.previous_byte = current_byte;
}
Ok(())
}
}

0 comments on commit 2dac5c9

Please sign in to comment.