use std::num::NonZero;
use symphonia_core::{
errors::Result,
io::{MediaSourceStream, ReadBytes as _},
};
use crate::{PacketInfo, endianness::Endianness, header::SetupHeader};
pub(crate) struct ChunkReader;
impl ChunkReader {
pub(crate) fn read(endianness: Endianness, mss: &mut MediaSourceStream<'_>) -> Result<Chunk> {
let chunk_type = mss.read_quad_bytes()?;
let size = endianness.u32(mss)?;
match &chunk_type {
b"fmt " => Ok(Chunk::Fmt(Fmt::read(endianness, mss)?)),
b"data" => Ok(Chunk::Data(mss.pos() + u64::from(size))),
b"hash" => {
Ok(Chunk::Hash)
}
_ => symphonia_core::errors::decode_error("wem: unrecognized chunk type"),
}
}
}
pub(crate) enum Chunk {
Fmt(Fmt),
Data(u64),
Hash,
}
pub(crate) struct Fmt {
pub(crate) channels: NonZero<u16>,
pub(crate) sample_rate: NonZero<u32>,
pub(crate) avg_bytes_per_second: u32,
pub(crate) setup_packet_offset: u32,
pub(crate) first_audio_packet_offset: u32,
pub(crate) block_size_0: u8,
pub(crate) block_size_1: u8,
}
impl Fmt {
pub(crate) fn packet_info(&self, setup: &SetupHeader, last_offset: u64) -> PacketInfo {
PacketInfo {
last_offset,
block_size_0: self.block_size_0,
block_size_1: self.block_size_1,
mode_bits: setup.mode_bits as usize,
num_modes: u8::try_from(setup.mode_block_flags.len())
.expect("Block flags out of range"),
modes_block_flags: setup.mode_block_flags,
}
}
fn read(endianness: Endianness, mss: &mut MediaSourceStream<'_>) -> Result<Self> {
let pos = mss.pos();
let codec_id = mss.read_double_bytes()?;
if codec_id != [0xFF, 0xFF] {
return symphonia_core::errors::decode_error(
"wem: missing or wrong codec ID in format chunk",
);
}
let channels = endianness.non_zero_u16(mss)?;
let sample_rate = endianness.non_zero_u32(mss)?;
let avg_bytes_per_second = endianness.u32(mss)?;
let _block_align = endianness.u16(mss)?;
let _bits_per_sample = endianness.u16(mss)?;
mss.ignore_bytes(0x18 - (mss.pos() - pos))?;
let _sample_count = endianness.u32(mss)?;
let _mod_signal = endianness.u32(mss)?;
mss.ignore_bytes((0x18 + 0x10) - (mss.pos() - pos))?;
let setup_packet_offset = endianness.u32(mss)?;
let first_audio_packet_offset = endianness.u32(mss)?;
mss.ignore_bytes((0x18 + 0x24) - (mss.pos() - pos))?;
let _uid = endianness.u32(mss)?;
let block_size_0 = mss.read_u8()?;
let block_size_1 = mss.read_u8()?;
Ok(Self {
channels,
sample_rate,
avg_bytes_per_second,
setup_packet_offset,
first_audio_packet_offset,
block_size_0,
block_size_1,
})
}
}