1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
use std::io::Cursor;
use std::marker::PhantomData;
use std::mem;
use byteorder::{BigEndian, ByteOrder, LittleEndian, WriteBytesExt};
use claxon::frame::FrameReader;
use crate::cdrom::{CD_FRAME_SIZE, CD_MAX_SECTOR_DATA, CD_MAX_SUBCODE_DATA};
use crate::compression::zlib::ZlibCodec;
use crate::compression::{
CodecImplementation, CompressionCodec, CompressionCodecType, DecompressResult,
};
use crate::error::{Error, Result};
use crate::header::CodecType;
/// Generic block decoder for FLAC.
///
/// Defaults assume 2 channel interleaved FLAC.
/// The byte order determines the endianness of the output data.
struct FlacCodec<T: ByteOrder, const CHANNELS: usize = 2> {
buffer: Vec<i32>,
_byteorder: PhantomData<T>,
}
impl<T: ByteOrder, const CHANNELS: usize> CodecImplementation for FlacCodec<T, CHANNELS> {
fn new(hunk_bytes: u32) -> Result<Self>
where
Self: Sized,
{
if hunk_bytes % (CHANNELS * mem::size_of::<i16>()) as u32 != 0 {
return Err(Error::CodecError);
}
Ok(FlacCodec {
buffer: Vec::new(),
_byteorder: PhantomData::default(),
})
}
fn decompress(&mut self, input: &[u8], output: &mut [u8]) -> Result<DecompressResult> {
let comp_buf = Cursor::new(input);
// Number of samples to write to the buffer.
let sample_len = output.len() / (CHANNELS * mem::size_of::<i16>());
// We don't need to create a fake header since claxon will read raw FLAC frames just fine.
// We just need to be careful not to read past the number of blocks in the input buffer.
let mut frame_read = FrameReader::new(comp_buf);
let mut cursor = Cursor::new(output);
// Buffer to hold decompressed FLAC block data.
let mut block_buf = mem::take(&mut self.buffer);
// A little bit of a misnomer. 1 'sample' refers to a sample for all channels.
let mut samples_written = 0;
while samples_written < sample_len {
// Loop through all blocks until we have enough samples written.
match frame_read.read_next_or_eof(block_buf) {
Ok(Some(block)) => {
// We assume 2 channels (by default), so we can use claxon's stereo_samples
// iterator for slightly better performance.
#[cfg(not(feature = "nonstandard_channel_count"))]
for (l, r) in block.stereo_samples() {
cursor.write_i16::<T>(l as i16)?;
cursor.write_i16::<T>(r as i16)?;
samples_written += 1;
}
// This is generic over number of assumed channels, but is broken effectively
// for any value other than 2.
// What we really want here is specialization for CHANNELS = 2 ...
#[cfg(feature = "nonstandard_channel_count")]
for sample in 0..block.len() / block.channels() {
for channel in 0..block.channels() {
let sample_data = block.sample(channel, sample) as u16;
cursor.write_i16::<T>(sample_data as i16)?;
}
samples_written += 1;
}
block_buf = block.into_buffer();
}
_ => {
// If frame_read dies our buffer just gets eaten. The Error return for a failed
// read does not expose the inner buffer.
return Err(Error::DecompressionError);
}
}
}
self.buffer = block_buf;
let bytes_in = frame_read.into_inner().position();
Ok(DecompressResult::new(
samples_written * 4,
bytes_in as usize,
))
}
}
/// Raw FLAC (flac) decompression codec.
///
/// ## Format details
/// Raw FLAC expects the first byte as either 'L' (0x4C) or 'B' (0x42) to indicate the endianness
/// of the output data, followed by the compressed FLAC data.
///
/// FLAC compressed audio data is assumed to be 2-channel 16-bit signed integer PCM.
/// The audio data is decompressed in interleaved format, with the left channel first, then
/// the right channel for each sample, for 32 bits each sample.
///
/// ## Buffer Restrictions
/// Each compressed FLAC hunk decompresses to a hunk-sized chunk.
/// The input buffer must contain enough samples to fill the hunk-sized output buffer.
pub struct RawFlacCodec {
be: FlacCodec<BigEndian>,
le: FlacCodec<LittleEndian>,
}
impl CompressionCodec for RawFlacCodec {}
impl CompressionCodecType for RawFlacCodec {
fn codec_type(&self) -> CodecType
where
Self: Sized,
{
CodecType::FlacV5
}
}
impl CodecImplementation for RawFlacCodec {
fn new(hunk_bytes: u32) -> Result<Self> {
Ok(RawFlacCodec {
be: FlacCodec::new(hunk_bytes)?,
le: FlacCodec::new(hunk_bytes)?,
})
}
fn decompress(&mut self, input: &[u8], output: &mut [u8]) -> Result<DecompressResult> {
match input[0] {
b'L' => self.le.decompress(&input[1..], output),
b'B' => self.be.decompress(&input[1..], output),
_ => Err(Error::DecompressionError),
}
}
}
/// CD-ROM wrapper decompression codec (cdfl) using the FLAC
/// for decompression of sector data and the [Deflate codec](crate::codecs::ZlibCodec) for
/// decompression of subcode data.
///
/// ## Format Details
/// FLAC compressed audio data is assumed to be 2-channel 16-bit signed integer PCM.
/// The audio data is decompressed in interleaved format, with the left channel first, then
/// the right channel for each sample, for 32 bits each sample.
///
/// CD-ROM wrapped FLAC is always written to the output stream in big-endian byte order.
///
/// CD-ROM compressed hunks have a layout with all compressed frame data in sequential order,
/// followed by compressed subcode data.
///
/// ```c
/// [Frame0, Frame1, ..., FrameN, Subcode0, Subcode1, ..., SubcodeN]
/// ```
/// Unlike CDLZ or CDZL, there is no header before the compressed data begins.
/// The length of the compressed data is determined by the number of 2448-sized frames
/// that can fit into the hunk-sized output buffer. Following the FLAC compressed blocks,
/// the subcode data is a single Deflate stream.
///
/// After decompression, the data is swizzled so that each frame is followed by its corresponding
/// subcode data.
/// ```c
/// [Frame0, Subcode0, Frame1, Subcode1, ..., FrameN, SubcodeN]
/// ```
/// FLAC compressed frames does not require manual reconstruction of the sync header or ECC bytes.
///
/// ## Buffer Restrictions
/// Each compressed CDFL hunk decompresses to a hunk-sized chunk. The hunk size must be a multiple
/// of 2448, the size of each CD frame. The input buffer must contain enough samples to fill
/// the number of CD sectors that can fit into the output buffer.
pub struct CdFlacCodec {
// cdfl always writes in big endian.
engine: FlacCodec<BigEndian>,
sub_engine: ZlibCodec,
buffer: Vec<u8>,
}
impl CompressionCodec for CdFlacCodec {}
impl CompressionCodecType for CdFlacCodec {
fn codec_type(&self) -> CodecType {
CodecType::FlacCdV5
}
}
impl CodecImplementation for CdFlacCodec {
fn new(hunk_size: u32) -> Result<Self>
where
Self: Sized,
{
if hunk_size % CD_FRAME_SIZE != 0 {
return Err(Error::CodecError);
}
// The size of the FLAC data in each cdfl hunk, excluding the subcode data.
let max_frames = hunk_size / CD_FRAME_SIZE;
let flac_data_size = max_frames * CD_MAX_SECTOR_DATA;
// neither FlacCodec nor ZlibCodec actually make use of hunk_size.
Ok(CdFlacCodec {
engine: FlacCodec::new(flac_data_size)?,
sub_engine: ZlibCodec::new(hunk_size)?,
buffer: vec![0u8; hunk_size as usize],
})
}
fn decompress(&mut self, input: &[u8], output: &mut [u8]) -> Result<DecompressResult> {
let total_frames = output.len() / CD_FRAME_SIZE as usize;
let frame_res = self.engine.decompress(
input,
&mut self.buffer[..total_frames * CD_MAX_SECTOR_DATA as usize],
)?;
#[cfg(feature = "want_subcode")]
let sub_res = self.sub_engine.decompress(
&input[frame_res.total_in()..],
&mut self.buffer[total_frames * CD_MAX_SECTOR_DATA as usize..]
[..total_frames * CD_MAX_SUBCODE_DATA as usize],
)?;
#[cfg(not(feature = "want_subcode"))]
let sub_res = DecompressResult::default();
// Decompressed FLAC data has layout
// [Frame0, Frame1, ..., FrameN, Subcode0, Subcode1, ..., SubcodeN]
// We need to reassemble the data to be
// [Frame0, Subcode0, Frame1, Subcode1, ..., FrameN, SubcodeN]
// Reassemble frame data to expected layout.
for (frame_num, chunk) in self.buffer[..total_frames * CD_MAX_SECTOR_DATA as usize]
.chunks_exact(CD_MAX_SECTOR_DATA as usize)
.enumerate()
{
output[frame_num * CD_FRAME_SIZE as usize..][..CD_MAX_SECTOR_DATA as usize]
.copy_from_slice(chunk);
}
// Reassemble subcode data to expected layout.
#[cfg(feature = "want_subcode")]
for (frame_num, chunk) in self.buffer[total_frames * CD_MAX_SECTOR_DATA as usize..]
.chunks_exact(CD_MAX_SUBCODE_DATA as usize)
.enumerate()
{
output[frame_num * CD_FRAME_SIZE as usize + CD_MAX_SECTOR_DATA as usize..]
[..CD_MAX_SUBCODE_DATA as usize]
.copy_from_slice(chunk);
}
Ok(frame_res + sub_res)
}
}