use std::{borrow::Cow, io, io::Write};
use log::trace;
use slice_group_by::GroupBy;
use vorbis_bitpack::{bitpacked_integer_width, BitpackWriter, BitpackedIntegerWidth};
use super::{
audio_packet_rewrite::AudioPacketRewrite, ilog, setup_header_parse::VorbisSetupData,
VorbisOptimizerError
};
use crate::vorbis::VectorLookupType;
pub(super) struct SetupHeaderRewrite {
pub(super) codec_setup: Option<VorbisSetupData>
}
impl SetupHeaderRewrite {
#[allow(clippy::type_complexity)]
pub(super) fn optimize_packet<'packet>(
&mut self,
mut packet: Cow<'packet, [u8]>
) -> Result<
(
Option<(Cow<'packet, [u8]>, Option<u16>)>,
Option<AudioPacketRewrite>
),
VorbisOptimizerError
> {
trace!("Optimizing setup header Vorbis packet");
let mut codec_setup = self.codec_setup.take().unwrap();
let packet_data = packet.to_mut();
packet_data.clear();
packet_data.push(5); packet_data.extend_from_slice(b"vorbis");
let mut bitpacker = optimize_and_write_codebooks(&mut codec_setup, packet_data)?;
bitpacker.write_unsigned_integer(0, bitpacked_integer_width!(6))?;
bitpacker.write_unsigned_integer(0, bitpacked_integer_width!(16))?;
write_floor_configurations(&codec_setup, &mut bitpacker)?;
write_residue_configurations(&codec_setup, &mut bitpacker)?;
write_mapping_configurations(&codec_setup, &mut bitpacker)?;
write_modes(&codec_setup, &mut bitpacker)?;
bitpacker.write_flag(true)?;
drop(bitpacker);
Ok((
Some((packet, None)),
Some(AudioPacketRewrite::new(codec_setup))
))
}
}
fn optimize_and_write_codebooks<W: Write>(
codec_setup: &mut VorbisSetupData,
mut packet_data: W
) -> Result<BitpackWriter<W>, io::Error> {
packet_data.write_all(&[(codec_setup.codebook_configurations.len() - 1) as u8])?;
let mut bitpacker = BitpackWriter::new(packet_data);
for codebook_configuration in &mut codec_setup.codebook_configurations {
bitpacker.write_unsigned_integer(0x564342, bitpacked_integer_width!(24))?;
bitpacker.write_unsigned_integer(
codebook_configuration.dimensions as u32,
bitpacked_integer_width!(16)
)?;
bitpacker.write_unsigned_integer(
codebook_configuration.entry_count,
bitpacked_integer_width!(24)
)?;
let optimal_codeword_lengths = codebook_configuration.codebook.optimal_codeword_lengths();
let mut has_unused_entries = optimal_codeword_lengths
.first()
.map(|first_entry_frequency| *first_entry_frequency == 0)
.unwrap_or(false);
let codeword_lengths_are_sorted = optimal_codeword_lengths.windows(2).fold(
true,
|cw_lengths_are_sorted, cw_length_window| {
has_unused_entries =
has_unused_entries || cw_length_window[0] == 0 || cw_length_window[1] == 0;
cw_lengths_are_sorted && cw_length_window[0] > cw_length_window[1]
}
);
let use_ordered_format = codeword_lengths_are_sorted
&& !has_unused_entries
&& !optimal_codeword_lengths.is_empty();
bitpacker.write_flag(use_ordered_format)?;
if use_ordered_format {
bitpacker.write_unsigned_integer(
(optimal_codeword_lengths[0] - 1) as u32,
bitpacked_integer_width!(5)
)?;
let mut processed_entries = 0;
for codeword_length_run in optimal_codeword_lengths.exponential_group() {
let entries_per_codeword_length = codeword_length_run.len();
bitpacker.write_unsigned_integer(
entries_per_codeword_length as u32,
BitpackedIntegerWidth::new(ilog(
codebook_configuration.entry_count as i32 - processed_entries
))
.unwrap()
)?;
processed_entries += entries_per_codeword_length as i32;
}
} else {
bitpacker.write_flag(has_unused_entries)?;
if has_unused_entries {
for codeword_length in optimal_codeword_lengths.iter().copied() {
let used_entry = codeword_length != 0;
bitpacker.write_flag(used_entry)?;
if used_entry {
bitpacker.write_unsigned_integer(
(codeword_length - 1) as u32,
bitpacked_integer_width!(5)
)?;
}
}
} else {
for codeword_length in optimal_codeword_lengths.iter().copied() {
bitpacker.write_unsigned_integer(
(codeword_length - 1) as u32,
bitpacked_integer_width!(5)
)?;
}
}
}
bitpacker.write_unsigned_integer(
codebook_configuration.vector_lookup_type as u32,
bitpacked_integer_width!(4)
)?;
if codebook_configuration.vector_lookup_type != VectorLookupType::NoLookup {
bitpacker.write_float32(codebook_configuration.codebook_vector_minimum_value)?;
bitpacker.write_float32(codebook_configuration.codebook_vector_delta_value)?;
bitpacker.write_unsigned_integer(
codebook_configuration.codebook_vector_value_bits as u32 - 1,
bitpacked_integer_width!(4)
)?;
bitpacker.write_flag(codebook_configuration.codebook_vector_sequence_flag)?;
let multiplicand_width =
BitpackedIntegerWidth::new(codebook_configuration.codebook_vector_value_bits)
.unwrap();
for multiplicand in codebook_configuration
.codebook_vector_multiplicands
.iter()
.copied()
{
bitpacker.write_unsigned_integer(multiplicand as u32, multiplicand_width)?;
}
}
}
Ok(bitpacker)
}
fn write_floor_configurations<W: Write>(
codec_setup: &VorbisSetupData,
bitpacker: &mut BitpackWriter<W>
) -> Result<(), io::Error> {
bitpacker.write_unsigned_integer(
codec_setup.floor_configurations.len() as u32 - 1,
bitpacked_integer_width!(6)
)?;
for floor_configuration in &codec_setup.floor_configurations {
bitpacker.write_unsigned_integer(1, bitpacked_integer_width!(16))?;
bitpacker.write_unsigned_integer(
floor_configuration.partition_class_list.len() as u32,
bitpacked_integer_width!(5)
)?;
for partition_class in floor_configuration
.partition_class_list
.iter()
.map(|class| *class as u32)
{
bitpacker.write_unsigned_integer(partition_class, bitpacked_integer_width!(4))?;
}
let class_configuration = floor_configuration
.class_dimensions
.iter()
.copied()
.zip(floor_configuration.class_subclasses.iter().copied())
.zip(floor_configuration.class_masterbooks.iter())
.zip(floor_configuration.subclass_books.iter());
for (((class_dimensions, class_subclasses), class_masterbooks), subclass_books) in
class_configuration
{
bitpacker
.write_unsigned_integer(class_dimensions as u32 - 1, bitpacked_integer_width!(3))?;
bitpacker
.write_unsigned_integer(class_subclasses as u32, bitpacked_integer_width!(2))?;
if let Some(codebook_number) = class_masterbooks {
bitpacker
.write_unsigned_integer(*codebook_number as u32, bitpacked_integer_width!(8))?;
}
for subclass_book in subclass_books {
bitpacker.write_unsigned_integer(
subclass_book.map_or(0, |book| book as u32 + 1),
bitpacked_integer_width!(8)
)?;
}
}
bitpacker.write_unsigned_integer(
floor_configuration.multiplier as u32 - 1,
bitpacked_integer_width!(2)
)?;
bitpacker.write_unsigned_integer(
floor_configuration.range_bits as u32,
bitpacked_integer_width!(4)
)?;
let range_bits_width = BitpackedIntegerWidth::new(floor_configuration.range_bits).unwrap();
for x_value in floor_configuration.x_list.iter().copied() {
bitpacker.write_unsigned_integer(x_value as u32, range_bits_width)?;
}
}
Ok(())
}
fn write_residue_configurations<W: Write>(
codec_setup: &VorbisSetupData,
bitpacker: &mut BitpackWriter<W>
) -> Result<(), io::Error> {
bitpacker.write_unsigned_integer(
codec_setup.residue_configurations.len() as u32 - 1,
bitpacked_integer_width!(6)
)?;
for residue_configuration in &codec_setup.residue_configurations {
bitpacker.write_unsigned_integer(
residue_configuration.residue_type as u32,
bitpacked_integer_width!(16)
)?;
bitpacker
.write_unsigned_integer(residue_configuration.begin, bitpacked_integer_width!(24))?;
bitpacker
.write_unsigned_integer(residue_configuration.end, bitpacked_integer_width!(24))?;
bitpacker.write_unsigned_integer(
residue_configuration.partition_size - 1,
bitpacked_integer_width!(24)
)?;
bitpacker.write_unsigned_integer(
residue_configuration.classifications as u32 - 1,
bitpacked_integer_width!(6)
)?;
bitpacker.write_unsigned_integer(
residue_configuration.classbook as u32,
bitpacked_integer_width!(8)
)?;
for books in &residue_configuration.books {
let mut mask = 0;
for (i, book) in books.iter().enumerate() {
mask |= (book.is_some() as u32) << i;
}
let high_mask_bits = (mask & 0xF8) >> 3;
let any_high_mask_bit_set = high_mask_bits != 0;
bitpacker.write_unsigned_integer(mask, bitpacked_integer_width!(3))?;
bitpacker.write_flag(any_high_mask_bit_set)?;
if any_high_mask_bit_set {
bitpacker.write_unsigned_integer(high_mask_bits, bitpacked_integer_width!(5))?;
}
}
for books in &residue_configuration.books {
for book in books.iter().filter_map(|book| *book) {
bitpacker.write_unsigned_integer(book as u32, bitpacked_integer_width!(8))?;
}
}
}
Ok(())
}
fn write_mapping_configurations<W: Write>(
codec_setup: &VorbisSetupData,
bitpacker: &mut BitpackWriter<W>
) -> Result<(), io::Error> {
bitpacker.write_unsigned_integer(
codec_setup.mapping_configurations.len() as u32 - 1,
bitpacked_integer_width!(6)
)?;
for mapping_configuration in &codec_setup.mapping_configurations {
bitpacker.write_unsigned_integer(0, bitpacked_integer_width!(16))?;
let mapping_submap_count =
mapping_configuration.floor_and_residue_mappings.len() as u32 - 1;
let mapping_submap_count_is_nonzero = mapping_submap_count != 0;
bitpacker.write_flag(mapping_submap_count_is_nonzero)?;
if mapping_submap_count_is_nonzero {
bitpacker.write_unsigned_integer(mapping_submap_count, bitpacked_integer_width!(4))?;
}
let channel_mappings_used = !mapping_configuration.channel_mappings.is_empty();
bitpacker.write_flag(channel_mappings_used)?;
if channel_mappings_used {
bitpacker.write_unsigned_integer(
mapping_configuration.channel_mappings.len() as u32 - 1,
bitpacked_integer_width!(8)
)?;
let audio_channels = mapping_configuration.mapping_mux.len();
let channel_index_width =
BitpackedIntegerWidth::new(ilog(audio_channels as i32 - 1)).unwrap();
for coupling_step in &mapping_configuration.channel_mappings {
bitpacker.write_unsigned_integer(
coupling_step.magnitude_channel as u32,
channel_index_width
)?;
bitpacker.write_unsigned_integer(
coupling_step.angle_channel as u32,
channel_index_width
)?;
}
}
bitpacker.write_unsigned_integer(0, bitpacked_integer_width!(2))?;
if mapping_submap_count > 0 {
for mux_submap in &mapping_configuration.mapping_mux {
bitpacker
.write_unsigned_integer(*mux_submap as u32, bitpacked_integer_width!(4))?;
}
}
for floor_and_residue_map in &mapping_configuration.floor_and_residue_mappings {
bitpacker.write_unsigned_integer(0, bitpacked_integer_width!(8))?;
bitpacker.write_unsigned_integer(
floor_and_residue_map.floor_number as u32,
bitpacked_integer_width!(8)
)?;
bitpacker.write_unsigned_integer(
floor_and_residue_map.residue_number as u32,
bitpacked_integer_width!(8)
)?;
}
}
Ok(())
}
fn write_modes<W: Write>(
codec_setup: &VorbisSetupData,
bitpacker: &mut BitpackWriter<W>
) -> Result<(), io::Error> {
bitpacker.write_unsigned_integer(
codec_setup.modes.len() as u32 - 1,
bitpacked_integer_width!(6)
)?;
for mode in &codec_setup.modes {
bitpacker.write_flag(mode.big_block)?;
bitpacker.write_unsigned_integer(0, bitpacked_integer_width!(16))?;
bitpacker.write_unsigned_integer(0, bitpacked_integer_width!(16))?;
bitpacker
.write_unsigned_integer(mode.mapping_number as u32, bitpacked_integer_width!(8))?;
}
Ok(())
}