symphonia-core-0.5.4/.cargo_vcs_info.json0000644000000001540000000000100137770ustar { "git": { "sha1": "d3b7742fa73674b70d9ab80cc5f8384cc653df3a" }, "path_in_vcs": "symphonia-core" }symphonia-core-0.5.4/Cargo.toml0000644000000027320000000000100120010ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" rust-version = "1.53" name = "symphonia-core" version = "0.5.4" authors = ["Philip Deljanov "] description = "Project Symphonia shared structs, traits, and features." homepage = "https://github.com/pdeljanov/Symphonia" readme = "README.md" keywords = [ "audio", "codec", "decoder", "multimedia", "media", ] categories = [ "multimedia", "multimedia::audio", "multimedia::encoding", ] license = "MPL-2.0" repository = "https://github.com/pdeljanov/Symphonia" [dependencies.arrayvec] version = "0.7.1" [dependencies.bitflags] version = "1.2.1" [dependencies.bytemuck] version = "1.7" [dependencies.lazy_static] version = "1.4.0" [dependencies.log] version = "0.4" [dependencies.rustfft] version = "6.1.0" optional = true default-features = false [features] default = [] opt-simd = [ "opt-simd-sse", "opt-simd-avx", "opt-simd-neon", ] opt-simd-avx = ["rustfft/avx"] opt-simd-neon = ["rustfft/neon"] opt-simd-sse = ["rustfft/sse"] symphonia-core-0.5.4/Cargo.toml.orig000064400000000000000000000016451046102023000154640ustar 00000000000000[package] name = "symphonia-core" version = "0.5.4" description = "Project Symphonia shared structs, traits, and features." homepage = "https://github.com/pdeljanov/Symphonia" repository = "https://github.com/pdeljanov/Symphonia" authors = ["Philip Deljanov "] license = "MPL-2.0" readme = "README.md" categories = ["multimedia", "multimedia::audio", "multimedia::encoding"] keywords = ["audio", "codec", "decoder", "multimedia", "media"] edition = "2018" rust-version = "1.53" [features] default = [] # SIMD support. opt-simd-sse = ["rustfft/sse"] opt-simd-avx = ["rustfft/avx"] opt-simd-neon = ["rustfft/neon"] # Enable all SIMD support. opt-simd = [ "opt-simd-sse", "opt-simd-avx", "opt-simd-neon", ] [dependencies] arrayvec = "0.7.1" bitflags = "1.2.1" bytemuck = "1.7" lazy_static = "1.4.0" log = "0.4" [dependencies.rustfft] version = "6.1.0" optional = true default-features = falsesymphonia-core-0.5.4/README.md000064400000000000000000000012571046102023000140530ustar 00000000000000# Symphonia Core [![Docs](https://docs.rs/symphonia-core/badge.svg)](https://docs.rs/symphonia-core) Core structs, traits, helpers, and more for Project Symphonia. **Note:** This crate should only be used if developing Project Symphonia decoders and demuxers. For other use cases please use the [`symphonia`](https://crates.io/crates/symphonia) crate. ## License Symphonia is provided under the MPL v2.0 license. Please refer to the LICENSE file for more details. ## Contributing Symphonia is a free and open-source project that welcomes contributions! To get started, please read our [Contribution Guidelines](https://github.com/pdeljanov/Symphonia/tree/master/CONTRIBUTING.md). symphonia-core-0.5.4/src/audio.rs000064400000000000000000001306211046102023000150300ustar 00000000000000// Symphonia // Copyright (c) 2019-2022 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/. //! The `audio` module provides primitives for working with multi-channel audio buffers of varying //! sample formats. use std::borrow::Cow; use std::fmt; use std::marker::PhantomData; use std::mem; use std::vec::Vec; use arrayvec::ArrayVec; use bitflags::bitflags; use crate::conv::{ConvertibleSample, FromSample, IntoSample}; use crate::errors::Result; use crate::sample::{i24, u24, Sample}; use crate::units::Duration; /// The maximum number of audio plane slices `AudioPlanes` or `AudioPlanesMut` will store on the /// stack before storing the slices on the heap. const AUDIO_PLANES_STORAGE_STACK_LIMIT: usize = 8; bitflags! { /// A bitmask representing the audio channels in an audio buffer or signal. /// /// The first 18 defined channels are guaranteed to be identical to those specified by /// Microsoft's WAVEFORMATEXTENSIBLE structure. Channels after 18 are defined by Symphonia and /// no order is guaranteed. #[derive(Default)] pub struct Channels: u32 { /// Front-left (left) or the Mono channel. const FRONT_LEFT = 0x0000_0001; /// Front-right (right) channel. const FRONT_RIGHT = 0x0000_0002; /// Front-centre (centre) channel. const FRONT_CENTRE = 0x0000_0004; /// Low frequency channel 1. const LFE1 = 0x0000_0008; /// Rear-left (surround rear left) channel. const REAR_LEFT = 0x0000_0010; /// Rear-right (surround rear right) channel. const REAR_RIGHT = 0x0000_0020; /// Front left-of-centre (left center) channel. const FRONT_LEFT_CENTRE = 0x0000_0040; /// Front right-of-centre (right center) channel. const FRONT_RIGHT_CENTRE = 0x0000_0080; /// Rear-centre (surround rear centre) channel. const REAR_CENTRE = 0x0000_0100; /// Side left (surround left) channel. const SIDE_LEFT = 0x0000_0200; /// Side right (surround right) channel. const SIDE_RIGHT = 0x0000_0400; /// Top centre channel. const TOP_CENTRE = 0x0000_0800; /// Top front-left channel. const TOP_FRONT_LEFT = 0x0000_1000; /// Top centre channel. const TOP_FRONT_CENTRE = 0x0000_2000; /// Top front-right channel. const TOP_FRONT_RIGHT = 0x0000_4000; /// Top rear-left channel. const TOP_REAR_LEFT = 0x0000_8000; /// Top rear-centre channel. const TOP_REAR_CENTRE = 0x0001_0000; /// Top rear-right channel. const TOP_REAR_RIGHT = 0x0002_0000; /// Rear left-of-centre channel. const REAR_LEFT_CENTRE = 0x0004_0000; /// Rear right-of-centre channel. const REAR_RIGHT_CENTRE = 0x0008_0000; /// Front left-wide channel. const FRONT_LEFT_WIDE = 0x0010_0000; /// Front right-wide channel. const FRONT_RIGHT_WIDE = 0x0020_0000; /// Front left-high channel. const FRONT_LEFT_HIGH = 0x0040_0000; /// Front centre-high channel. const FRONT_CENTRE_HIGH = 0x0080_0000; /// Front right-high channel. const FRONT_RIGHT_HIGH = 0x0100_0000; /// Low frequency channel 2. const LFE2 = 0x0200_0000; } } /// An iterator over individual channels within a `Channels` bitmask. pub struct ChannelsIter { channels: Channels, } impl Iterator for ChannelsIter { type Item = Channels; fn next(&mut self) -> Option { if !self.channels.is_empty() { let channel = Channels::from_bits_truncate(1 << self.channels.bits.trailing_zeros()); self.channels ^= channel; Some(channel) } else { None } } } impl Channels { /// Gets the number of channels. pub fn count(self) -> usize { self.bits.count_ones() as usize } /// Gets an iterator over individual channels. pub fn iter(&self) -> ChannelsIter { ChannelsIter { channels: *self } } } impl fmt::Display for Channels { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:#032b}", self.bits) } } /// `Layout` describes common audio channel configurations. #[derive(Copy, Clone, Debug)] pub enum Layout { /// Single centre channel. Mono, /// Left and Right channels. Stereo, /// Left and Right channels with a single low-frequency channel. TwoPointOne, /// Front Left and Right, Rear Left and Right, and a single low-frequency channel. FivePointOne, } impl Layout { /// Converts a channel `Layout` into a `Channels` bit mask. pub fn into_channels(self) -> Channels { match self { Layout::Mono => Channels::FRONT_LEFT, Layout::Stereo => Channels::FRONT_LEFT | Channels::FRONT_RIGHT, Layout::TwoPointOne => Channels::FRONT_LEFT | Channels::FRONT_RIGHT | Channels::LFE1, Layout::FivePointOne => { Channels::FRONT_LEFT | Channels::FRONT_RIGHT | Channels::FRONT_CENTRE | Channels::REAR_LEFT | Channels::REAR_RIGHT | Channels::LFE1 } } } } /// `SignalSpec` describes the characteristics of a Signal. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct SignalSpec { /// The signal sampling rate in hertz (Hz). pub rate: u32, /// The channel assignments of the signal. The order of the channels in the vector is the order /// in which each channel sample is stored in a frame. pub channels: Channels, } impl SignalSpec { pub fn new(rate: u32, channels: Channels) -> Self { SignalSpec { rate, channels } } pub fn new_with_layout(rate: u32, layout: Layout) -> Self { SignalSpec { rate, channels: layout.into_channels() } } } /// Small-storage optimization capable storage of immutable slices of `AudioBuffer` audio planes. enum AudioPlaneStorage<'a, S, const N: usize> { Stack(ArrayVec<&'a [S], N>), Heap(Vec<&'a [S]>), } /// `AudioPlanes` provides immutable slices to each audio channel (plane) contained in a signal. pub struct AudioPlanes<'a, S: 'a + Sample> { planes: AudioPlaneStorage<'a, S, AUDIO_PLANES_STORAGE_STACK_LIMIT>, } impl<'a, S: Sample> AudioPlanes<'a, S> { /// Instantiate `AudioPlanes` for the given channel configuration. fn new(channels: Channels) -> Self { let n_planes = channels.count(); if n_planes <= AUDIO_PLANES_STORAGE_STACK_LIMIT { AudioPlanes { planes: AudioPlaneStorage::Stack(ArrayVec::new()) } } else { AudioPlanes { planes: AudioPlaneStorage::Heap(Vec::with_capacity(n_planes)) } } } /// Push an immutable reference to an audio plane. This function may panic if the number of /// pushed planes exceeds the number specified at instantiation. fn push(&mut self, plane: &'a [S]) { match &mut self.planes { AudioPlaneStorage::Stack(planes) => { debug_assert!(!planes.is_full()); planes.push(plane); } AudioPlaneStorage::Heap(planes) => { planes.push(plane); } } } /// Gets immutable slices of all the audio planes. pub fn planes(&self) -> &[&'a [S]] { match &self.planes { AudioPlaneStorage::Stack(planes) => planes, AudioPlaneStorage::Heap(planes) => planes, } } } /// Small-storage optimization capable storage of mutable slices of `AudioBuffer` audio planes. enum AudioPlaneStorageMut<'a, S, const N: usize> { Stack(ArrayVec<&'a mut [S], N>), Heap(Vec<&'a mut [S]>), } /// `AudioPlanesMut` provides mutable slices to each audio channel (plane) contained in a signal. pub struct AudioPlanesMut<'a, S: 'a + Sample> { planes: AudioPlaneStorageMut<'a, S, AUDIO_PLANES_STORAGE_STACK_LIMIT>, } impl<'a, S: Sample> AudioPlanesMut<'a, S> { /// Instantiate `AudioPlanesMut` for the given channel configuration. fn new(channels: Channels) -> Self { let n_planes = channels.count(); if n_planes <= AUDIO_PLANES_STORAGE_STACK_LIMIT { AudioPlanesMut { planes: AudioPlaneStorageMut::Stack(ArrayVec::new()) } } else { AudioPlanesMut { planes: AudioPlaneStorageMut::Heap(Vec::with_capacity(n_planes)) } } } /// Push a mutable reference to an audio plane. This function may panic if the number of /// pushed planes exceeds the number specified at instantiation. fn push(&mut self, plane: &'a mut [S]) { match &mut self.planes { AudioPlaneStorageMut::Stack(planes) => { debug_assert!(!planes.is_full()); planes.push(plane); } AudioPlaneStorageMut::Heap(storage) => { storage.push(plane); } } } /// Gets mutable slices of all the audio planes. pub fn planes(&mut self) -> &mut [&'a mut [S]] { match &mut self.planes { AudioPlaneStorageMut::Stack(planes) => planes, AudioPlaneStorageMut::Heap(planes) => planes, } } } /// `AudioBuffer` is a container for multi-channel planar audio sample data. An `AudioBuffer` is /// characterized by the duration (capacity), and audio specification (channels and sample rate). /// The capacity of an `AudioBuffer` is the maximum number of samples the buffer may store per /// channel. Manipulation of samples is accomplished through the Signal trait or direct buffer /// manipulation. #[derive(Clone)] pub struct AudioBuffer { buf: Vec, spec: SignalSpec, n_frames: usize, n_capacity: usize, } impl AudioBuffer { /// Instantiate a new `AudioBuffer` using the specified signal specification and of the given /// duration. pub fn new(duration: Duration, spec: SignalSpec) -> Self { // The number of channels * duration cannot exceed u64::MAX. assert!(duration <= u64::MAX / spec.channels.count() as u64, "duration too large"); // The total number of samples the buffer will store. let n_samples = duration * spec.channels.count() as u64; // Practically speaking, it is not possible to allocate more than usize::MAX bytes of // samples. This assertion ensures the potential downcast of n_samples to usize below is // safe. assert!(n_samples <= (usize::MAX / mem::size_of::()) as u64, "duration too large"); // Allocate sample buffer and default initialize all samples to silence. let buf = vec![S::MID; n_samples as usize]; AudioBuffer { buf, spec, n_frames: 0, n_capacity: duration as usize } } /// Instantiates an unused `AudioBuffer`. An unused `AudioBuffer` will not allocate any memory, /// has a sample rate of 0, and no audio channels. pub fn unused() -> Self { AudioBuffer { buf: Vec::with_capacity(0), spec: SignalSpec::new(0, Channels::empty()), n_frames: 0, n_capacity: 0, } } /// Returns `true` if the `AudioBuffer` is unused. pub fn is_unused(&self) -> bool { self.n_capacity == 0 } /// Gets the signal specification for the buffer. pub fn spec(&self) -> &SignalSpec { &self.spec } /// Gets the total capacity of the buffer. The capacity is the maximum number of audio frames /// a buffer can store. pub fn capacity(&self) -> usize { self.n_capacity } /// Gets immutable references to all audio planes (channels) within the audio buffer. /// /// Note: This is not a cheap operation for audio buffers with > 8 channels. It is advisable /// that this call is only used when operating on large batches of frames. Generally speaking, /// it is almost always better to use `chan()` to selectively choose the plane to read instead. pub fn planes(&self) -> AudioPlanes { // Fill the audio planes structure with references to the written portion of each audio // plane. let mut planes = AudioPlanes::new(self.spec.channels); for channel in self.buf.chunks_exact(self.n_capacity) { planes.push(&channel[..self.n_frames]); } planes } /// Gets mutable references to all audio planes (channels) within the buffer. /// /// Note: This is not a cheap operation for audio buffers with > 8 channels. It is advisable /// that this call is only used when modifying large batches of frames. Generally speaking, /// it is almost always better to use `render()`, `fill()`, `chan_mut()`, and `chan_pair_mut()` /// to modify the buffer instead. pub fn planes_mut(&mut self) -> AudioPlanesMut { // Fill the audio planes structure with references to the written portion of each audio // plane. let mut planes = AudioPlanesMut::new(self.spec.channels); for channel in self.buf.chunks_exact_mut(self.n_capacity) { planes.push(&mut channel[..self.n_frames]); } planes } /// Converts the contents of an AudioBuffer into an equivalent destination AudioBuffer of a /// different type. If the types are the same then this is a copy operation. pub fn convert(&self, dest: &mut AudioBuffer) where S: IntoSample, { assert!(dest.n_capacity >= self.n_capacity); assert!(dest.spec == self.spec); for c in 0..self.spec.channels.count() { let begin = c * self.n_capacity; let end = begin + self.n_frames; for (d, s) in dest.buf[begin..end].iter_mut().zip(&self.buf[begin..end]) { *d = (*s).into_sample(); } } dest.n_frames = self.n_frames; } /// Makes an equivalent AudioBuffer of a different type. pub fn make_equivalent(&self) -> AudioBuffer { AudioBuffer::::new(self.n_capacity as Duration, self.spec) } } macro_rules! impl_audio_buffer_ref_func { ($var:expr, $buf:ident,$expr:expr) => { match $var { AudioBufferRef::U8($buf) => $expr, AudioBufferRef::U16($buf) => $expr, AudioBufferRef::U24($buf) => $expr, AudioBufferRef::U32($buf) => $expr, AudioBufferRef::S8($buf) => $expr, AudioBufferRef::S16($buf) => $expr, AudioBufferRef::S24($buf) => $expr, AudioBufferRef::S32($buf) => $expr, AudioBufferRef::F32($buf) => $expr, AudioBufferRef::F64($buf) => $expr, } }; } /// `AudioBufferRef` is a copy-on-write reference to an `AudioBuffer` of any type. #[derive(Clone)] pub enum AudioBufferRef<'a> { U8(Cow<'a, AudioBuffer>), U16(Cow<'a, AudioBuffer>), U24(Cow<'a, AudioBuffer>), U32(Cow<'a, AudioBuffer>), S8(Cow<'a, AudioBuffer>), S16(Cow<'a, AudioBuffer>), S24(Cow<'a, AudioBuffer>), S32(Cow<'a, AudioBuffer>), F32(Cow<'a, AudioBuffer>), F64(Cow<'a, AudioBuffer>), } impl<'a> AudioBufferRef<'a> { /// Gets the signal specification for the buffer. pub fn spec(&self) -> &SignalSpec { impl_audio_buffer_ref_func!(self, buf, buf.spec()) } /// Gets the total capacity of the buffer. The capacity is the maximum number of audio frames /// a buffer can store. pub fn capacity(&self) -> usize { impl_audio_buffer_ref_func!(self, buf, buf.capacity()) } /// Gets the number of frames in the buffer. pub fn frames(&self) -> usize { impl_audio_buffer_ref_func!(self, buf, buf.frames()) } pub fn convert(&self, dest: &mut AudioBuffer) where T: Sample + FromSample + FromSample + FromSample + FromSample + FromSample + FromSample + FromSample + FromSample + FromSample + FromSample, { impl_audio_buffer_ref_func!(self, buf, buf.convert(dest)) } pub fn make_equivalent(&self) -> AudioBuffer { impl_audio_buffer_ref_func!(self, buf, buf.make_equivalent::()) } } /// `AsAudioBufferRef` is a trait implemented for `AudioBuffer`s that may be referenced in an /// `AudioBufferRef`. pub trait AsAudioBufferRef { /// Get an `AudioBufferRef` reference. fn as_audio_buffer_ref(&self) -> AudioBufferRef; } macro_rules! impl_as_audio_buffer_ref { ($fmt:ty, $ref:path) => { impl AsAudioBufferRef for AudioBuffer<$fmt> { fn as_audio_buffer_ref(&self) -> AudioBufferRef { $ref(Cow::Borrowed(self)) } } }; } impl_as_audio_buffer_ref!(u8, AudioBufferRef::U8); impl_as_audio_buffer_ref!(u16, AudioBufferRef::U16); impl_as_audio_buffer_ref!(u24, AudioBufferRef::U24); impl_as_audio_buffer_ref!(u32, AudioBufferRef::U32); impl_as_audio_buffer_ref!(i8, AudioBufferRef::S8); impl_as_audio_buffer_ref!(i16, AudioBufferRef::S16); impl_as_audio_buffer_ref!(i24, AudioBufferRef::S24); impl_as_audio_buffer_ref!(i32, AudioBufferRef::S32); impl_as_audio_buffer_ref!(f32, AudioBufferRef::F32); impl_as_audio_buffer_ref!(f64, AudioBufferRef::F64); /// The `Signal` trait provides methods for rendering and transforming contiguous buffers of audio /// data. pub trait Signal { /// Gets the number of actual frames written to the buffer. Conversely, this also is the number /// of written samples in any one channel. fn frames(&self) -> usize; /// Clears all written frames from the buffer. This is a cheap operation and does not zero the /// underlying audio data. fn clear(&mut self); /// Gets an immutable reference to all the written samples in the specified channel. fn chan(&self, channel: usize) -> &[S]; /// Gets a mutable reference to all the written samples in the specified channel. fn chan_mut(&mut self, channel: usize) -> &mut [S]; /// Gets two mutable references to two different channels. fn chan_pair_mut(&mut self, first: usize, second: usize) -> (&mut [S], &mut [S]); /// Renders a number of silent frames. /// /// If `n_frames` is `None`, the remaining number of frames will be used. fn render_silence(&mut self, n_frames: Option); /// Renders a reserved number of frames. This is a cheap operation and simply advances the frame /// counter. The underlying audio data is not modified and should be overwritten through other /// means. /// /// If `n_frames` is `None`, the remaining number of frames will be used. If `n_frames` is too /// large, this function will assert. fn render_reserved(&mut self, n_frames: Option); /// Renders a number of frames using the provided render function. The number of frames to /// render is specified by `n_frames`. If `n_frames` is `None`, the remaining number of frames /// in the buffer will be rendered. If the render function returns an error, the render /// operation is terminated prematurely. fn render<'a, F>(&'a mut self, n_frames: Option, render: F) -> Result<()> where F: FnMut(&mut AudioPlanesMut<'a, S>, usize) -> Result<()>; /// Clears, and then renders the entire buffer using the fill function. This is a convenience /// wrapper around `render` and exhibits the same behaviour as `render` in regards to the fill /// function. #[inline] fn fill<'a, F>(&'a mut self, fill: F) -> Result<()> where F: FnMut(&mut AudioPlanesMut<'a, S>, usize) -> Result<()>, { self.clear(); self.render(None, fill) } /// Transforms every written sample in the signal using the transformation function provided. /// This function does not guarantee an order in which the samples are transformed. fn transform(&mut self, f: F) where F: Fn(S) -> S; /// Truncates the buffer to the number of frames specified. If the number of frames in the /// buffer is less-than the number of frames specified, then this function does nothing. fn truncate(&mut self, n_frames: usize); /// Shifts the contents of the buffer back by the number of frames specified. The leading frames /// are dropped from the buffer. fn shift(&mut self, shift: usize); /// Trims samples from the start and end of the buffer. fn trim(&mut self, start: usize, end: usize) { // First, trim the end to reduce the number of frames have to be shifted when the front is // trimmed. self.truncate(self.frames().saturating_sub(end)); // Second, trim the start. self.shift(start); } } impl Signal for AudioBuffer { fn clear(&mut self) { self.n_frames = 0; } fn frames(&self) -> usize { self.n_frames } fn chan(&self, channel: usize) -> &[S] { let start = channel * self.n_capacity; // If the channel index is invalid the slice will be out-of-bounds. assert!(start + self.n_capacity <= self.buf.len(), "invalid channel index"); &self.buf[start..start + self.n_frames] } fn chan_mut(&mut self, channel: usize) -> &mut [S] { let start = channel * self.n_capacity; // If the channel index is invalid the slice will be out-of-bounds. assert!(start + self.n_capacity <= self.buf.len(), "invalid channel index"); &mut self.buf[start..start + self.n_frames] } fn chan_pair_mut(&mut self, first: usize, second: usize) -> (&mut [S], &mut [S]) { // Both channels in the pair must be unique. assert!(first != second, "channel indicies cannot be the same"); let first_idx = self.n_capacity * first; let second_idx = self.n_capacity * second; // If a channel index is invalid the slice will be out-of-bounds. assert!(first_idx + self.n_capacity <= self.buf.len(), "invalid channel index"); assert!(second_idx + self.n_capacity <= self.buf.len(), "invalid channel index"); if first_idx < second_idx { let (a, b) = self.buf.split_at_mut(second_idx); (&mut a[first_idx..first_idx + self.n_frames], &mut b[..self.n_frames]) } else { let (a, b) = self.buf.split_at_mut(first_idx); (&mut b[..self.n_frames], &mut a[second_idx..second_idx + self.n_frames]) } } fn render_silence(&mut self, n_frames: Option) { let n_silent_frames = n_frames.unwrap_or(self.n_capacity - self.n_frames); // Do not render past the end of the audio buffer. assert!(self.n_frames + n_silent_frames <= self.capacity(), "capacity will be exceeded"); for channel in self.buf.chunks_exact_mut(self.n_capacity) { for sample in &mut channel[self.n_frames..self.n_frames + n_silent_frames] { *sample = S::MID; } } self.n_frames += n_silent_frames; } fn render_reserved(&mut self, n_frames: Option) { let n_reserved_frames = n_frames.unwrap_or(self.n_capacity - self.n_frames); // Do not render past the end of the audio buffer. assert!(self.n_frames + n_reserved_frames <= self.n_capacity, "capacity will be exceeded"); self.n_frames += n_reserved_frames; } fn render<'a, F>(&'a mut self, n_frames: Option, mut render: F) -> Result<()> where F: FnMut(&mut AudioPlanesMut<'a, S>, usize) -> Result<()>, { // The number of frames to be rendered is the amount requested, if specified, or the // remainder of the audio buffer. let n_render_frames = n_frames.unwrap_or(self.n_capacity - self.n_frames); // Do not render past the end of the audio buffer. let end = self.n_frames + n_render_frames; assert!(end <= self.n_capacity, "capacity will be exceeded"); // At this point, n_render_frames can be considered "reserved". Create an audio plane // structure and fill each plane entry with a reference to the "reserved" samples in each // channel respectively. let mut planes = AudioPlanesMut::new(self.spec.channels); for channel in self.buf.chunks_exact_mut(self.n_capacity) { planes.push(&mut channel[self.n_frames..end]); } // Attempt to render the into the reserved frames, one-by-one, exiting only if there is an // error in the render function. while self.n_frames < end { render(&mut planes, self.n_frames)?; self.n_frames += 1; } Ok(()) } fn transform(&mut self, f: F) where F: Fn(S) -> S, { debug_assert!(self.n_frames <= self.n_capacity); // Apply the transformation function over each sample in each plane. for plane in self.buf.chunks_mut(self.n_capacity) { for sample in &mut plane[0..self.n_frames] { *sample = f(*sample); } } } fn truncate(&mut self, n_frames: usize) { if n_frames < self.n_frames { self.n_frames = n_frames; } } fn shift(&mut self, shift: usize) { if shift >= self.n_frames { self.clear(); } else if shift > 0 { // Shift the samples down in each plane. for plane in self.buf.chunks_mut(self.n_capacity) { plane.copy_within(shift..self.n_frames, 0); } self.n_frames -= shift; } } } /// A `SampleBuffer`, is a sample oriented buffer. It is agnostic to the ordering/layout of samples /// within the buffer. `SampleBuffer` is mean't for safely importing and exporting sample data to /// and from Symphonia using the sample's in-memory data-type. pub struct SampleBuffer { buf: Box<[S]>, n_written: usize, } impl SampleBuffer { /// Instantiate a new `SampleBuffer` using the specified signal specification and of the given /// duration. pub fn new(duration: Duration, spec: SignalSpec) -> SampleBuffer { // The number of channels * duration cannot exceed u64::MAX. assert!(duration <= u64::MAX / spec.channels.count() as u64, "duration too large"); // The total number of samples the buffer will store. let n_samples = duration * spec.channels.count() as u64; // Practically speaking, it is not possible to allocate more than usize::MAX bytes of // samples. This assertion ensures the potential downcast of n_samples to usize below is // safe. assert!(n_samples <= (usize::MAX / mem::size_of::()) as u64, "duration too large"); // Allocate enough memory for all the samples and fill the buffer with silence. let buf = vec![S::MID; n_samples as usize].into_boxed_slice(); SampleBuffer { buf, n_written: 0 } } /// Gets the number of written samples. pub fn len(&self) -> usize { self.n_written } /// Returns `true` if the buffer contains no written samples. pub fn is_empty(&self) -> bool { self.n_written == 0 } /// Gets an immutable slice of all written samples. pub fn samples(&self) -> &[S] { &self.buf[..self.n_written] } /// Gets a mutable slice of all written samples. pub fn samples_mut(&mut self) -> &mut [S] { &mut self.buf[..self.n_written] } /// Gets the maximum number of samples the `SampleBuffer` may store. pub fn capacity(&self) -> usize { self.buf.len() } /// Clears all written samples. pub fn clear(&mut self) { self.n_written = 0; } /// Copies all audio data from the source `AudioBufferRef` in planar channel order into the /// `SampleBuffer`. The two buffers must be equivalent. pub fn copy_planar_ref(&mut self, src: AudioBufferRef) where S: ConvertibleSample, { match src { AudioBufferRef::U8(buf) => self.copy_planar_typed(&buf), AudioBufferRef::U16(buf) => self.copy_planar_typed(&buf), AudioBufferRef::U24(buf) => self.copy_planar_typed(&buf), AudioBufferRef::U32(buf) => self.copy_planar_typed(&buf), AudioBufferRef::S8(buf) => self.copy_planar_typed(&buf), AudioBufferRef::S16(buf) => self.copy_planar_typed(&buf), AudioBufferRef::S24(buf) => self.copy_planar_typed(&buf), AudioBufferRef::S32(buf) => self.copy_planar_typed(&buf), AudioBufferRef::F32(buf) => self.copy_planar_typed(&buf), AudioBufferRef::F64(buf) => self.copy_planar_typed(&buf), } } /// Copies all audio data from a source `AudioBuffer` into the `SampleBuffer` in planar /// channel order. The two buffers must be equivalent. pub fn copy_planar_typed(&mut self, src: &AudioBuffer) where F: Sample + IntoSample, { let n_frames = src.frames(); let n_channels = src.spec.channels.count(); let n_samples = n_frames * n_channels; // Ensure that the capacity of the sample buffer is greater than or equal to the number // of samples that will be copied from the source buffer. assert!(self.capacity() >= n_samples); for ch in 0..n_channels { let ch_slice = src.chan(ch); for (dst, src) in self.buf[ch * n_frames..].iter_mut().zip(ch_slice) { *dst = (*src).into_sample(); } } // Commit the written samples. self.n_written = n_samples; } /// Copies all audio data from the source `AudioBufferRef` in interleaved channel order into the /// `SampleBuffer`. The two buffers must be equivalent. pub fn copy_interleaved_ref(&mut self, src: AudioBufferRef) where S: ConvertibleSample, { match src { AudioBufferRef::U8(buf) => self.copy_interleaved_typed(&buf), AudioBufferRef::U16(buf) => self.copy_interleaved_typed(&buf), AudioBufferRef::U24(buf) => self.copy_interleaved_typed(&buf), AudioBufferRef::U32(buf) => self.copy_interleaved_typed(&buf), AudioBufferRef::S8(buf) => self.copy_interleaved_typed(&buf), AudioBufferRef::S16(buf) => self.copy_interleaved_typed(&buf), AudioBufferRef::S24(buf) => self.copy_interleaved_typed(&buf), AudioBufferRef::S32(buf) => self.copy_interleaved_typed(&buf), AudioBufferRef::F32(buf) => self.copy_interleaved_typed(&buf), AudioBufferRef::F64(buf) => self.copy_interleaved_typed(&buf), } } /// Copies all audio samples from a source `AudioBuffer` into the `SampleBuffer` in interleaved /// channel order. The two buffers must be equivalent. pub fn copy_interleaved_typed(&mut self, src: &AudioBuffer) where F: Sample + IntoSample, { let n_channels = src.spec.channels.count(); let n_samples = src.frames() * n_channels; // Ensure that the capacity of the sample buffer is greater than or equal to the number // of samples that will be copied from the source buffer. assert!(self.capacity() >= n_samples); // Interleave the source buffer channels into the sample buffer. for ch in 0..n_channels { let ch_slice = src.chan(ch); for (dst, src) in self.buf[ch..].iter_mut().step_by(n_channels).zip(ch_slice) { *dst = (*src).into_sample(); } } // Commit the written samples. self.n_written = n_samples; } } /// This non-public module contains the trait `Sealed` which is used to constrain /// `RawSample::RawType` with `bytemuck::Pod`. This is a trade-off to hide `bytemuck` from the public /// interface. The downside is that `RawSample::RawType` is locked to the types we implement /// `Sealed` on. To compensate, we implement `Sealed` on all primitive numeric data types, and byte /// arrays up to 8 bytes long. mod sealed { pub trait Sealed: bytemuck::Pod {} } impl sealed::Sealed for u8 {} impl sealed::Sealed for i8 {} impl sealed::Sealed for u16 {} impl sealed::Sealed for i16 {} impl sealed::Sealed for u32 {} impl sealed::Sealed for i32 {} impl sealed::Sealed for u64 {} impl sealed::Sealed for i64 {} impl sealed::Sealed for f32 {} impl sealed::Sealed for f64 {} impl sealed::Sealed for [u8; 1] {} impl sealed::Sealed for [u8; 2] {} impl sealed::Sealed for [u8; 3] {} impl sealed::Sealed for [u8; 4] {} impl sealed::Sealed for [u8; 5] {} impl sealed::Sealed for [u8; 6] {} impl sealed::Sealed for [u8; 7] {} impl sealed::Sealed for [u8; 8] {} /// `RawSample` provides a typed interface for converting a `Sample` from it's in-memory data type /// to actual binary type. pub trait RawSample: Sample { /// The `RawType` is a primitive data type, or fixed-size byte array, that is the final binary /// representation of the sample when written out to a byte-buffer. type RawType: Copy + Default + sealed::Sealed; fn into_raw_sample(self) -> Self::RawType; } impl RawSample for u8 { type RawType = u8; #[inline(always)] fn into_raw_sample(self) -> Self::RawType { self } } impl RawSample for i8 { type RawType = i8; #[inline(always)] fn into_raw_sample(self) -> Self::RawType { self } } impl RawSample for u16 { type RawType = u16; #[inline(always)] fn into_raw_sample(self) -> Self::RawType { self } } impl RawSample for i16 { type RawType = i16; #[inline(always)] fn into_raw_sample(self) -> Self::RawType { self } } impl RawSample for u24 { type RawType = [u8; 3]; #[inline(always)] fn into_raw_sample(self) -> Self::RawType { self.to_ne_bytes() } } impl RawSample for i24 { type RawType = [u8; 3]; #[inline(always)] fn into_raw_sample(self) -> Self::RawType { self.to_ne_bytes() } } impl RawSample for u32 { type RawType = u32; #[inline(always)] fn into_raw_sample(self) -> Self::RawType { self } } impl RawSample for i32 { type RawType = i32; #[inline(always)] fn into_raw_sample(self) -> Self::RawType { self } } impl RawSample for f32 { type RawType = f32; #[inline(always)] fn into_raw_sample(self) -> Self::RawType { self } } impl RawSample for f64 { type RawType = f64; #[inline(always)] fn into_raw_sample(self) -> Self::RawType { self } } /// A `RawSampleBuffer`, is a byte-oriented sample buffer. All samples copied to this buffer are /// converted into their packed data-type and stored as a stream of bytes. `RawSampleBuffer` is /// mean't for safely importing and exporting sample data to and from Symphonia as raw bytes. pub struct RawSampleBuffer { buf: Box<[S::RawType]>, n_written: usize, // Might take your heart. sample_format: PhantomData, } impl RawSampleBuffer { /// Instantiate a new `RawSampleBuffer` using the specified signal specification and of the given /// duration. pub fn new(duration: Duration, spec: SignalSpec) -> RawSampleBuffer { // The number of channels * duration cannot exceed u64::MAX. assert!(duration <= u64::MAX / spec.channels.count() as u64, "duration too large"); // The total number of samples the buffer will store. let n_samples = duration * spec.channels.count() as u64; // Practically speaking, it is not possible to allocate more than usize::MAX bytes of raw // samples. This assertion ensures the potential downcast of n_samples to usize below is // safe. assert!( n_samples <= (usize::MAX / mem::size_of::()) as u64, "duration too large" ); // Allocate enough memory for all the samples and fill the buffer with silence. let buf = vec![S::MID.into_raw_sample(); n_samples as usize].into_boxed_slice(); RawSampleBuffer { buf, n_written: 0, sample_format: PhantomData } } /// Gets the number of written samples. pub fn len(&self) -> usize { self.n_written } /// Returns `true` if the buffer contains no written samples. pub fn is_empty(&self) -> bool { self.n_written == 0 } /// Gets the maximum number of samples the `RawSampleBuffer` may store. pub fn capacity(&self) -> usize { self.buf.len() } /// Clears all written samples. pub fn clear(&mut self) { self.n_written = 0; } /// Gets an immutable slice to the bytes of the sample's written in the `RawSampleBuffer`. pub fn as_bytes(&self) -> &[u8] { // Get a slice to the written raw samples in the buffer, and convert from &[RawType] to // &[u8]. Since &[u8] has the least strict alignment requirements, this should always be // safe and therefore cast_slice should never panic. bytemuck::cast_slice(&self.buf[..self.n_written]) } /// Copies all audio data from the source `AudioBufferRef` in planar channel order into the /// `RawSampleBuffer`. The two buffers must be equivalent. pub fn copy_planar_ref(&mut self, src: AudioBufferRef) where S: ConvertibleSample, { match src { AudioBufferRef::U8(buf) => self.copy_planar_typed(&buf), AudioBufferRef::U16(buf) => self.copy_planar_typed(&buf), AudioBufferRef::U24(buf) => self.copy_planar_typed(&buf), AudioBufferRef::U32(buf) => self.copy_planar_typed(&buf), AudioBufferRef::S8(buf) => self.copy_planar_typed(&buf), AudioBufferRef::S16(buf) => self.copy_planar_typed(&buf), AudioBufferRef::S24(buf) => self.copy_planar_typed(&buf), AudioBufferRef::S32(buf) => self.copy_planar_typed(&buf), AudioBufferRef::F32(buf) => self.copy_planar_typed(&buf), AudioBufferRef::F64(buf) => self.copy_planar_typed(&buf), } } /// Copies all audio data from a source `AudioBuffer` that is of a different sample format type /// than that of the `RawSampleBuffer` in planar channel order. The two buffers must be /// equivalent. pub fn copy_planar_typed(&mut self, src: &AudioBuffer) where F: Sample + IntoSample, { let n_channels = src.spec.channels.count(); let n_samples = n_channels * src.n_frames; // Ensure that the capacity of the sample buffer is greater than or equal to the number // of samples that will be copied from the source buffer. assert!(self.capacity() >= n_samples); let dst_buf = &mut self.buf[..n_samples]; for (ch, dst_ch) in dst_buf.chunks_exact_mut(src.n_frames).enumerate() { let src_ch = src.chan(ch); for (&s, d) in src_ch.iter().zip(dst_ch) { *d = s.into_sample().into_raw_sample(); } } self.n_written = n_samples; } /// Copies all audio data from the source `AudioBuffer` to the `RawSampleBuffer` in planar order. /// The two buffers must be equivalent. pub fn copy_planar(&mut self, src: &AudioBuffer) { let n_channels = src.spec.channels.count(); let n_samples = src.n_frames * n_channels; // Ensure that the capacity of the sample buffer is greater than or equal to the number // of samples that will be copied from the source buffer. assert!(self.capacity() >= n_samples); let dst_buf = &mut self.buf[..n_samples]; for (ch, dst_ch) in dst_buf.chunks_exact_mut(src.n_frames).enumerate() { let src_ch = src.chan(ch); for (&s, d) in src_ch.iter().zip(dst_ch) { *d = s.into_raw_sample(); } } self.n_written = n_samples; } /// Copies all audio data from the source `AudioBufferRef` in interleaved channel order into the /// `RawSampleBuffer`. The two buffers must be equivalent. pub fn copy_interleaved_ref(&mut self, src: AudioBufferRef) where S: ConvertibleSample, { match src { AudioBufferRef::U8(buf) => self.copy_interleaved_typed(&buf), AudioBufferRef::U16(buf) => self.copy_interleaved_typed(&buf), AudioBufferRef::U24(buf) => self.copy_interleaved_typed(&buf), AudioBufferRef::U32(buf) => self.copy_interleaved_typed(&buf), AudioBufferRef::S8(buf) => self.copy_interleaved_typed(&buf), AudioBufferRef::S16(buf) => self.copy_interleaved_typed(&buf), AudioBufferRef::S24(buf) => self.copy_interleaved_typed(&buf), AudioBufferRef::S32(buf) => self.copy_interleaved_typed(&buf), AudioBufferRef::F32(buf) => self.copy_interleaved_typed(&buf), AudioBufferRef::F64(buf) => self.copy_interleaved_typed(&buf), } } /// Copies all audio data from a source `AudioBuffer` that is of a different sample format type /// than that of the `RawSampleBuffer` in interleaved channel order. The two buffers must be /// equivalent. pub fn copy_interleaved_typed(&mut self, src: &AudioBuffer) where F: Sample + IntoSample, { let n_frames = src.n_frames; let n_channels = src.spec.channels.count(); let n_samples = n_frames * n_channels; // Ensure that the capacity of the sample buffer is greater than or equal to the number // of samples that will be copied from the source buffer. assert!(self.capacity() >= n_samples); // The destination buffer slice. let dst_buf = &mut self.buf[..n_samples]; // Provide slightly optimized interleave algorithms for Mono and Stereo buffers. match n_channels { // No channels, do nothing. 0 => (), // Mono 1 => { for (&s, d) in src.chan(0).iter().zip(dst_buf) { *d = s.into_sample().into_raw_sample(); } } // Stereo 2 => { let l_buf = src.chan(0); let r_buf = src.chan(1); for ((&l, &r), d) in l_buf.iter().zip(r_buf).zip(dst_buf.chunks_exact_mut(2)) { d[0] = l.into_sample().into_raw_sample(); d[1] = r.into_sample().into_raw_sample(); } } // 3+ channels _ => { for ch in 0..n_channels { let src_ch = src.chan(ch); let dst_ch_iter = dst_buf[ch..].iter_mut().step_by(n_channels); for (&s, d) in src_ch.iter().zip(dst_ch_iter) { *d = s.into_sample().into_raw_sample(); } } } } self.n_written = n_samples; } /// Copies all audio data from the source `AudioBuffer` to the `RawSampleBuffer` in interleaved /// channel order. The two buffers must be equivalent. pub fn copy_interleaved(&mut self, src: &AudioBuffer) { let n_frames = src.n_frames; let n_channels = src.spec.channels.count(); let n_samples = n_frames * n_channels; // Ensure that the capacity of the sample buffer is greater than or equal to the number // of samples that will be copied from the source buffer. assert!(self.capacity() >= n_samples); // The destination buffer slice. let dst_buf = &mut self.buf[..n_samples]; // Provide slightly optimized interleave algorithms for Mono and Stereo buffers. match n_channels { // No channels, do nothing. 0 => (), // Mono 1 => { for (&s, d) in src.chan(0).iter().zip(dst_buf) { *d = s.into_raw_sample(); } } // Stereo 2 => { let l_buf = src.chan(0); let r_buf = src.chan(1); for ((&l, &r), d) in l_buf.iter().zip(r_buf).zip(dst_buf.chunks_exact_mut(2)) { d[0] = l.into_raw_sample(); d[1] = r.into_raw_sample(); } } // 3+ channels _ => { for ch in 0..n_channels { let src_ch = src.chan(ch); let dst_ch_iter = dst_buf[ch..].iter_mut().step_by(n_channels); for (&s, d) in src_ch.iter().zip(dst_ch_iter) { *d = s.into_raw_sample(); } } } } self.n_written = n_samples; } } symphonia-core-0.5.4/src/checksum/crc16.rs000064400000000000000000000613731046102023000164560ustar 00000000000000// Symphonia // Copyright (c) 2019-2022 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/. use crate::io::Monitor; // Credit: This table was extracted from the reference FLAC decoder. #[rustfmt::skip] const CRC16_ANSI: [[u16; 256]; 8] = [ [ 0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011, 0x8033, 0x0036, 0x003c, 0x8039, 0x0028, 0x802d, 0x8027, 0x0022, 0x8063, 0x0066, 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072, 0x0050, 0x8055, 0x805f, 0x005a, 0x804b, 0x004e, 0x0044, 0x8041, 0x80c3, 0x00c6, 0x00cc, 0x80c9, 0x00d8, 0x80dd, 0x80d7, 0x00d2, 0x00f0, 0x80f5, 0x80ff, 0x00fa, 0x80eb, 0x00ee, 0x00e4, 0x80e1, 0x00a0, 0x80a5, 0x80af, 0x00aa, 0x80bb, 0x00be, 0x00b4, 0x80b1, 0x8093, 0x0096, 0x009c, 0x8099, 0x0088, 0x808d, 0x8087, 0x0082, 0x8183, 0x0186, 0x018c, 0x8189, 0x0198, 0x819d, 0x8197, 0x0192, 0x01b0, 0x81b5, 0x81bf, 0x01ba, 0x81ab, 0x01ae, 0x01a4, 0x81a1, 0x01e0, 0x81e5, 0x81ef, 0x01ea, 0x81fb, 0x01fe, 0x01f4, 0x81f1, 0x81d3, 0x01d6, 0x01dc, 0x81d9, 0x01c8, 0x81cd, 0x81c7, 0x01c2, 0x0140, 0x8145, 0x814f, 0x014a, 0x815b, 0x015e, 0x0154, 0x8151, 0x8173, 0x0176, 0x017c, 0x8179, 0x0168, 0x816d, 0x8167, 0x0162, 0x8123, 0x0126, 0x012c, 0x8129, 0x0138, 0x813d, 0x8137, 0x0132, 0x0110, 0x8115, 0x811f, 0x011a, 0x810b, 0x010e, 0x0104, 0x8101, 0x8303, 0x0306, 0x030c, 0x8309, 0x0318, 0x831d, 0x8317, 0x0312, 0x0330, 0x8335, 0x833f, 0x033a, 0x832b, 0x032e, 0x0324, 0x8321, 0x0360, 0x8365, 0x836f, 0x036a, 0x837b, 0x037e, 0x0374, 0x8371, 0x8353, 0x0356, 0x035c, 0x8359, 0x0348, 0x834d, 0x8347, 0x0342, 0x03c0, 0x83c5, 0x83cf, 0x03ca, 0x83db, 0x03de, 0x03d4, 0x83d1, 0x83f3, 0x03f6, 0x03fc, 0x83f9, 0x03e8, 0x83ed, 0x83e7, 0x03e2, 0x83a3, 0x03a6, 0x03ac, 0x83a9, 0x03b8, 0x83bd, 0x83b7, 0x03b2, 0x0390, 0x8395, 0x839f, 0x039a, 0x838b, 0x038e, 0x0384, 0x8381, 0x0280, 0x8285, 0x828f, 0x028a, 0x829b, 0x029e, 0x0294, 0x8291, 0x82b3, 0x02b6, 0x02bc, 0x82b9, 0x02a8, 0x82ad, 0x82a7, 0x02a2, 0x82e3, 0x02e6, 0x02ec, 0x82e9, 0x02f8, 0x82fd, 0x82f7, 0x02f2, 0x02d0, 0x82d5, 0x82df, 0x02da, 0x82cb, 0x02ce, 0x02c4, 0x82c1, 0x8243, 0x0246, 0x024c, 0x8249, 0x0258, 0x825d, 0x8257, 0x0252, 0x0270, 0x8275, 0x827f, 0x027a, 0x826b, 0x026e, 0x0264, 0x8261, 0x0220, 0x8225, 0x822f, 0x022a, 0x823b, 0x023e, 0x0234, 0x8231, 0x8213, 0x0216, 0x021c, 0x8219, 0x0208, 0x820d, 0x8207, 0x0202, ], [ 0x0000, 0x8603, 0x8c03, 0x0a00, 0x9803, 0x1e00, 0x1400, 0x9203, 0xb003, 0x3600, 0x3c00, 0xba03, 0x2800, 0xae03, 0xa403, 0x2200, 0xe003, 0x6600, 0x6c00, 0xea03, 0x7800, 0xfe03, 0xf403, 0x7200, 0x5000, 0xd603, 0xdc03, 0x5a00, 0xc803, 0x4e00, 0x4400, 0xc203, 0x4003, 0xc600, 0xcc00, 0x4a03, 0xd800, 0x5e03, 0x5403, 0xd200, 0xf000, 0x7603, 0x7c03, 0xfa00, 0x6803, 0xee00, 0xe400, 0x6203, 0xa000, 0x2603, 0x2c03, 0xaa00, 0x3803, 0xbe00, 0xb400, 0x3203, 0x1003, 0x9600, 0x9c00, 0x1a03, 0x8800, 0x0e03, 0x0403, 0x8200, 0x8006, 0x0605, 0x0c05, 0x8a06, 0x1805, 0x9e06, 0x9406, 0x1205, 0x3005, 0xb606, 0xbc06, 0x3a05, 0xa806, 0x2e05, 0x2405, 0xa206, 0x6005, 0xe606, 0xec06, 0x6a05, 0xf806, 0x7e05, 0x7405, 0xf206, 0xd006, 0x5605, 0x5c05, 0xda06, 0x4805, 0xce06, 0xc406, 0x4205, 0xc005, 0x4606, 0x4c06, 0xca05, 0x5806, 0xde05, 0xd405, 0x5206, 0x7006, 0xf605, 0xfc05, 0x7a06, 0xe805, 0x6e06, 0x6406, 0xe205, 0x2006, 0xa605, 0xac05, 0x2a06, 0xb805, 0x3e06, 0x3406, 0xb205, 0x9005, 0x1606, 0x1c06, 0x9a05, 0x0806, 0x8e05, 0x8405, 0x0206, 0x8009, 0x060a, 0x0c0a, 0x8a09, 0x180a, 0x9e09, 0x9409, 0x120a, 0x300a, 0xb609, 0xbc09, 0x3a0a, 0xa809, 0x2e0a, 0x240a, 0xa209, 0x600a, 0xe609, 0xec09, 0x6a0a, 0xf809, 0x7e0a, 0x740a, 0xf209, 0xd009, 0x560a, 0x5c0a, 0xda09, 0x480a, 0xce09, 0xc409, 0x420a, 0xc00a, 0x4609, 0x4c09, 0xca0a, 0x5809, 0xde0a, 0xd40a, 0x5209, 0x7009, 0xf60a, 0xfc0a, 0x7a09, 0xe80a, 0x6e09, 0x6409, 0xe20a, 0x2009, 0xa60a, 0xac0a, 0x2a09, 0xb80a, 0x3e09, 0x3409, 0xb20a, 0x900a, 0x1609, 0x1c09, 0x9a0a, 0x0809, 0x8e0a, 0x840a, 0x0209, 0x000f, 0x860c, 0x8c0c, 0x0a0f, 0x980c, 0x1e0f, 0x140f, 0x920c, 0xb00c, 0x360f, 0x3c0f, 0xba0c, 0x280f, 0xae0c, 0xa40c, 0x220f, 0xe00c, 0x660f, 0x6c0f, 0xea0c, 0x780f, 0xfe0c, 0xf40c, 0x720f, 0x500f, 0xd60c, 0xdc0c, 0x5a0f, 0xc80c, 0x4e0f, 0x440f, 0xc20c, 0x400c, 0xc60f, 0xcc0f, 0x4a0c, 0xd80f, 0x5e0c, 0x540c, 0xd20f, 0xf00f, 0x760c, 0x7c0c, 0xfa0f, 0x680c, 0xee0f, 0xe40f, 0x620c, 0xa00f, 0x260c, 0x2c0c, 0xaa0f, 0x380c, 0xbe0f, 0xb40f, 0x320c, 0x100c, 0x960f, 0x9c0f, 0x1a0c, 0x880f, 0x0e0c, 0x040c, 0x820f, ], [ 0x0000, 0x8017, 0x802b, 0x003c, 0x8053, 0x0044, 0x0078, 0x806f, 0x80a3, 0x00b4, 0x0088, 0x809f, 0x00f0, 0x80e7, 0x80db, 0x00cc, 0x8143, 0x0154, 0x0168, 0x817f, 0x0110, 0x8107, 0x813b, 0x012c, 0x01e0, 0x81f7, 0x81cb, 0x01dc, 0x81b3, 0x01a4, 0x0198, 0x818f, 0x8283, 0x0294, 0x02a8, 0x82bf, 0x02d0, 0x82c7, 0x82fb, 0x02ec, 0x0220, 0x8237, 0x820b, 0x021c, 0x8273, 0x0264, 0x0258, 0x824f, 0x03c0, 0x83d7, 0x83eb, 0x03fc, 0x8393, 0x0384, 0x03b8, 0x83af, 0x8363, 0x0374, 0x0348, 0x835f, 0x0330, 0x8327, 0x831b, 0x030c, 0x8503, 0x0514, 0x0528, 0x853f, 0x0550, 0x8547, 0x857b, 0x056c, 0x05a0, 0x85b7, 0x858b, 0x059c, 0x85f3, 0x05e4, 0x05d8, 0x85cf, 0x0440, 0x8457, 0x846b, 0x047c, 0x8413, 0x0404, 0x0438, 0x842f, 0x84e3, 0x04f4, 0x04c8, 0x84df, 0x04b0, 0x84a7, 0x849b, 0x048c, 0x0780, 0x8797, 0x87ab, 0x07bc, 0x87d3, 0x07c4, 0x07f8, 0x87ef, 0x8723, 0x0734, 0x0708, 0x871f, 0x0770, 0x8767, 0x875b, 0x074c, 0x86c3, 0x06d4, 0x06e8, 0x86ff, 0x0690, 0x8687, 0x86bb, 0x06ac, 0x0660, 0x8677, 0x864b, 0x065c, 0x8633, 0x0624, 0x0618, 0x860f, 0x8a03, 0x0a14, 0x0a28, 0x8a3f, 0x0a50, 0x8a47, 0x8a7b, 0x0a6c, 0x0aa0, 0x8ab7, 0x8a8b, 0x0a9c, 0x8af3, 0x0ae4, 0x0ad8, 0x8acf, 0x0b40, 0x8b57, 0x8b6b, 0x0b7c, 0x8b13, 0x0b04, 0x0b38, 0x8b2f, 0x8be3, 0x0bf4, 0x0bc8, 0x8bdf, 0x0bb0, 0x8ba7, 0x8b9b, 0x0b8c, 0x0880, 0x8897, 0x88ab, 0x08bc, 0x88d3, 0x08c4, 0x08f8, 0x88ef, 0x8823, 0x0834, 0x0808, 0x881f, 0x0870, 0x8867, 0x885b, 0x084c, 0x89c3, 0x09d4, 0x09e8, 0x89ff, 0x0990, 0x8987, 0x89bb, 0x09ac, 0x0960, 0x8977, 0x894b, 0x095c, 0x8933, 0x0924, 0x0918, 0x890f, 0x0f00, 0x8f17, 0x8f2b, 0x0f3c, 0x8f53, 0x0f44, 0x0f78, 0x8f6f, 0x8fa3, 0x0fb4, 0x0f88, 0x8f9f, 0x0ff0, 0x8fe7, 0x8fdb, 0x0fcc, 0x8e43, 0x0e54, 0x0e68, 0x8e7f, 0x0e10, 0x8e07, 0x8e3b, 0x0e2c, 0x0ee0, 0x8ef7, 0x8ecb, 0x0edc, 0x8eb3, 0x0ea4, 0x0e98, 0x8e8f, 0x8d83, 0x0d94, 0x0da8, 0x8dbf, 0x0dd0, 0x8dc7, 0x8dfb, 0x0dec, 0x0d20, 0x8d37, 0x8d0b, 0x0d1c, 0x8d73, 0x0d64, 0x0d58, 0x8d4f, 0x0cc0, 0x8cd7, 0x8ceb, 0x0cfc, 0x8c93, 0x0c84, 0x0cb8, 0x8caf, 0x8c63, 0x0c74, 0x0c48, 0x8c5f, 0x0c30, 0x8c27, 0x8c1b, 0x0c0c, ], [ 0x0000, 0x9403, 0xa803, 0x3c00, 0xd003, 0x4400, 0x7800, 0xec03, 0x2003, 0xb400, 0x8800, 0x1c03, 0xf000, 0x6403, 0x5803, 0xcc00, 0x4006, 0xd405, 0xe805, 0x7c06, 0x9005, 0x0406, 0x3806, 0xac05, 0x6005, 0xf406, 0xc806, 0x5c05, 0xb006, 0x2405, 0x1805, 0x8c06, 0x800c, 0x140f, 0x280f, 0xbc0c, 0x500f, 0xc40c, 0xf80c, 0x6c0f, 0xa00f, 0x340c, 0x080c, 0x9c0f, 0x700c, 0xe40f, 0xd80f, 0x4c0c, 0xc00a, 0x5409, 0x6809, 0xfc0a, 0x1009, 0x840a, 0xb80a, 0x2c09, 0xe009, 0x740a, 0x480a, 0xdc09, 0x300a, 0xa409, 0x9809, 0x0c0a, 0x801d, 0x141e, 0x281e, 0xbc1d, 0x501e, 0xc41d, 0xf81d, 0x6c1e, 0xa01e, 0x341d, 0x081d, 0x9c1e, 0x701d, 0xe41e, 0xd81e, 0x4c1d, 0xc01b, 0x5418, 0x6818, 0xfc1b, 0x1018, 0x841b, 0xb81b, 0x2c18, 0xe018, 0x741b, 0x481b, 0xdc18, 0x301b, 0xa418, 0x9818, 0x0c1b, 0x0011, 0x9412, 0xa812, 0x3c11, 0xd012, 0x4411, 0x7811, 0xec12, 0x2012, 0xb411, 0x8811, 0x1c12, 0xf011, 0x6412, 0x5812, 0xcc11, 0x4017, 0xd414, 0xe814, 0x7c17, 0x9014, 0x0417, 0x3817, 0xac14, 0x6014, 0xf417, 0xc817, 0x5c14, 0xb017, 0x2414, 0x1814, 0x8c17, 0x803f, 0x143c, 0x283c, 0xbc3f, 0x503c, 0xc43f, 0xf83f, 0x6c3c, 0xa03c, 0x343f, 0x083f, 0x9c3c, 0x703f, 0xe43c, 0xd83c, 0x4c3f, 0xc039, 0x543a, 0x683a, 0xfc39, 0x103a, 0x8439, 0xb839, 0x2c3a, 0xe03a, 0x7439, 0x4839, 0xdc3a, 0x3039, 0xa43a, 0x983a, 0x0c39, 0x0033, 0x9430, 0xa830, 0x3c33, 0xd030, 0x4433, 0x7833, 0xec30, 0x2030, 0xb433, 0x8833, 0x1c30, 0xf033, 0x6430, 0x5830, 0xcc33, 0x4035, 0xd436, 0xe836, 0x7c35, 0x9036, 0x0435, 0x3835, 0xac36, 0x6036, 0xf435, 0xc835, 0x5c36, 0xb035, 0x2436, 0x1836, 0x8c35, 0x0022, 0x9421, 0xa821, 0x3c22, 0xd021, 0x4422, 0x7822, 0xec21, 0x2021, 0xb422, 0x8822, 0x1c21, 0xf022, 0x6421, 0x5821, 0xcc22, 0x4024, 0xd427, 0xe827, 0x7c24, 0x9027, 0x0424, 0x3824, 0xac27, 0x6027, 0xf424, 0xc824, 0x5c27, 0xb024, 0x2427, 0x1827, 0x8c24, 0x802e, 0x142d, 0x282d, 0xbc2e, 0x502d, 0xc42e, 0xf82e, 0x6c2d, 0xa02d, 0x342e, 0x082e, 0x9c2d, 0x702e, 0xe42d, 0xd82d, 0x4c2e, 0xc028, 0x542b, 0x682b, 0xfc28, 0x102b, 0x8428, 0xb828, 0x2c2b, 0xe02b, 0x7428, 0x4828, 0xdc2b, 0x3028, 0xa42b, 0x982b, 0x0c28, ], [ 0x0000, 0x807b, 0x80f3, 0x0088, 0x81e3, 0x0198, 0x0110, 0x816b, 0x83c3, 0x03b8, 0x0330, 0x834b, 0x0220, 0x825b, 0x82d3, 0x02a8, 0x8783, 0x07f8, 0x0770, 0x870b, 0x0660, 0x861b, 0x8693, 0x06e8, 0x0440, 0x843b, 0x84b3, 0x04c8, 0x85a3, 0x05d8, 0x0550, 0x852b, 0x8f03, 0x0f78, 0x0ff0, 0x8f8b, 0x0ee0, 0x8e9b, 0x8e13, 0x0e68, 0x0cc0, 0x8cbb, 0x8c33, 0x0c48, 0x8d23, 0x0d58, 0x0dd0, 0x8dab, 0x0880, 0x88fb, 0x8873, 0x0808, 0x8963, 0x0918, 0x0990, 0x89eb, 0x8b43, 0x0b38, 0x0bb0, 0x8bcb, 0x0aa0, 0x8adb, 0x8a53, 0x0a28, 0x9e03, 0x1e78, 0x1ef0, 0x9e8b, 0x1fe0, 0x9f9b, 0x9f13, 0x1f68, 0x1dc0, 0x9dbb, 0x9d33, 0x1d48, 0x9c23, 0x1c58, 0x1cd0, 0x9cab, 0x1980, 0x99fb, 0x9973, 0x1908, 0x9863, 0x1818, 0x1890, 0x98eb, 0x9a43, 0x1a38, 0x1ab0, 0x9acb, 0x1ba0, 0x9bdb, 0x9b53, 0x1b28, 0x1100, 0x917b, 0x91f3, 0x1188, 0x90e3, 0x1098, 0x1010, 0x906b, 0x92c3, 0x12b8, 0x1230, 0x924b, 0x1320, 0x935b, 0x93d3, 0x13a8, 0x9683, 0x16f8, 0x1670, 0x960b, 0x1760, 0x971b, 0x9793, 0x17e8, 0x1540, 0x953b, 0x95b3, 0x15c8, 0x94a3, 0x14d8, 0x1450, 0x942b, 0xbc03, 0x3c78, 0x3cf0, 0xbc8b, 0x3de0, 0xbd9b, 0xbd13, 0x3d68, 0x3fc0, 0xbfbb, 0xbf33, 0x3f48, 0xbe23, 0x3e58, 0x3ed0, 0xbeab, 0x3b80, 0xbbfb, 0xbb73, 0x3b08, 0xba63, 0x3a18, 0x3a90, 0xbaeb, 0xb843, 0x3838, 0x38b0, 0xb8cb, 0x39a0, 0xb9db, 0xb953, 0x3928, 0x3300, 0xb37b, 0xb3f3, 0x3388, 0xb2e3, 0x3298, 0x3210, 0xb26b, 0xb0c3, 0x30b8, 0x3030, 0xb04b, 0x3120, 0xb15b, 0xb1d3, 0x31a8, 0xb483, 0x34f8, 0x3470, 0xb40b, 0x3560, 0xb51b, 0xb593, 0x35e8, 0x3740, 0xb73b, 0xb7b3, 0x37c8, 0xb6a3, 0x36d8, 0x3650, 0xb62b, 0x2200, 0xa27b, 0xa2f3, 0x2288, 0xa3e3, 0x2398, 0x2310, 0xa36b, 0xa1c3, 0x21b8, 0x2130, 0xa14b, 0x2020, 0xa05b, 0xa0d3, 0x20a8, 0xa583, 0x25f8, 0x2570, 0xa50b, 0x2460, 0xa41b, 0xa493, 0x24e8, 0x2640, 0xa63b, 0xa6b3, 0x26c8, 0xa7a3, 0x27d8, 0x2750, 0xa72b, 0xad03, 0x2d78, 0x2df0, 0xad8b, 0x2ce0, 0xac9b, 0xac13, 0x2c68, 0x2ec0, 0xaebb, 0xae33, 0x2e48, 0xaf23, 0x2f58, 0x2fd0, 0xafab, 0x2a80, 0xaafb, 0xaa73, 0x2a08, 0xab63, 0x2b18, 0x2b90, 0xabeb, 0xa943, 0x2938, 0x29b0, 0xa9cb, 0x28a0, 0xa8db, 0xa853, 0x2828, ], [ 0x0000, 0xf803, 0x7003, 0x8800, 0xe006, 0x1805, 0x9005, 0x6806, 0x4009, 0xb80a, 0x300a, 0xc809, 0xa00f, 0x580c, 0xd00c, 0x280f, 0x8012, 0x7811, 0xf011, 0x0812, 0x6014, 0x9817, 0x1017, 0xe814, 0xc01b, 0x3818, 0xb018, 0x481b, 0x201d, 0xd81e, 0x501e, 0xa81d, 0x8021, 0x7822, 0xf022, 0x0821, 0x6027, 0x9824, 0x1024, 0xe827, 0xc028, 0x382b, 0xb02b, 0x4828, 0x202e, 0xd82d, 0x502d, 0xa82e, 0x0033, 0xf830, 0x7030, 0x8833, 0xe035, 0x1836, 0x9036, 0x6835, 0x403a, 0xb839, 0x3039, 0xc83a, 0xa03c, 0x583f, 0xd03f, 0x283c, 0x8047, 0x7844, 0xf044, 0x0847, 0x6041, 0x9842, 0x1042, 0xe841, 0xc04e, 0x384d, 0xb04d, 0x484e, 0x2048, 0xd84b, 0x504b, 0xa848, 0x0055, 0xf856, 0x7056, 0x8855, 0xe053, 0x1850, 0x9050, 0x6853, 0x405c, 0xb85f, 0x305f, 0xc85c, 0xa05a, 0x5859, 0xd059, 0x285a, 0x0066, 0xf865, 0x7065, 0x8866, 0xe060, 0x1863, 0x9063, 0x6860, 0x406f, 0xb86c, 0x306c, 0xc86f, 0xa069, 0x586a, 0xd06a, 0x2869, 0x8074, 0x7877, 0xf077, 0x0874, 0x6072, 0x9871, 0x1071, 0xe872, 0xc07d, 0x387e, 0xb07e, 0x487d, 0x207b, 0xd878, 0x5078, 0xa87b, 0x808b, 0x7888, 0xf088, 0x088b, 0x608d, 0x988e, 0x108e, 0xe88d, 0xc082, 0x3881, 0xb081, 0x4882, 0x2084, 0xd887, 0x5087, 0xa884, 0x0099, 0xf89a, 0x709a, 0x8899, 0xe09f, 0x189c, 0x909c, 0x689f, 0x4090, 0xb893, 0x3093, 0xc890, 0xa096, 0x5895, 0xd095, 0x2896, 0x00aa, 0xf8a9, 0x70a9, 0x88aa, 0xe0ac, 0x18af, 0x90af, 0x68ac, 0x40a3, 0xb8a0, 0x30a0, 0xc8a3, 0xa0a5, 0x58a6, 0xd0a6, 0x28a5, 0x80b8, 0x78bb, 0xf0bb, 0x08b8, 0x60be, 0x98bd, 0x10bd, 0xe8be, 0xc0b1, 0x38b2, 0xb0b2, 0x48b1, 0x20b7, 0xd8b4, 0x50b4, 0xa8b7, 0x00cc, 0xf8cf, 0x70cf, 0x88cc, 0xe0ca, 0x18c9, 0x90c9, 0x68ca, 0x40c5, 0xb8c6, 0x30c6, 0xc8c5, 0xa0c3, 0x58c0, 0xd0c0, 0x28c3, 0x80de, 0x78dd, 0xf0dd, 0x08de, 0x60d8, 0x98db, 0x10db, 0xe8d8, 0xc0d7, 0x38d4, 0xb0d4, 0x48d7, 0x20d1, 0xd8d2, 0x50d2, 0xa8d1, 0x80ed, 0x78ee, 0xf0ee, 0x08ed, 0x60eb, 0x98e8, 0x10e8, 0xe8eb, 0xc0e4, 0x38e7, 0xb0e7, 0x48e4, 0x20e2, 0xd8e1, 0x50e1, 0xa8e2, 0x00ff, 0xf8fc, 0x70fc, 0x88ff, 0xe0f9, 0x18fa, 0x90fa, 0x68f9, 0x40f6, 0xb8f5, 0x30f5, 0xc8f6, 0xa0f0, 0x58f3, 0xd0f3, 0x28f0, ], [ 0x0000, 0x8113, 0x8223, 0x0330, 0x8443, 0x0550, 0x0660, 0x8773, 0x8883, 0x0990, 0x0aa0, 0x8bb3, 0x0cc0, 0x8dd3, 0x8ee3, 0x0ff0, 0x9103, 0x1010, 0x1320, 0x9233, 0x1540, 0x9453, 0x9763, 0x1670, 0x1980, 0x9893, 0x9ba3, 0x1ab0, 0x9dc3, 0x1cd0, 0x1fe0, 0x9ef3, 0xa203, 0x2310, 0x2020, 0xa133, 0x2640, 0xa753, 0xa463, 0x2570, 0x2a80, 0xab93, 0xa8a3, 0x29b0, 0xaec3, 0x2fd0, 0x2ce0, 0xadf3, 0x3300, 0xb213, 0xb123, 0x3030, 0xb743, 0x3650, 0x3560, 0xb473, 0xbb83, 0x3a90, 0x39a0, 0xb8b3, 0x3fc0, 0xbed3, 0xbde3, 0x3cf0, 0xc403, 0x4510, 0x4620, 0xc733, 0x4040, 0xc153, 0xc263, 0x4370, 0x4c80, 0xcd93, 0xcea3, 0x4fb0, 0xc8c3, 0x49d0, 0x4ae0, 0xcbf3, 0x5500, 0xd413, 0xd723, 0x5630, 0xd143, 0x5050, 0x5360, 0xd273, 0xdd83, 0x5c90, 0x5fa0, 0xdeb3, 0x59c0, 0xd8d3, 0xdbe3, 0x5af0, 0x6600, 0xe713, 0xe423, 0x6530, 0xe243, 0x6350, 0x6060, 0xe173, 0xee83, 0x6f90, 0x6ca0, 0xedb3, 0x6ac0, 0xebd3, 0xe8e3, 0x69f0, 0xf703, 0x7610, 0x7520, 0xf433, 0x7340, 0xf253, 0xf163, 0x7070, 0x7f80, 0xfe93, 0xfda3, 0x7cb0, 0xfbc3, 0x7ad0, 0x79e0, 0xf8f3, 0x0803, 0x8910, 0x8a20, 0x0b33, 0x8c40, 0x0d53, 0x0e63, 0x8f70, 0x8080, 0x0193, 0x02a3, 0x83b0, 0x04c3, 0x85d0, 0x86e0, 0x07f3, 0x9900, 0x1813, 0x1b23, 0x9a30, 0x1d43, 0x9c50, 0x9f60, 0x1e73, 0x1183, 0x9090, 0x93a0, 0x12b3, 0x95c0, 0x14d3, 0x17e3, 0x96f0, 0xaa00, 0x2b13, 0x2823, 0xa930, 0x2e43, 0xaf50, 0xac60, 0x2d73, 0x2283, 0xa390, 0xa0a0, 0x21b3, 0xa6c0, 0x27d3, 0x24e3, 0xa5f0, 0x3b03, 0xba10, 0xb920, 0x3833, 0xbf40, 0x3e53, 0x3d63, 0xbc70, 0xb380, 0x3293, 0x31a3, 0xb0b0, 0x37c3, 0xb6d0, 0xb5e0, 0x34f3, 0xcc00, 0x4d13, 0x4e23, 0xcf30, 0x4843, 0xc950, 0xca60, 0x4b73, 0x4483, 0xc590, 0xc6a0, 0x47b3, 0xc0c0, 0x41d3, 0x42e3, 0xc3f0, 0x5d03, 0xdc10, 0xdf20, 0x5e33, 0xd940, 0x5853, 0x5b63, 0xda70, 0xd580, 0x5493, 0x57a3, 0xd6b0, 0x51c3, 0xd0d0, 0xd3e0, 0x52f3, 0x6e03, 0xef10, 0xec20, 0x6d33, 0xea40, 0x6b53, 0x6863, 0xe970, 0xe680, 0x6793, 0x64a3, 0xe5b0, 0x62c3, 0xe3d0, 0xe0e0, 0x61f3, 0xff00, 0x7e13, 0x7d23, 0xfc30, 0x7b43, 0xfa50, 0xf960, 0x7873, 0x7783, 0xf690, 0xf5a0, 0x74b3, 0xf3c0, 0x72d3, 0x71e3, 0xf0f0, ], [ 0x0000, 0x1006, 0x200c, 0x300a, 0x4018, 0x501e, 0x6014, 0x7012, 0x8030, 0x9036, 0xa03c, 0xb03a, 0xc028, 0xd02e, 0xe024, 0xf022, 0x8065, 0x9063, 0xa069, 0xb06f, 0xc07d, 0xd07b, 0xe071, 0xf077, 0x0055, 0x1053, 0x2059, 0x305f, 0x404d, 0x504b, 0x6041, 0x7047, 0x80cf, 0x90c9, 0xa0c3, 0xb0c5, 0xc0d7, 0xd0d1, 0xe0db, 0xf0dd, 0x00ff, 0x10f9, 0x20f3, 0x30f5, 0x40e7, 0x50e1, 0x60eb, 0x70ed, 0x00aa, 0x10ac, 0x20a6, 0x30a0, 0x40b2, 0x50b4, 0x60be, 0x70b8, 0x809a, 0x909c, 0xa096, 0xb090, 0xc082, 0xd084, 0xe08e, 0xf088, 0x819b, 0x919d, 0xa197, 0xb191, 0xc183, 0xd185, 0xe18f, 0xf189, 0x01ab, 0x11ad, 0x21a7, 0x31a1, 0x41b3, 0x51b5, 0x61bf, 0x71b9, 0x01fe, 0x11f8, 0x21f2, 0x31f4, 0x41e6, 0x51e0, 0x61ea, 0x71ec, 0x81ce, 0x91c8, 0xa1c2, 0xb1c4, 0xc1d6, 0xd1d0, 0xe1da, 0xf1dc, 0x0154, 0x1152, 0x2158, 0x315e, 0x414c, 0x514a, 0x6140, 0x7146, 0x8164, 0x9162, 0xa168, 0xb16e, 0xc17c, 0xd17a, 0xe170, 0xf176, 0x8131, 0x9137, 0xa13d, 0xb13b, 0xc129, 0xd12f, 0xe125, 0xf123, 0x0101, 0x1107, 0x210d, 0x310b, 0x4119, 0x511f, 0x6115, 0x7113, 0x8333, 0x9335, 0xa33f, 0xb339, 0xc32b, 0xd32d, 0xe327, 0xf321, 0x0303, 0x1305, 0x230f, 0x3309, 0x431b, 0x531d, 0x6317, 0x7311, 0x0356, 0x1350, 0x235a, 0x335c, 0x434e, 0x5348, 0x6342, 0x7344, 0x8366, 0x9360, 0xa36a, 0xb36c, 0xc37e, 0xd378, 0xe372, 0xf374, 0x03fc, 0x13fa, 0x23f0, 0x33f6, 0x43e4, 0x53e2, 0x63e8, 0x73ee, 0x83cc, 0x93ca, 0xa3c0, 0xb3c6, 0xc3d4, 0xd3d2, 0xe3d8, 0xf3de, 0x8399, 0x939f, 0xa395, 0xb393, 0xc381, 0xd387, 0xe38d, 0xf38b, 0x03a9, 0x13af, 0x23a5, 0x33a3, 0x43b1, 0x53b7, 0x63bd, 0x73bb, 0x02a8, 0x12ae, 0x22a4, 0x32a2, 0x42b0, 0x52b6, 0x62bc, 0x72ba, 0x8298, 0x929e, 0xa294, 0xb292, 0xc280, 0xd286, 0xe28c, 0xf28a, 0x82cd, 0x92cb, 0xa2c1, 0xb2c7, 0xc2d5, 0xd2d3, 0xe2d9, 0xf2df, 0x02fd, 0x12fb, 0x22f1, 0x32f7, 0x42e5, 0x52e3, 0x62e9, 0x72ef, 0x8267, 0x9261, 0xa26b, 0xb26d, 0xc27f, 0xd279, 0xe273, 0xf275, 0x0257, 0x1251, 0x225b, 0x325d, 0x424f, 0x5249, 0x6243, 0x7245, 0x0202, 0x1204, 0x220e, 0x3208, 0x421a, 0x521c, 0x6216, 0x7210, 0x8232, 0x9234, 0xa23e, 0xb238, 0xc22a, 0xd22c, 0xe226, 0xf220, ] ]; /// `Crc16Ansi` implements the CRC-16 algorithm using the ANSI polynominal. /// /// * Polynomial = 0x8005 /// * RefIn = false /// * RefOut = false /// * XorOut = false pub struct Crc16Ansi { state: u16, } impl Crc16Ansi { /// Instantiate a `Crc16Ansi` instance with an initial state. pub fn new(state: u16) -> Self { Crc16Ansi { state } } /// Returns the computed CRC. pub fn crc(&self) -> u16 { self.state } } impl Monitor for Crc16Ansi { #[inline(always)] fn process_byte(&mut self, byte: u8) { self.state = (self.state << 8) ^ CRC16_ANSI[0][((self.state >> 8) as u8 ^ byte) as usize]; } fn process_buf_bytes(&mut self, buf: &[u8]) { let mut iter = buf.chunks_exact(8); for bytes in &mut iter { let word = (u16::from(bytes[0]) << 8) | u16::from(bytes[1]); let xor = self.state ^ word; self.state = CRC16_ANSI[7][((xor >> 8) & 0xff) as usize] ^ CRC16_ANSI[6][((xor >> 0) & 0xff) as usize] ^ CRC16_ANSI[5][usize::from(bytes[2])] ^ CRC16_ANSI[4][usize::from(bytes[3])] ^ CRC16_ANSI[3][usize::from(bytes[4])] ^ CRC16_ANSI[2][usize::from(bytes[5])] ^ CRC16_ANSI[1][usize::from(bytes[6])] ^ CRC16_ANSI[0][usize::from(bytes[7])]; } for byte in iter.remainder() { self.process_byte(*byte); } } } #[rustfmt::skip] const CRC16_ANSI_LE: [u16; 256] = [ 0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241, 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440, 0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40, 0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841, 0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40, 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41, 0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641, 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040, 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240, 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441, 0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41, 0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840, 0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41, 0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40, 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640, 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041, 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240, 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441, 0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41, 0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840, 0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41, 0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40, 0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640, 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041, 0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241, 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440, 0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40, 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841, 0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40, 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41, 0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641, 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040, ]; /// `Crc16AnsiLe` implements the CRC-16 algorithm using the ANSI polynominal in little-endian byte /// order. /// /// * Polynomial = 0x8005 /// * RefIn = false /// * RefOut = false /// * XorOut = false pub struct Crc16AnsiLe { state: u16, } impl Crc16AnsiLe { /// Instantiate a `Crc16AnsiLe` instance with an initial state. pub fn new(state: u16) -> Self { Crc16AnsiLe { state } } /// Returns the computed CRC. pub fn crc(&self) -> u16 { self.state } } impl Monitor for Crc16AnsiLe { #[inline(always)] fn process_byte(&mut self, byte: u8) { self.state = (self.state >> 8) ^ CRC16_ANSI_LE[(self.state as u8 ^ byte) as usize]; } fn process_buf_bytes(&mut self, buf: &[u8]) { // TODO: Implement by-8 method. for byte in buf.iter() { self.process_byte(*byte); } } } symphonia-core-0.5.4/src/checksum/crc32.rs000064400000000000000000000763171046102023000164600ustar 00000000000000// Symphonia // Copyright (c) 2019-2022 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/. use crate::io::Monitor; #[rustfmt::skip] const CRC32: [[u32; 256]; 8] = [ [ 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4, ], [ 0x00000000, 0xd219c1dc, 0xa0f29e0f, 0x72eb5fd3, 0x452421a9, 0x973de075, 0xe5d6bfa6, 0x37cf7e7a, 0x8a484352, 0x5851828e, 0x2abadd5d, 0xf8a31c81, 0xcf6c62fb, 0x1d75a327, 0x6f9efcf4, 0xbd873d28, 0x10519b13, 0xc2485acf, 0xb0a3051c, 0x62bac4c0, 0x5575baba, 0x876c7b66, 0xf58724b5, 0x279ee569, 0x9a19d841, 0x4800199d, 0x3aeb464e, 0xe8f28792, 0xdf3df9e8, 0x0d243834, 0x7fcf67e7, 0xadd6a63b, 0x20a33626, 0xf2baf7fa, 0x8051a829, 0x524869f5, 0x6587178f, 0xb79ed653, 0xc5758980, 0x176c485c, 0xaaeb7574, 0x78f2b4a8, 0x0a19eb7b, 0xd8002aa7, 0xefcf54dd, 0x3dd69501, 0x4f3dcad2, 0x9d240b0e, 0x30f2ad35, 0xe2eb6ce9, 0x9000333a, 0x4219f2e6, 0x75d68c9c, 0xa7cf4d40, 0xd5241293, 0x073dd34f, 0xbabaee67, 0x68a32fbb, 0x1a487068, 0xc851b1b4, 0xff9ecfce, 0x2d870e12, 0x5f6c51c1, 0x8d75901d, 0x41466c4c, 0x935fad90, 0xe1b4f243, 0x33ad339f, 0x04624de5, 0xd67b8c39, 0xa490d3ea, 0x76891236, 0xcb0e2f1e, 0x1917eec2, 0x6bfcb111, 0xb9e570cd, 0x8e2a0eb7, 0x5c33cf6b, 0x2ed890b8, 0xfcc15164, 0x5117f75f, 0x830e3683, 0xf1e56950, 0x23fca88c, 0x1433d6f6, 0xc62a172a, 0xb4c148f9, 0x66d88925, 0xdb5fb40d, 0x094675d1, 0x7bad2a02, 0xa9b4ebde, 0x9e7b95a4, 0x4c625478, 0x3e890bab, 0xec90ca77, 0x61e55a6a, 0xb3fc9bb6, 0xc117c465, 0x130e05b9, 0x24c17bc3, 0xf6d8ba1f, 0x8433e5cc, 0x562a2410, 0xebad1938, 0x39b4d8e4, 0x4b5f8737, 0x994646eb, 0xae893891, 0x7c90f94d, 0x0e7ba69e, 0xdc626742, 0x71b4c179, 0xa3ad00a5, 0xd1465f76, 0x035f9eaa, 0x3490e0d0, 0xe689210c, 0x94627edf, 0x467bbf03, 0xfbfc822b, 0x29e543f7, 0x5b0e1c24, 0x8917ddf8, 0xbed8a382, 0x6cc1625e, 0x1e2a3d8d, 0xcc33fc51, 0x828cd898, 0x50951944, 0x227e4697, 0xf067874b, 0xc7a8f931, 0x15b138ed, 0x675a673e, 0xb543a6e2, 0x08c49bca, 0xdadd5a16, 0xa83605c5, 0x7a2fc419, 0x4de0ba63, 0x9ff97bbf, 0xed12246c, 0x3f0be5b0, 0x92dd438b, 0x40c48257, 0x322fdd84, 0xe0361c58, 0xd7f96222, 0x05e0a3fe, 0x770bfc2d, 0xa5123df1, 0x189500d9, 0xca8cc105, 0xb8679ed6, 0x6a7e5f0a, 0x5db12170, 0x8fa8e0ac, 0xfd43bf7f, 0x2f5a7ea3, 0xa22feebe, 0x70362f62, 0x02dd70b1, 0xd0c4b16d, 0xe70bcf17, 0x35120ecb, 0x47f95118, 0x95e090c4, 0x2867adec, 0xfa7e6c30, 0x889533e3, 0x5a8cf23f, 0x6d438c45, 0xbf5a4d99, 0xcdb1124a, 0x1fa8d396, 0xb27e75ad, 0x6067b471, 0x128ceba2, 0xc0952a7e, 0xf75a5404, 0x254395d8, 0x57a8ca0b, 0x85b10bd7, 0x383636ff, 0xea2ff723, 0x98c4a8f0, 0x4add692c, 0x7d121756, 0xaf0bd68a, 0xdde08959, 0x0ff94885, 0xc3cab4d4, 0x11d37508, 0x63382adb, 0xb121eb07, 0x86ee957d, 0x54f754a1, 0x261c0b72, 0xf405caae, 0x4982f786, 0x9b9b365a, 0xe9706989, 0x3b69a855, 0x0ca6d62f, 0xdebf17f3, 0xac544820, 0x7e4d89fc, 0xd39b2fc7, 0x0182ee1b, 0x7369b1c8, 0xa1707014, 0x96bf0e6e, 0x44a6cfb2, 0x364d9061, 0xe45451bd, 0x59d36c95, 0x8bcaad49, 0xf921f29a, 0x2b383346, 0x1cf74d3c, 0xceee8ce0, 0xbc05d333, 0x6e1c12ef, 0xe36982f2, 0x3170432e, 0x439b1cfd, 0x9182dd21, 0xa64da35b, 0x74546287, 0x06bf3d54, 0xd4a6fc88, 0x6921c1a0, 0xbb38007c, 0xc9d35faf, 0x1bca9e73, 0x2c05e009, 0xfe1c21d5, 0x8cf77e06, 0x5eeebfda, 0xf33819e1, 0x2121d83d, 0x53ca87ee, 0x81d34632, 0xb61c3848, 0x6405f994, 0x16eea647, 0xc4f7679b, 0x79705ab3, 0xab699b6f, 0xd982c4bc, 0x0b9b0560, 0x3c547b1a, 0xee4dbac6, 0x9ca6e515, 0x4ebf24c9, ], [ 0x00000000, 0x01d8ac87, 0x03b1590e, 0x0269f589, 0x0762b21c, 0x06ba1e9b, 0x04d3eb12, 0x050b4795, 0x0ec56438, 0x0f1dc8bf, 0x0d743d36, 0x0cac91b1, 0x09a7d624, 0x087f7aa3, 0x0a168f2a, 0x0bce23ad, 0x1d8ac870, 0x1c5264f7, 0x1e3b917e, 0x1fe33df9, 0x1ae87a6c, 0x1b30d6eb, 0x19592362, 0x18818fe5, 0x134fac48, 0x129700cf, 0x10fef546, 0x112659c1, 0x142d1e54, 0x15f5b2d3, 0x179c475a, 0x1644ebdd, 0x3b1590e0, 0x3acd3c67, 0x38a4c9ee, 0x397c6569, 0x3c7722fc, 0x3daf8e7b, 0x3fc67bf2, 0x3e1ed775, 0x35d0f4d8, 0x3408585f, 0x3661add6, 0x37b90151, 0x32b246c4, 0x336aea43, 0x31031fca, 0x30dbb34d, 0x269f5890, 0x2747f417, 0x252e019e, 0x24f6ad19, 0x21fdea8c, 0x2025460b, 0x224cb382, 0x23941f05, 0x285a3ca8, 0x2982902f, 0x2beb65a6, 0x2a33c921, 0x2f388eb4, 0x2ee02233, 0x2c89d7ba, 0x2d517b3d, 0x762b21c0, 0x77f38d47, 0x759a78ce, 0x7442d449, 0x714993dc, 0x70913f5b, 0x72f8cad2, 0x73206655, 0x78ee45f8, 0x7936e97f, 0x7b5f1cf6, 0x7a87b071, 0x7f8cf7e4, 0x7e545b63, 0x7c3daeea, 0x7de5026d, 0x6ba1e9b0, 0x6a794537, 0x6810b0be, 0x69c81c39, 0x6cc35bac, 0x6d1bf72b, 0x6f7202a2, 0x6eaaae25, 0x65648d88, 0x64bc210f, 0x66d5d486, 0x670d7801, 0x62063f94, 0x63de9313, 0x61b7669a, 0x606fca1d, 0x4d3eb120, 0x4ce61da7, 0x4e8fe82e, 0x4f5744a9, 0x4a5c033c, 0x4b84afbb, 0x49ed5a32, 0x4835f6b5, 0x43fbd518, 0x4223799f, 0x404a8c16, 0x41922091, 0x44996704, 0x4541cb83, 0x47283e0a, 0x46f0928d, 0x50b47950, 0x516cd5d7, 0x5305205e, 0x52dd8cd9, 0x57d6cb4c, 0x560e67cb, 0x54679242, 0x55bf3ec5, 0x5e711d68, 0x5fa9b1ef, 0x5dc04466, 0x5c18e8e1, 0x5913af74, 0x58cb03f3, 0x5aa2f67a, 0x5b7a5afd, 0xec564380, 0xed8eef07, 0xefe71a8e, 0xee3fb609, 0xeb34f19c, 0xeaec5d1b, 0xe885a892, 0xe95d0415, 0xe29327b8, 0xe34b8b3f, 0xe1227eb6, 0xe0fad231, 0xe5f195a4, 0xe4293923, 0xe640ccaa, 0xe798602d, 0xf1dc8bf0, 0xf0042777, 0xf26dd2fe, 0xf3b57e79, 0xf6be39ec, 0xf766956b, 0xf50f60e2, 0xf4d7cc65, 0xff19efc8, 0xfec1434f, 0xfca8b6c6, 0xfd701a41, 0xf87b5dd4, 0xf9a3f153, 0xfbca04da, 0xfa12a85d, 0xd743d360, 0xd69b7fe7, 0xd4f28a6e, 0xd52a26e9, 0xd021617c, 0xd1f9cdfb, 0xd3903872, 0xd24894f5, 0xd986b758, 0xd85e1bdf, 0xda37ee56, 0xdbef42d1, 0xdee40544, 0xdf3ca9c3, 0xdd555c4a, 0xdc8df0cd, 0xcac91b10, 0xcb11b797, 0xc978421e, 0xc8a0ee99, 0xcdaba90c, 0xcc73058b, 0xce1af002, 0xcfc25c85, 0xc40c7f28, 0xc5d4d3af, 0xc7bd2626, 0xc6658aa1, 0xc36ecd34, 0xc2b661b3, 0xc0df943a, 0xc10738bd, 0x9a7d6240, 0x9ba5cec7, 0x99cc3b4e, 0x981497c9, 0x9d1fd05c, 0x9cc77cdb, 0x9eae8952, 0x9f7625d5, 0x94b80678, 0x9560aaff, 0x97095f76, 0x96d1f3f1, 0x93dab464, 0x920218e3, 0x906bed6a, 0x91b341ed, 0x87f7aa30, 0x862f06b7, 0x8446f33e, 0x859e5fb9, 0x8095182c, 0x814db4ab, 0x83244122, 0x82fceda5, 0x8932ce08, 0x88ea628f, 0x8a839706, 0x8b5b3b81, 0x8e507c14, 0x8f88d093, 0x8de1251a, 0x8c39899d, 0xa168f2a0, 0xa0b05e27, 0xa2d9abae, 0xa3010729, 0xa60a40bc, 0xa7d2ec3b, 0xa5bb19b2, 0xa463b535, 0xafad9698, 0xae753a1f, 0xac1ccf96, 0xadc46311, 0xa8cf2484, 0xa9178803, 0xab7e7d8a, 0xaaa6d10d, 0xbce23ad0, 0xbd3a9657, 0xbf5363de, 0xbe8bcf59, 0xbb8088cc, 0xba58244b, 0xb831d1c2, 0xb9e97d45, 0xb2275ee8, 0xb3fff26f, 0xb19607e6, 0xb04eab61, 0xb545ecf4, 0xb49d4073, 0xb6f4b5fa, 0xb72c197d, ], [ 0x00000000, 0xdc6d9ab7, 0xbc1a28d9, 0x6077b26e, 0x7cf54c05, 0xa098d6b2, 0xc0ef64dc, 0x1c82fe6b, 0xf9ea980a, 0x258702bd, 0x45f0b0d3, 0x999d2a64, 0x851fd40f, 0x59724eb8, 0x3905fcd6, 0xe5686661, 0xf7142da3, 0x2b79b714, 0x4b0e057a, 0x97639fcd, 0x8be161a6, 0x578cfb11, 0x37fb497f, 0xeb96d3c8, 0x0efeb5a9, 0xd2932f1e, 0xb2e49d70, 0x6e8907c7, 0x720bf9ac, 0xae66631b, 0xce11d175, 0x127c4bc2, 0xeae946f1, 0x3684dc46, 0x56f36e28, 0x8a9ef49f, 0x961c0af4, 0x4a719043, 0x2a06222d, 0xf66bb89a, 0x1303defb, 0xcf6e444c, 0xaf19f622, 0x73746c95, 0x6ff692fe, 0xb39b0849, 0xd3ecba27, 0x0f812090, 0x1dfd6b52, 0xc190f1e5, 0xa1e7438b, 0x7d8ad93c, 0x61082757, 0xbd65bde0, 0xdd120f8e, 0x017f9539, 0xe417f358, 0x387a69ef, 0x580ddb81, 0x84604136, 0x98e2bf5d, 0x448f25ea, 0x24f89784, 0xf8950d33, 0xd1139055, 0x0d7e0ae2, 0x6d09b88c, 0xb164223b, 0xade6dc50, 0x718b46e7, 0x11fcf489, 0xcd916e3e, 0x28f9085f, 0xf49492e8, 0x94e32086, 0x488eba31, 0x540c445a, 0x8861deed, 0xe8166c83, 0x347bf634, 0x2607bdf6, 0xfa6a2741, 0x9a1d952f, 0x46700f98, 0x5af2f1f3, 0x869f6b44, 0xe6e8d92a, 0x3a85439d, 0xdfed25fc, 0x0380bf4b, 0x63f70d25, 0xbf9a9792, 0xa31869f9, 0x7f75f34e, 0x1f024120, 0xc36fdb97, 0x3bfad6a4, 0xe7974c13, 0x87e0fe7d, 0x5b8d64ca, 0x470f9aa1, 0x9b620016, 0xfb15b278, 0x277828cf, 0xc2104eae, 0x1e7dd419, 0x7e0a6677, 0xa267fcc0, 0xbee502ab, 0x6288981c, 0x02ff2a72, 0xde92b0c5, 0xcceefb07, 0x108361b0, 0x70f4d3de, 0xac994969, 0xb01bb702, 0x6c762db5, 0x0c019fdb, 0xd06c056c, 0x3504630d, 0xe969f9ba, 0x891e4bd4, 0x5573d163, 0x49f12f08, 0x959cb5bf, 0xf5eb07d1, 0x29869d66, 0xa6e63d1d, 0x7a8ba7aa, 0x1afc15c4, 0xc6918f73, 0xda137118, 0x067eebaf, 0x660959c1, 0xba64c376, 0x5f0ca517, 0x83613fa0, 0xe3168dce, 0x3f7b1779, 0x23f9e912, 0xff9473a5, 0x9fe3c1cb, 0x438e5b7c, 0x51f210be, 0x8d9f8a09, 0xede83867, 0x3185a2d0, 0x2d075cbb, 0xf16ac60c, 0x911d7462, 0x4d70eed5, 0xa81888b4, 0x74751203, 0x1402a06d, 0xc86f3ada, 0xd4edc4b1, 0x08805e06, 0x68f7ec68, 0xb49a76df, 0x4c0f7bec, 0x9062e15b, 0xf0155335, 0x2c78c982, 0x30fa37e9, 0xec97ad5e, 0x8ce01f30, 0x508d8587, 0xb5e5e3e6, 0x69887951, 0x09ffcb3f, 0xd5925188, 0xc910afe3, 0x157d3554, 0x750a873a, 0xa9671d8d, 0xbb1b564f, 0x6776ccf8, 0x07017e96, 0xdb6ce421, 0xc7ee1a4a, 0x1b8380fd, 0x7bf43293, 0xa799a824, 0x42f1ce45, 0x9e9c54f2, 0xfeebe69c, 0x22867c2b, 0x3e048240, 0xe26918f7, 0x821eaa99, 0x5e73302e, 0x77f5ad48, 0xab9837ff, 0xcbef8591, 0x17821f26, 0x0b00e14d, 0xd76d7bfa, 0xb71ac994, 0x6b775323, 0x8e1f3542, 0x5272aff5, 0x32051d9b, 0xee68872c, 0xf2ea7947, 0x2e87e3f0, 0x4ef0519e, 0x929dcb29, 0x80e180eb, 0x5c8c1a5c, 0x3cfba832, 0xe0963285, 0xfc14ccee, 0x20795659, 0x400ee437, 0x9c637e80, 0x790b18e1, 0xa5668256, 0xc5113038, 0x197caa8f, 0x05fe54e4, 0xd993ce53, 0xb9e47c3d, 0x6589e68a, 0x9d1cebb9, 0x4171710e, 0x2106c360, 0xfd6b59d7, 0xe1e9a7bc, 0x3d843d0b, 0x5df38f65, 0x819e15d2, 0x64f673b3, 0xb89be904, 0xd8ec5b6a, 0x0481c1dd, 0x18033fb6, 0xc46ea501, 0xa419176f, 0x78748dd8, 0x6a08c61a, 0xb6655cad, 0xd612eec3, 0x0a7f7474, 0x16fd8a1f, 0xca9010a8, 0xaae7a2c6, 0x768a3871, 0x93e25e10, 0x4f8fc4a7, 0x2ff876c9, 0xf395ec7e, 0xef171215, 0x337a88a2, 0x530d3acc, 0x8f60a07b, ], [ 0x00000000, 0x490d678d, 0x921acf1a, 0xdb17a897, 0x20f48383, 0x69f9e40e, 0xb2ee4c99, 0xfbe32b14, 0x41e90706, 0x08e4608b, 0xd3f3c81c, 0x9afeaf91, 0x611d8485, 0x2810e308, 0xf3074b9f, 0xba0a2c12, 0x83d20e0c, 0xcadf6981, 0x11c8c116, 0x58c5a69b, 0xa3268d8f, 0xea2bea02, 0x313c4295, 0x78312518, 0xc23b090a, 0x8b366e87, 0x5021c610, 0x192ca19d, 0xe2cf8a89, 0xabc2ed04, 0x70d54593, 0x39d8221e, 0x036501af, 0x4a686622, 0x917fceb5, 0xd872a938, 0x2391822c, 0x6a9ce5a1, 0xb18b4d36, 0xf8862abb, 0x428c06a9, 0x0b816124, 0xd096c9b3, 0x999bae3e, 0x6278852a, 0x2b75e2a7, 0xf0624a30, 0xb96f2dbd, 0x80b70fa3, 0xc9ba682e, 0x12adc0b9, 0x5ba0a734, 0xa0438c20, 0xe94eebad, 0x3259433a, 0x7b5424b7, 0xc15e08a5, 0x88536f28, 0x5344c7bf, 0x1a49a032, 0xe1aa8b26, 0xa8a7ecab, 0x73b0443c, 0x3abd23b1, 0x06ca035e, 0x4fc764d3, 0x94d0cc44, 0xddddabc9, 0x263e80dd, 0x6f33e750, 0xb4244fc7, 0xfd29284a, 0x47230458, 0x0e2e63d5, 0xd539cb42, 0x9c34accf, 0x67d787db, 0x2edae056, 0xf5cd48c1, 0xbcc02f4c, 0x85180d52, 0xcc156adf, 0x1702c248, 0x5e0fa5c5, 0xa5ec8ed1, 0xece1e95c, 0x37f641cb, 0x7efb2646, 0xc4f10a54, 0x8dfc6dd9, 0x56ebc54e, 0x1fe6a2c3, 0xe40589d7, 0xad08ee5a, 0x761f46cd, 0x3f122140, 0x05af02f1, 0x4ca2657c, 0x97b5cdeb, 0xdeb8aa66, 0x255b8172, 0x6c56e6ff, 0xb7414e68, 0xfe4c29e5, 0x444605f7, 0x0d4b627a, 0xd65ccaed, 0x9f51ad60, 0x64b28674, 0x2dbfe1f9, 0xf6a8496e, 0xbfa52ee3, 0x867d0cfd, 0xcf706b70, 0x1467c3e7, 0x5d6aa46a, 0xa6898f7e, 0xef84e8f3, 0x34934064, 0x7d9e27e9, 0xc7940bfb, 0x8e996c76, 0x558ec4e1, 0x1c83a36c, 0xe7608878, 0xae6deff5, 0x757a4762, 0x3c7720ef, 0x0d9406bc, 0x44996131, 0x9f8ec9a6, 0xd683ae2b, 0x2d60853f, 0x646de2b2, 0xbf7a4a25, 0xf6772da8, 0x4c7d01ba, 0x05706637, 0xde67cea0, 0x976aa92d, 0x6c898239, 0x2584e5b4, 0xfe934d23, 0xb79e2aae, 0x8e4608b0, 0xc74b6f3d, 0x1c5cc7aa, 0x5551a027, 0xaeb28b33, 0xe7bfecbe, 0x3ca84429, 0x75a523a4, 0xcfaf0fb6, 0x86a2683b, 0x5db5c0ac, 0x14b8a721, 0xef5b8c35, 0xa656ebb8, 0x7d41432f, 0x344c24a2, 0x0ef10713, 0x47fc609e, 0x9cebc809, 0xd5e6af84, 0x2e058490, 0x6708e31d, 0xbc1f4b8a, 0xf5122c07, 0x4f180015, 0x06156798, 0xdd02cf0f, 0x940fa882, 0x6fec8396, 0x26e1e41b, 0xfdf64c8c, 0xb4fb2b01, 0x8d23091f, 0xc42e6e92, 0x1f39c605, 0x5634a188, 0xadd78a9c, 0xe4daed11, 0x3fcd4586, 0x76c0220b, 0xccca0e19, 0x85c76994, 0x5ed0c103, 0x17dda68e, 0xec3e8d9a, 0xa533ea17, 0x7e244280, 0x3729250d, 0x0b5e05e2, 0x4253626f, 0x9944caf8, 0xd049ad75, 0x2baa8661, 0x62a7e1ec, 0xb9b0497b, 0xf0bd2ef6, 0x4ab702e4, 0x03ba6569, 0xd8adcdfe, 0x91a0aa73, 0x6a438167, 0x234ee6ea, 0xf8594e7d, 0xb15429f0, 0x888c0bee, 0xc1816c63, 0x1a96c4f4, 0x539ba379, 0xa878886d, 0xe175efe0, 0x3a624777, 0x736f20fa, 0xc9650ce8, 0x80686b65, 0x5b7fc3f2, 0x1272a47f, 0xe9918f6b, 0xa09ce8e6, 0x7b8b4071, 0x328627fc, 0x083b044d, 0x413663c0, 0x9a21cb57, 0xd32cacda, 0x28cf87ce, 0x61c2e043, 0xbad548d4, 0xf3d82f59, 0x49d2034b, 0x00df64c6, 0xdbc8cc51, 0x92c5abdc, 0x692680c8, 0x202be745, 0xfb3c4fd2, 0xb231285f, 0x8be90a41, 0xc2e46dcc, 0x19f3c55b, 0x50fea2d6, 0xab1d89c2, 0xe210ee4f, 0x390746d8, 0x700a2155, 0xca000d47, 0x830d6aca, 0x581ac25d, 0x1117a5d0, 0xeaf48ec4, 0xa3f9e949, 0x78ee41de, 0x31e32653, ], [ 0x00000000, 0x1b280d78, 0x36501af0, 0x2d781788, 0x6ca035e0, 0x77883898, 0x5af02f10, 0x41d82268, 0xd9406bc0, 0xc26866b8, 0xef107130, 0xf4387c48, 0xb5e05e20, 0xaec85358, 0x83b044d0, 0x989849a8, 0xb641ca37, 0xad69c74f, 0x8011d0c7, 0x9b39ddbf, 0xdae1ffd7, 0xc1c9f2af, 0xecb1e527, 0xf799e85f, 0x6f01a1f7, 0x7429ac8f, 0x5951bb07, 0x4279b67f, 0x03a19417, 0x1889996f, 0x35f18ee7, 0x2ed9839f, 0x684289d9, 0x736a84a1, 0x5e129329, 0x453a9e51, 0x04e2bc39, 0x1fcab141, 0x32b2a6c9, 0x299aabb1, 0xb102e219, 0xaa2aef61, 0x8752f8e9, 0x9c7af591, 0xdda2d7f9, 0xc68ada81, 0xebf2cd09, 0xf0dac071, 0xde0343ee, 0xc52b4e96, 0xe853591e, 0xf37b5466, 0xb2a3760e, 0xa98b7b76, 0x84f36cfe, 0x9fdb6186, 0x0743282e, 0x1c6b2556, 0x311332de, 0x2a3b3fa6, 0x6be31dce, 0x70cb10b6, 0x5db3073e, 0x469b0a46, 0xd08513b2, 0xcbad1eca, 0xe6d50942, 0xfdfd043a, 0xbc252652, 0xa70d2b2a, 0x8a753ca2, 0x915d31da, 0x09c57872, 0x12ed750a, 0x3f956282, 0x24bd6ffa, 0x65654d92, 0x7e4d40ea, 0x53355762, 0x481d5a1a, 0x66c4d985, 0x7decd4fd, 0x5094c375, 0x4bbcce0d, 0x0a64ec65, 0x114ce11d, 0x3c34f695, 0x271cfbed, 0xbf84b245, 0xa4acbf3d, 0x89d4a8b5, 0x92fca5cd, 0xd32487a5, 0xc80c8add, 0xe5749d55, 0xfe5c902d, 0xb8c79a6b, 0xa3ef9713, 0x8e97809b, 0x95bf8de3, 0xd467af8b, 0xcf4fa2f3, 0xe237b57b, 0xf91fb803, 0x6187f1ab, 0x7aaffcd3, 0x57d7eb5b, 0x4cffe623, 0x0d27c44b, 0x160fc933, 0x3b77debb, 0x205fd3c3, 0x0e86505c, 0x15ae5d24, 0x38d64aac, 0x23fe47d4, 0x622665bc, 0x790e68c4, 0x54767f4c, 0x4f5e7234, 0xd7c63b9c, 0xccee36e4, 0xe196216c, 0xfabe2c14, 0xbb660e7c, 0xa04e0304, 0x8d36148c, 0x961e19f4, 0xa5cb3ad3, 0xbee337ab, 0x939b2023, 0x88b32d5b, 0xc96b0f33, 0xd243024b, 0xff3b15c3, 0xe41318bb, 0x7c8b5113, 0x67a35c6b, 0x4adb4be3, 0x51f3469b, 0x102b64f3, 0x0b03698b, 0x267b7e03, 0x3d53737b, 0x138af0e4, 0x08a2fd9c, 0x25daea14, 0x3ef2e76c, 0x7f2ac504, 0x6402c87c, 0x497adff4, 0x5252d28c, 0xcaca9b24, 0xd1e2965c, 0xfc9a81d4, 0xe7b28cac, 0xa66aaec4, 0xbd42a3bc, 0x903ab434, 0x8b12b94c, 0xcd89b30a, 0xd6a1be72, 0xfbd9a9fa, 0xe0f1a482, 0xa12986ea, 0xba018b92, 0x97799c1a, 0x8c519162, 0x14c9d8ca, 0x0fe1d5b2, 0x2299c23a, 0x39b1cf42, 0x7869ed2a, 0x6341e052, 0x4e39f7da, 0x5511faa2, 0x7bc8793d, 0x60e07445, 0x4d9863cd, 0x56b06eb5, 0x17684cdd, 0x0c4041a5, 0x2138562d, 0x3a105b55, 0xa28812fd, 0xb9a01f85, 0x94d8080d, 0x8ff00575, 0xce28271d, 0xd5002a65, 0xf8783ded, 0xe3503095, 0x754e2961, 0x6e662419, 0x431e3391, 0x58363ee9, 0x19ee1c81, 0x02c611f9, 0x2fbe0671, 0x34960b09, 0xac0e42a1, 0xb7264fd9, 0x9a5e5851, 0x81765529, 0xc0ae7741, 0xdb867a39, 0xf6fe6db1, 0xedd660c9, 0xc30fe356, 0xd827ee2e, 0xf55ff9a6, 0xee77f4de, 0xafafd6b6, 0xb487dbce, 0x99ffcc46, 0x82d7c13e, 0x1a4f8896, 0x016785ee, 0x2c1f9266, 0x37379f1e, 0x76efbd76, 0x6dc7b00e, 0x40bfa786, 0x5b97aafe, 0x1d0ca0b8, 0x0624adc0, 0x2b5cba48, 0x3074b730, 0x71ac9558, 0x6a849820, 0x47fc8fa8, 0x5cd482d0, 0xc44ccb78, 0xdf64c600, 0xf21cd188, 0xe934dcf0, 0xa8ecfe98, 0xb3c4f3e0, 0x9ebce468, 0x8594e910, 0xab4d6a8f, 0xb06567f7, 0x9d1d707f, 0x86357d07, 0xc7ed5f6f, 0xdcc55217, 0xf1bd459f, 0xea9548e7, 0x720d014f, 0x69250c37, 0x445d1bbf, 0x5f7516c7, 0x1ead34af, 0x058539d7, 0x28fd2e5f, 0x33d52327, ], [ 0x00000000, 0x4f576811, 0x9eaed022, 0xd1f9b833, 0x399cbdf3, 0x76cbd5e2, 0xa7326dd1, 0xe86505c0, 0x73397be6, 0x3c6e13f7, 0xed97abc4, 0xa2c0c3d5, 0x4aa5c615, 0x05f2ae04, 0xd40b1637, 0x9b5c7e26, 0xe672f7cc, 0xa9259fdd, 0x78dc27ee, 0x378b4fff, 0xdfee4a3f, 0x90b9222e, 0x41409a1d, 0x0e17f20c, 0x954b8c2a, 0xda1ce43b, 0x0be55c08, 0x44b23419, 0xacd731d9, 0xe38059c8, 0x3279e1fb, 0x7d2e89ea, 0xc824f22f, 0x87739a3e, 0x568a220d, 0x19dd4a1c, 0xf1b84fdc, 0xbeef27cd, 0x6f169ffe, 0x2041f7ef, 0xbb1d89c9, 0xf44ae1d8, 0x25b359eb, 0x6ae431fa, 0x8281343a, 0xcdd65c2b, 0x1c2fe418, 0x53788c09, 0x2e5605e3, 0x61016df2, 0xb0f8d5c1, 0xffafbdd0, 0x17cab810, 0x589dd001, 0x89646832, 0xc6330023, 0x5d6f7e05, 0x12381614, 0xc3c1ae27, 0x8c96c636, 0x64f3c3f6, 0x2ba4abe7, 0xfa5d13d4, 0xb50a7bc5, 0x9488f9e9, 0xdbdf91f8, 0x0a2629cb, 0x457141da, 0xad14441a, 0xe2432c0b, 0x33ba9438, 0x7cedfc29, 0xe7b1820f, 0xa8e6ea1e, 0x791f522d, 0x36483a3c, 0xde2d3ffc, 0x917a57ed, 0x4083efde, 0x0fd487cf, 0x72fa0e25, 0x3dad6634, 0xec54de07, 0xa303b616, 0x4b66b3d6, 0x0431dbc7, 0xd5c863f4, 0x9a9f0be5, 0x01c375c3, 0x4e941dd2, 0x9f6da5e1, 0xd03acdf0, 0x385fc830, 0x7708a021, 0xa6f11812, 0xe9a67003, 0x5cac0bc6, 0x13fb63d7, 0xc202dbe4, 0x8d55b3f5, 0x6530b635, 0x2a67de24, 0xfb9e6617, 0xb4c90e06, 0x2f957020, 0x60c21831, 0xb13ba002, 0xfe6cc813, 0x1609cdd3, 0x595ea5c2, 0x88a71df1, 0xc7f075e0, 0xbadefc0a, 0xf589941b, 0x24702c28, 0x6b274439, 0x834241f9, 0xcc1529e8, 0x1dec91db, 0x52bbf9ca, 0xc9e787ec, 0x86b0effd, 0x574957ce, 0x181e3fdf, 0xf07b3a1f, 0xbf2c520e, 0x6ed5ea3d, 0x2182822c, 0x2dd0ee65, 0x62878674, 0xb37e3e47, 0xfc295656, 0x144c5396, 0x5b1b3b87, 0x8ae283b4, 0xc5b5eba5, 0x5ee99583, 0x11befd92, 0xc04745a1, 0x8f102db0, 0x67752870, 0x28224061, 0xf9dbf852, 0xb68c9043, 0xcba219a9, 0x84f571b8, 0x550cc98b, 0x1a5ba19a, 0xf23ea45a, 0xbd69cc4b, 0x6c907478, 0x23c71c69, 0xb89b624f, 0xf7cc0a5e, 0x2635b26d, 0x6962da7c, 0x8107dfbc, 0xce50b7ad, 0x1fa90f9e, 0x50fe678f, 0xe5f41c4a, 0xaaa3745b, 0x7b5acc68, 0x340da479, 0xdc68a1b9, 0x933fc9a8, 0x42c6719b, 0x0d91198a, 0x96cd67ac, 0xd99a0fbd, 0x0863b78e, 0x4734df9f, 0xaf51da5f, 0xe006b24e, 0x31ff0a7d, 0x7ea8626c, 0x0386eb86, 0x4cd18397, 0x9d283ba4, 0xd27f53b5, 0x3a1a5675, 0x754d3e64, 0xa4b48657, 0xebe3ee46, 0x70bf9060, 0x3fe8f871, 0xee114042, 0xa1462853, 0x49232d93, 0x06744582, 0xd78dfdb1, 0x98da95a0, 0xb958178c, 0xf60f7f9d, 0x27f6c7ae, 0x68a1afbf, 0x80c4aa7f, 0xcf93c26e, 0x1e6a7a5d, 0x513d124c, 0xca616c6a, 0x8536047b, 0x54cfbc48, 0x1b98d459, 0xf3fdd199, 0xbcaab988, 0x6d5301bb, 0x220469aa, 0x5f2ae040, 0x107d8851, 0xc1843062, 0x8ed35873, 0x66b65db3, 0x29e135a2, 0xf8188d91, 0xb74fe580, 0x2c139ba6, 0x6344f3b7, 0xb2bd4b84, 0xfdea2395, 0x158f2655, 0x5ad84e44, 0x8b21f677, 0xc4769e66, 0x717ce5a3, 0x3e2b8db2, 0xefd23581, 0xa0855d90, 0x48e05850, 0x07b73041, 0xd64e8872, 0x9919e063, 0x02459e45, 0x4d12f654, 0x9ceb4e67, 0xd3bc2676, 0x3bd923b6, 0x748e4ba7, 0xa577f394, 0xea209b85, 0x970e126f, 0xd8597a7e, 0x09a0c24d, 0x46f7aa5c, 0xae92af9c, 0xe1c5c78d, 0x303c7fbe, 0x7f6b17af, 0xe4376989, 0xab600198, 0x7a99b9ab, 0x35ced1ba, 0xddabd47a, 0x92fcbc6b, 0x43050458, 0x0c526c49, ], [ 0x00000000, 0x5ba1dcca, 0xb743b994, 0xece2655e, 0x6a466e9f, 0x31e7b255, 0xdd05d70b, 0x86a40bc1, 0xd48cdd3e, 0x8f2d01f4, 0x63cf64aa, 0x386eb860, 0xbecab3a1, 0xe56b6f6b, 0x09890a35, 0x5228d6ff, 0xadd8a7cb, 0xf6797b01, 0x1a9b1e5f, 0x413ac295, 0xc79ec954, 0x9c3f159e, 0x70dd70c0, 0x2b7cac0a, 0x79547af5, 0x22f5a63f, 0xce17c361, 0x95b61fab, 0x1312146a, 0x48b3c8a0, 0xa451adfe, 0xfff07134, 0x5f705221, 0x04d18eeb, 0xe833ebb5, 0xb392377f, 0x35363cbe, 0x6e97e074, 0x8275852a, 0xd9d459e0, 0x8bfc8f1f, 0xd05d53d5, 0x3cbf368b, 0x671eea41, 0xe1bae180, 0xba1b3d4a, 0x56f95814, 0x0d5884de, 0xf2a8f5ea, 0xa9092920, 0x45eb4c7e, 0x1e4a90b4, 0x98ee9b75, 0xc34f47bf, 0x2fad22e1, 0x740cfe2b, 0x262428d4, 0x7d85f41e, 0x91679140, 0xcac64d8a, 0x4c62464b, 0x17c39a81, 0xfb21ffdf, 0xa0802315, 0xbee0a442, 0xe5417888, 0x09a31dd6, 0x5202c11c, 0xd4a6cadd, 0x8f071617, 0x63e57349, 0x3844af83, 0x6a6c797c, 0x31cda5b6, 0xdd2fc0e8, 0x868e1c22, 0x002a17e3, 0x5b8bcb29, 0xb769ae77, 0xecc872bd, 0x13380389, 0x4899df43, 0xa47bba1d, 0xffda66d7, 0x797e6d16, 0x22dfb1dc, 0xce3dd482, 0x959c0848, 0xc7b4deb7, 0x9c15027d, 0x70f76723, 0x2b56bbe9, 0xadf2b028, 0xf6536ce2, 0x1ab109bc, 0x4110d576, 0xe190f663, 0xba312aa9, 0x56d34ff7, 0x0d72933d, 0x8bd698fc, 0xd0774436, 0x3c952168, 0x6734fda2, 0x351c2b5d, 0x6ebdf797, 0x825f92c9, 0xd9fe4e03, 0x5f5a45c2, 0x04fb9908, 0xe819fc56, 0xb3b8209c, 0x4c4851a8, 0x17e98d62, 0xfb0be83c, 0xa0aa34f6, 0x260e3f37, 0x7dafe3fd, 0x914d86a3, 0xcaec5a69, 0x98c48c96, 0xc365505c, 0x2f873502, 0x7426e9c8, 0xf282e209, 0xa9233ec3, 0x45c15b9d, 0x1e608757, 0x79005533, 0x22a189f9, 0xce43eca7, 0x95e2306d, 0x13463bac, 0x48e7e766, 0xa4058238, 0xffa45ef2, 0xad8c880d, 0xf62d54c7, 0x1acf3199, 0x416eed53, 0xc7cae692, 0x9c6b3a58, 0x70895f06, 0x2b2883cc, 0xd4d8f2f8, 0x8f792e32, 0x639b4b6c, 0x383a97a6, 0xbe9e9c67, 0xe53f40ad, 0x09dd25f3, 0x527cf939, 0x00542fc6, 0x5bf5f30c, 0xb7179652, 0xecb64a98, 0x6a124159, 0x31b39d93, 0xdd51f8cd, 0x86f02407, 0x26700712, 0x7dd1dbd8, 0x9133be86, 0xca92624c, 0x4c36698d, 0x1797b547, 0xfb75d019, 0xa0d40cd3, 0xf2fcda2c, 0xa95d06e6, 0x45bf63b8, 0x1e1ebf72, 0x98bab4b3, 0xc31b6879, 0x2ff90d27, 0x7458d1ed, 0x8ba8a0d9, 0xd0097c13, 0x3ceb194d, 0x674ac587, 0xe1eece46, 0xba4f128c, 0x56ad77d2, 0x0d0cab18, 0x5f247de7, 0x0485a12d, 0xe867c473, 0xb3c618b9, 0x35621378, 0x6ec3cfb2, 0x8221aaec, 0xd9807626, 0xc7e0f171, 0x9c412dbb, 0x70a348e5, 0x2b02942f, 0xada69fee, 0xf6074324, 0x1ae5267a, 0x4144fab0, 0x136c2c4f, 0x48cdf085, 0xa42f95db, 0xff8e4911, 0x792a42d0, 0x228b9e1a, 0xce69fb44, 0x95c8278e, 0x6a3856ba, 0x31998a70, 0xdd7bef2e, 0x86da33e4, 0x007e3825, 0x5bdfe4ef, 0xb73d81b1, 0xec9c5d7b, 0xbeb48b84, 0xe515574e, 0x09f73210, 0x5256eeda, 0xd4f2e51b, 0x8f5339d1, 0x63b15c8f, 0x38108045, 0x9890a350, 0xc3317f9a, 0x2fd31ac4, 0x7472c60e, 0xf2d6cdcf, 0xa9771105, 0x4595745b, 0x1e34a891, 0x4c1c7e6e, 0x17bda2a4, 0xfb5fc7fa, 0xa0fe1b30, 0x265a10f1, 0x7dfbcc3b, 0x9119a965, 0xcab875af, 0x3548049b, 0x6ee9d851, 0x820bbd0f, 0xd9aa61c5, 0x5f0e6a04, 0x04afb6ce, 0xe84dd390, 0xb3ec0f5a, 0xe1c4d9a5, 0xba65056f, 0x56876031, 0x0d26bcfb, 0x8b82b73a, 0xd0236bf0, 0x3cc10eae, 0x6760d264, ] ]; /// `Crc32` implements the CRC-32 checksum algorithm using the standard polynomial. /// /// * Polynomial = 0x04c11db7 /// * RefIn = false /// * RefOut = false /// * XorOut = false pub struct Crc32 { state: u32, } impl Crc32 { /// Instantiates a `Crc32` instance with an initial state. pub fn new(state: u32) -> Self { Crc32 { state } } /// Returns the computed CRC. pub fn crc(&self) -> u32 { self.state } } impl Monitor for Crc32 { #[inline(always)] fn process_byte(&mut self, byte: u8) { self.state = (self.state << 8) ^ CRC32[0][usize::from((self.state >> 24) as u8 ^ byte)]; } fn process_buf_bytes(&mut self, buf: &[u8]) { let mut iter = buf.chunks_exact(8); for bytes in &mut iter { let word = (u32::from(bytes[0]) << 24) | (u32::from(bytes[1]) << 16) | (u32::from(bytes[2]) << 8) | (u32::from(bytes[3]) << 0); let xor = self.state ^ word; self.state = CRC32[7][((xor >> 24) & 0xff) as usize] ^ CRC32[6][((xor >> 16) & 0xff) as usize] ^ CRC32[5][((xor >> 8) & 0xff) as usize] ^ CRC32[4][((xor >> 0) & 0xff) as usize] ^ CRC32[3][usize::from(bytes[4])] ^ CRC32[2][usize::from(bytes[5])] ^ CRC32[1][usize::from(bytes[6])] ^ CRC32[0][usize::from(bytes[7])]; } for byte in iter.remainder() { self.process_byte(*byte); } } } #[cfg(test)] mod tests { use super::{Crc32, Monitor}; #[test] fn verify_crc32() { // Test using CRC32/MPEG2 parameters. { let mut crc = Crc32::new(0xffffffff); crc.process_buf_bytes(&[]); assert_eq!(crc.crc(), 0xffffffff); } { let mut crc = Crc32::new(0xffffffff); crc.process_buf_bytes(&[0]); assert_eq!(crc.crc(), 0x4e08bfb4); } { let mut crc = Crc32::new(0xffffffff); crc.process_buf_bytes(b"123456789"); assert_eq!(crc.crc(), 0x0376e6e7); } { let mut crc = Crc32::new(0xffffffff); crc.process_buf_bytes(b"abcdefghijklmnopqrstuvwxyz123456789"); assert_eq!(crc.crc(), 0x178dc1e0); } { let mut crc = Crc32::new(0xffffffff); crc.process_byte(b'1'); crc.process_byte(b'2'); crc.process_byte(b'3'); crc.process_byte(b'4'); crc.process_byte(b'5'); crc.process_byte(b'6'); crc.process_byte(b'7'); crc.process_byte(b'8'); crc.process_byte(b'9'); assert_eq!(crc.crc(), 0x0376e6e7); } } } symphonia-core-0.5.4/src/checksum/crc8.rs000064400000000000000000000053661046102023000163770ustar 00000000000000// Symphonia // Copyright (c) 2019-2022 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/. use crate::io::Monitor; // Credit: This table was extracted from the reference FLAC decoder. #[rustfmt::skip] const CRC8_CCITT: [u8; 256] = [ 0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15, 0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d, 0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65, 0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d, 0xe0, 0xe7, 0xee, 0xe9, 0xfc, 0xfb, 0xf2, 0xf5, 0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd, 0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85, 0xa8, 0xaf, 0xa6, 0xa1, 0xb4, 0xb3, 0xba, 0xbd, 0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2, 0xff, 0xf8, 0xf1, 0xf6, 0xe3, 0xe4, 0xed, 0xea, 0xb7, 0xb0, 0xb9, 0xbe, 0xab, 0xac, 0xa5, 0xa2, 0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, 0x9a, 0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32, 0x1f, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0d, 0x0a, 0x57, 0x50, 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42, 0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a, 0x89, 0x8e, 0x87, 0x80, 0x95, 0x92, 0x9b, 0x9c, 0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4, 0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec, 0xc1, 0xc6, 0xcf, 0xc8, 0xdd, 0xda, 0xd3, 0xd4, 0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c, 0x51, 0x56, 0x5f, 0x58, 0x4d, 0x4a, 0x43, 0x44, 0x19, 0x1e, 0x17, 0x10, 0x05, 0x02, 0x0b, 0x0c, 0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, 0x33, 0x34, 0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b, 0x76, 0x71, 0x78, 0x7f, 0x6a, 0x6d, 0x64, 0x63, 0x3e, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b, 0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13, 0xae, 0xa9, 0xa0, 0xa7, 0xb2, 0xb5, 0xbc, 0xbb, 0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8d, 0x84, 0x83, 0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb, 0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3, ]; /// `Crc8Ccitt` implements the CRC-8 algorithm using the CCITT polynominal. /// /// * Polynomial = 0x07 /// * RefIn = false /// * RefOut = false /// * XorOut = false pub struct Crc8Ccitt { state: u8, } impl Crc8Ccitt { /// Instantiate a `Crc8Ccitt` instance with an initial state. pub fn new(state: u8) -> Self { Crc8Ccitt { state } } /// Returns the computed CRC. pub fn crc(&self) -> u8 { self.state } } impl Monitor for Crc8Ccitt { #[inline(always)] fn process_byte(&mut self, byte: u8) { self.state = CRC8_CCITT[(self.state ^ byte) as usize]; } fn process_buf_bytes(&mut self, buf: &[u8]) { for byte in buf { self.state = CRC8_CCITT[(self.state ^ byte) as usize]; } } } symphonia-core-0.5.4/src/checksum/md5.rs000064400000000000000000000305711046102023000162210ustar 00000000000000// Symphonia // Copyright (c) 2019-2022 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/. use std::cmp; use crate::io::Monitor; fn transform(state: &mut [u32; 4], buf: &[u8]) { // Assert to hopefully force the compiler to elide bounds checks on buf. assert!(buf.len() == 64); let mut input = [0u32; 16]; // Collect 4 bytes from an input buffer and store as a u32 in the output buffer. Note: input // bytes are considered little-endian for MD5. macro_rules! collect { ($output:ident, $input:ident, $idx:expr) => { $output[$idx] = u32::from_le_bytes([ $input[$idx * 4 + 0], $input[$idx * 4 + 1], $input[$idx * 4 + 2], $input[$idx * 4 + 3], ]); }; } collect!(input, buf, 0); collect!(input, buf, 1); collect!(input, buf, 2); collect!(input, buf, 3); collect!(input, buf, 4); collect!(input, buf, 5); collect!(input, buf, 6); collect!(input, buf, 7); collect!(input, buf, 8); collect!(input, buf, 9); collect!(input, buf, 10); collect!(input, buf, 11); collect!(input, buf, 12); collect!(input, buf, 13); collect!(input, buf, 14); collect!(input, buf, 15); // The transformation for a single step of a round: A = B + ROTL32(F + A + K[i] + M[g], S). macro_rules! round_step { ($a:ident, $b:ident, $f:expr, $m:expr, $s:expr, $k:expr) => { $a = $f.wrapping_add($a).wrapping_add($k).wrapping_add($m); $a = $b.wrapping_add($a.rotate_left($s)); }; } let mut a = state[0]; let mut b = state[1]; let mut c = state[2]; let mut d = state[3]; // Round 1: F(B, C, D) = D xor (B and (C xor D)) { macro_rules! T { ($a:ident, $b:ident, $c:ident, $d:ident, $m:expr, $s:expr, $k:expr) => { round_step!($a, $b, $d ^ ($b & ($c ^ $d)), $m, $s, $k); }; } T!(a, b, c, d, input[0], 7, 0xd76aa478); T!(d, a, b, c, input[1], 12, 0xe8c7b756); T!(c, d, a, b, input[2], 17, 0x242070db); T!(b, c, d, a, input[3], 22, 0xc1bdceee); T!(a, b, c, d, input[4], 7, 0xf57c0faf); T!(d, a, b, c, input[5], 12, 0x4787c62a); T!(c, d, a, b, input[6], 17, 0xa8304613); T!(b, c, d, a, input[7], 22, 0xfd469501); T!(a, b, c, d, input[8], 7, 0x698098d8); T!(d, a, b, c, input[9], 12, 0x8b44f7af); T!(c, d, a, b, input[10], 17, 0xffff5bb1); T!(b, c, d, a, input[11], 22, 0x895cd7be); T!(a, b, c, d, input[12], 7, 0x6b901122); T!(d, a, b, c, input[13], 12, 0xfd987193); T!(c, d, a, b, input[14], 17, 0xa679438e); T!(b, c, d, a, input[15], 22, 0x49b40821); } // Round 2: G(B, C, D) = C xor (D and (B xor C)) { macro_rules! T { ($a:ident, $b:ident, $c:ident, $d:ident, $m:expr, $s:expr, $k:expr) => { round_step!($a, $b, $c ^ ($d & ($b ^ $c)), $m, $s, $k); }; } T!(a, b, c, d, input[1], 5, 0xf61e2562); T!(d, a, b, c, input[6], 9, 0xc040b340); T!(c, d, a, b, input[11], 14, 0x265e5a51); T!(b, c, d, a, input[0], 20, 0xe9b6c7aa); T!(a, b, c, d, input[5], 5, 0xd62f105d); T!(d, a, b, c, input[10], 9, 0x02441453); T!(c, d, a, b, input[15], 14, 0xd8a1e681); T!(b, c, d, a, input[4], 20, 0xe7d3fbc8); T!(a, b, c, d, input[9], 5, 0x21e1cde6); T!(d, a, b, c, input[14], 9, 0xc33707d6); T!(c, d, a, b, input[3], 14, 0xf4d50d87); T!(b, c, d, a, input[8], 20, 0x455a14ed); T!(a, b, c, d, input[13], 5, 0xa9e3e905); T!(d, a, b, c, input[2], 9, 0xfcefa3f8); T!(c, d, a, b, input[7], 14, 0x676f02d9); T!(b, c, d, a, input[12], 20, 0x8d2a4c8a); } // Round 3: H(B, C, D) = B xor C xor D { macro_rules! T { ($a:ident, $b:ident, $c:ident, $d:ident, $m:expr, $s:expr, $k:expr) => { round_step!($a, $b, $b ^ $c ^ $d, $m, $s, $k); }; } T!(a, b, c, d, input[5], 4, 0xfffa3942); T!(d, a, b, c, input[8], 11, 0x8771f681); T!(c, d, a, b, input[11], 16, 0x6d9d6122); T!(b, c, d, a, input[14], 23, 0xfde5380c); T!(a, b, c, d, input[1], 4, 0xa4beea44); T!(d, a, b, c, input[4], 11, 0x4bdecfa9); T!(c, d, a, b, input[7], 16, 0xf6bb4b60); T!(b, c, d, a, input[10], 23, 0xbebfbc70); T!(a, b, c, d, input[13], 4, 0x289b7ec6); T!(d, a, b, c, input[0], 11, 0xeaa127fa); T!(c, d, a, b, input[3], 16, 0xd4ef3085); T!(b, c, d, a, input[6], 23, 0x04881d05); T!(a, b, c, d, input[9], 4, 0xd9d4d039); T!(d, a, b, c, input[12], 11, 0xe6db99e5); T!(c, d, a, b, input[15], 16, 0x1fa27cf8); T!(b, c, d, a, input[2], 23, 0xc4ac5665); } // Round 4: I(B,C,D) = C xor (B or (not D)) { macro_rules! T { ($a:ident, $b:ident, $c:ident, $d:ident, $m:expr, $s:expr, $k:expr) => { round_step!($a, $b, $c ^ ($b | !$d), $m, $s, $k); }; } T!(a, b, c, d, input[0], 6, 0xf4292244); T!(d, a, b, c, input[7], 10, 0x432aff97); T!(c, d, a, b, input[14], 15, 0xab9423a7); T!(b, c, d, a, input[5], 21, 0xfc93a039); T!(a, b, c, d, input[12], 6, 0x655b59c3); T!(d, a, b, c, input[3], 10, 0x8f0ccc92); T!(c, d, a, b, input[10], 15, 0xffeff47d); T!(b, c, d, a, input[1], 21, 0x85845dd1); T!(a, b, c, d, input[8], 6, 0x6fa87e4f); T!(d, a, b, c, input[15], 10, 0xfe2ce6e0); T!(c, d, a, b, input[6], 15, 0xa3014314); T!(b, c, d, a, input[13], 21, 0x4e0811a1); T!(a, b, c, d, input[4], 6, 0xf7537e82); T!(d, a, b, c, input[11], 10, 0xbd3af235); T!(c, d, a, b, input[2], 15, 0x2ad7d2bb); T!(b, c, d, a, input[9], 21, 0xeb86d391); } state[0] = state[0].wrapping_add(a); state[1] = state[1].wrapping_add(b); state[2] = state[2].wrapping_add(c); state[3] = state[3].wrapping_add(d); } /// `Md5` implements the MD5 hashing algorithm. pub struct Md5 { state: [u32; 4], block: [u8; Md5::BLOCK_LEN], len: u64, } impl Default for Md5 { fn default() -> Self { Md5 { state: [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476], block: [0; Md5::BLOCK_LEN], len: 0, } } } impl Md5 { const BLOCK_LEN: usize = 64; const BLOCK_LEN_MASK: u64 = 0x3f; /// Finalizes and returns the computed MD5 hash. pub fn md5(&self) -> [u8; 16] { // Finalize locally. let mut block = [0; Md5::BLOCK_LEN]; let mut state = self.state; // The block length is the amount of data buffered for the current block. let block_len = (self.len & Md5::BLOCK_LEN_MASK) as usize; // The block length should *always* be less than the MD5 block length if the process_* // functions transform the block when it's full. assert!(block_len < Md5::BLOCK_LEN); // Copy the buffered block data locally for finalization. block[..block_len].copy_from_slice(&self.block[..block_len]); // Append the message terminator to the block. block[block_len] = 0x80; // If the message length can not be appended to the block, transform the block, and start // a new block. if Md5::BLOCK_LEN - block_len - 1 < 8 { transform(&mut state, &block); block = [0; Md5::BLOCK_LEN]; } // The final 8 bytes of the final block contain the message length in bits mod 2^64. block[Md5::BLOCK_LEN - 8..Md5::BLOCK_LEN].copy_from_slice(&(self.len << 3).to_le_bytes()); transform(&mut state, &block); // The message digest is in big-endian. let mut hash = [0; 16]; hash[0..4].copy_from_slice(&state[0].to_le_bytes()); hash[4..8].copy_from_slice(&state[1].to_le_bytes()); hash[8..12].copy_from_slice(&state[2].to_le_bytes()); hash[12..16].copy_from_slice(&state[3].to_le_bytes()); hash } } impl Monitor for Md5 { #[inline(always)] fn process_byte(&mut self, byte: u8) { self.block[(self.len & Md5::BLOCK_LEN_MASK) as usize] = byte; self.len += 1; // Atleast 1 bytes has been written (see above) and the length is a multiple of the MD5 // block length, therefore the current block is full. Perform a MD5 transformation on the // current block. if self.len & Md5::BLOCK_LEN_MASK == 0 { transform(&mut self.state, &self.block); } } #[inline(always)] fn process_buf_bytes(&mut self, buf: &[u8]) { let mut rem = buf; while !rem.is_empty() { let block_len = (self.len & Md5::BLOCK_LEN_MASK) as usize; let copy_len = cmp::min(rem.len(), Md5::BLOCK_LEN - block_len); self.len += copy_len as u64; // If the copy length is a whole block then perform the transformation directly from the // source buffer. if copy_len == Md5::BLOCK_LEN { transform(&mut self.state, &rem[..copy_len]); } else { // If the copy length is less than a whole block, buffer it into the current block. self.block[block_len..block_len + copy_len].copy_from_slice(&rem[..copy_len]); if self.len & Md5::BLOCK_LEN_MASK == 0 { transform(&mut self.state, &self.block); } } rem = &rem[copy_len..]; } } } #[cfg(test)] mod tests { use super::Md5; use super::Monitor; #[test] fn verify_md5() { const STRINGS: [&[u8]; 8] = [ b"", b"a", b"abc", b"The quick brown fox jumps over the lazy dog", b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!", b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!?", b".s)cyIl?XKs}wDnLEUeZj'72=A/0!w;B[e*QUh)0{&XcGvf'xMx5Chhx_'ahg{GP|_R(0=Xe`lXQN_@MK9::", ]; #[rustfmt::skip] const HASHES: [[u8; 16]; 8] = [ [ 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e, ], [ 0x0c, 0xc1, 0x75, 0xb9, 0xc0, 0xf1, 0xb6, 0xa8, 0x31, 0xc3, 0x99, 0xe2, 0x69, 0x77, 0x26, 0x61, ], [ 0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0, 0xd6, 0x96, 0x3f, 0x7d, 0x28, 0xe1, 0x7f, 0x72, ], [ 0x9e, 0x10, 0x7d, 0x9d, 0x37, 0x2b, 0xb6, 0x82, 0x6b, 0xd8, 0x1d, 0x35, 0x42, 0xa4, 0x19, 0xd6, ], [ 0xd1, 0x74, 0xab, 0x98, 0xd2, 0x77, 0xd9, 0xf5, 0xa5, 0x61, 0x1c, 0x2c, 0x9f, 0x41, 0x9d, 0x9f, ], [ 0x64, 0x1b, 0xa6, 0x02, 0x88, 0xc1, 0x7a, 0x2d, 0xa5, 0x09, 0x00, 0x77, 0xeb, 0x89, 0x58, 0xad, ], [ 0x0a, 0x71, 0xdb, 0x4d, 0xf3, 0x50, 0x92, 0x73, 0x62, 0x42, 0x3a, 0x42, 0xdc, 0xf8, 0x14, 0x57, ], [ 0x0b, 0x76, 0x74, 0x7e, 0xfd, 0xcd, 0xb9, 0x33, 0x67, 0xfe, 0x2d, 0xa3, 0x21, 0x1b, 0x5d, 0x41, ], ]; // As a buffer. for (string, hash) in STRINGS.iter().zip(&HASHES) { let mut md5: Md5 = Default::default(); md5.process_buf_bytes(string); assert_eq!(*hash, md5.md5()); } // As partial buffers. for (string, hash) in STRINGS.iter().zip(&HASHES) { let mut md5: Md5 = Default::default(); for bytes in string.chunks(21) { md5.process_buf_bytes(bytes); } assert_eq!(*hash, md5.md5()); } // Byte-by-byte for (string, hash) in STRINGS.iter().zip(&HASHES) { let mut md5: Md5 = Default::default(); for byte in string.iter() { md5.process_byte(*byte); } assert_eq!(*hash, md5.md5()); } } } symphonia-core-0.5.4/src/checksum/mod.rs000064400000000000000000000010351046102023000163040ustar 00000000000000// Symphonia // Copyright (c) 2019-2022 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/. //! The `checksum` module provides implementations of common error-detecting codes and hashing //! algorithms. mod crc16; mod crc32; mod crc8; mod md5; pub use crc16::{Crc16Ansi, Crc16AnsiLe}; pub use crc32::Crc32; pub use crc8::Crc8Ccitt; pub use md5::Md5; symphonia-core-0.5.4/src/codecs.rs000064400000000000000000000530071046102023000151710ustar 00000000000000// Symphonia // Copyright (c) 2019-2022 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/. //! The `codec` module provides the traits and support structures necessary to implement audio codec //! decoders. use std::collections::HashMap; use std::default::Default; use std::fmt; use crate::audio::{AudioBufferRef, Channels, Layout}; use crate::errors::{unsupported_error, Result}; use crate::formats::Packet; use crate::sample::SampleFormat; use crate::units::TimeBase; /// A `CodecType` is a unique identifier used to identify a specific codec. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub struct CodecType(u32); /// Declares a new `CodecType` given a character code. A character code is an ASCII string /// containing a maximum of 5 alphanumeric characters. /// /// Note: Due to the current limitations of const fn, this function is not able to panic on error. /// Therefore, if the character code contains an invalid character, then the character is dropped. /// Additionally, any extra characters will be truncated. pub const fn decl_codec_type(cc: &[u8]) -> CodecType { /// Map alphanumeric ASCII characters into a 6-bit code. const fn map_ascii_to_bits(cc: u8) -> u32 { // The mapping is defined as: // b'0'..=b'9' maps to 1..=10 // b'a'..=b'z' maps to 11..=36 // b'A'..=b'Z' maps to 37..=62 if cc.is_ascii_digit() { 1 + (cc - b'0') as u32 } else if cc.is_ascii_lowercase() { 11 + (cc - b'a') as u32 } else if cc.is_ascii_uppercase() { 37 + (cc - b'A') as u32 } else { 0 } } // TODO: assert!(cc.len() <= 5); // The upper-bit indicates the user codec namespace. let mut id = 0x8000_0000; let mut i = 0; let mut j = 0; while i < cc.len() && j < 5 { // TODO: When const panic is stabilized, assert that the character is alphanumeric to // generate an error rather than silently dropping invalid characters. // assert!(cc[i].is_ascii_alphanumeric()); // Pack the ASCII characters into the allocated 30 bits (6 bits per character) in MSb order. if cc[i].is_ascii_alphanumeric() { id |= map_ascii_to_bits(cc[i]) << (24 - (6 * j)); j += 1; } i += 1; } CodecType(id) } impl fmt::Display for CodecType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:#x}", self.0) } } /// Null codec pub const CODEC_TYPE_NULL: CodecType = CodecType(0x0); // Uncompressed PCM audio codecs //------------------------------ /// PCM signed 32-bit little-endian interleaved pub const CODEC_TYPE_PCM_S32LE: CodecType = CodecType(0x100); /// PCM signed 32-bit little-endian planar pub const CODEC_TYPE_PCM_S32LE_PLANAR: CodecType = CodecType(0x101); /// PCM signed 32-bit big-endian interleaved pub const CODEC_TYPE_PCM_S32BE: CodecType = CodecType(0x102); /// PCM signed 32-bit big-endian planar pub const CODEC_TYPE_PCM_S32BE_PLANAR: CodecType = CodecType(0x103); /// PCM signed 24-bit little-endian interleaved pub const CODEC_TYPE_PCM_S24LE: CodecType = CodecType(0x104); /// PCM signed 24-bit little-endian planar pub const CODEC_TYPE_PCM_S24LE_PLANAR: CodecType = CodecType(0x105); /// PCM signed 24-bit big-endian interleaved pub const CODEC_TYPE_PCM_S24BE: CodecType = CodecType(0x106); /// PCM signed 24-bit big-endian planar pub const CODEC_TYPE_PCM_S24BE_PLANAR: CodecType = CodecType(0x107); /// PCM signed 16-bit little-endian interleaved pub const CODEC_TYPE_PCM_S16LE: CodecType = CodecType(0x108); /// PCM signed 16-bit little-endian planar pub const CODEC_TYPE_PCM_S16LE_PLANAR: CodecType = CodecType(0x109); /// PCM signed 16-bit big-endian interleaved pub const CODEC_TYPE_PCM_S16BE: CodecType = CodecType(0x10a); /// PCM signed 16-bit big-endian planar pub const CODEC_TYPE_PCM_S16BE_PLANAR: CodecType = CodecType(0x10b); /// PCM signed 8-bit interleaved pub const CODEC_TYPE_PCM_S8: CodecType = CodecType(0x10c); /// PCM signed 8-bit planar pub const CODEC_TYPE_PCM_S8_PLANAR: CodecType = CodecType(0x10d); /// PCM unsigned 32-bit little-endian interleaved pub const CODEC_TYPE_PCM_U32LE: CodecType = CodecType(0x10e); /// PCM unsigned 32-bit little-endian planar pub const CODEC_TYPE_PCM_U32LE_PLANAR: CodecType = CodecType(0x10f); /// PCM unsigned 32-bit big-endian interleaved pub const CODEC_TYPE_PCM_U32BE: CodecType = CodecType(0x110); /// PCM unsigned 32-bit big-endian planar pub const CODEC_TYPE_PCM_U32BE_PLANAR: CodecType = CodecType(0x111); /// PCM unsigned 24-bit little-endian interleaved pub const CODEC_TYPE_PCM_U24LE: CodecType = CodecType(0x112); /// PCM unsigned 24-bit little-endian planar pub const CODEC_TYPE_PCM_U24LE_PLANAR: CodecType = CodecType(0x113); /// PCM unsigned 24-bit big-endian interleaved pub const CODEC_TYPE_PCM_U24BE: CodecType = CodecType(0x114); /// PCM unsigned 24-bit big-endian planar pub const CODEC_TYPE_PCM_U24BE_PLANAR: CodecType = CodecType(0x115); /// PCM unsigned 16-bit little-endian interleaved pub const CODEC_TYPE_PCM_U16LE: CodecType = CodecType(0x116); /// PCM unsigned 16-bit little-endian planar pub const CODEC_TYPE_PCM_U16LE_PLANAR: CodecType = CodecType(0x117); /// PCM unsigned 16-bit big-endian interleaved pub const CODEC_TYPE_PCM_U16BE: CodecType = CodecType(0x118); /// PCM unsigned 16-bit big-endian planar pub const CODEC_TYPE_PCM_U16BE_PLANAR: CodecType = CodecType(0x119); /// PCM unsigned 8-bit interleaved pub const CODEC_TYPE_PCM_U8: CodecType = CodecType(0x11a); /// PCM unsigned 8-bit planar pub const CODEC_TYPE_PCM_U8_PLANAR: CodecType = CodecType(0x11b); /// PCM 32-bit little-endian floating point interleaved pub const CODEC_TYPE_PCM_F32LE: CodecType = CodecType(0x11c); /// PCM 32-bit little-endian floating point planar pub const CODEC_TYPE_PCM_F32LE_PLANAR: CodecType = CodecType(0x11d); /// PCM 32-bit big-endian floating point interleaved pub const CODEC_TYPE_PCM_F32BE: CodecType = CodecType(0x11e); /// PCM 32-bit big-endian floating point planar pub const CODEC_TYPE_PCM_F32BE_PLANAR: CodecType = CodecType(0x11f); /// PCM 64-bit little-endian floating point interleaved pub const CODEC_TYPE_PCM_F64LE: CodecType = CodecType(0x120); /// PCM 64-bit little-endian floating point planar pub const CODEC_TYPE_PCM_F64LE_PLANAR: CodecType = CodecType(0x121); /// PCM 64-bit big-endian floating point interleaved pub const CODEC_TYPE_PCM_F64BE: CodecType = CodecType(0x122); /// PCM 64-bit big-endian floating point planar pub const CODEC_TYPE_PCM_F64BE_PLANAR: CodecType = CodecType(0x123); /// PCM A-law (G.711) pub const CODEC_TYPE_PCM_ALAW: CodecType = CodecType(0x124); /// PCM Mu-law (G.711) pub const CODEC_TYPE_PCM_MULAW: CodecType = CodecType(0x125); // ADPCM audio codecs //------------------- /// G.722 ADPCM pub const CODEC_TYPE_ADPCM_G722: CodecType = CodecType(0x200); /// G.726 ADPCM pub const CODEC_TYPE_ADPCM_G726: CodecType = CodecType(0x201); /// G.726 ADPCM little-endian pub const CODEC_TYPE_ADPCM_G726LE: CodecType = CodecType(0x202); /// Microsoft ADPCM pub const CODEC_TYPE_ADPCM_MS: CodecType = CodecType(0x203); /// ADPCM IMA WAV pub const CODEC_TYPE_ADPCM_IMA_WAV: CodecType = CodecType(0x204); /// ADPCM IMA QuickTime pub const CODEC_TYPE_ADPCM_IMA_QT: CodecType = CodecType(0x205); // Compressed lossy audio codecs //------------------------------ /// Vorbis pub const CODEC_TYPE_VORBIS: CodecType = CodecType(0x1000); /// MPEG Layer 1 (MP1) pub const CODEC_TYPE_MP1: CodecType = CodecType(0x1001); /// MPEG Layer 2 (MP2) pub const CODEC_TYPE_MP2: CodecType = CodecType(0x1002); /// MPEG Layer 3 (MP3) pub const CODEC_TYPE_MP3: CodecType = CodecType(0x1003); /// Advanced Audio Coding (AAC) pub const CODEC_TYPE_AAC: CodecType = CodecType(0x1004); /// Opus pub const CODEC_TYPE_OPUS: CodecType = CodecType(0x1005); /// Speex pub const CODEC_TYPE_SPEEX: CodecType = CodecType(0x1006); /// Musepack pub const CODEC_TYPE_MUSEPACK: CodecType = CodecType(0x1007); /// Adaptive Transform Acoustic Coding (ATRAC1) pub const CODEC_TYPE_ATRAC1: CodecType = CodecType(0x1008); /// Adaptive Transform Acoustic Coding 3 (ATRAC3) pub const CODEC_TYPE_ATRAC3: CodecType = CodecType(0x1009); /// Adaptive Transform Acoustic Coding 3+ (ATRAC3+) pub const CODEC_TYPE_ATRAC3PLUS: CodecType = CodecType(0x100a); /// Adaptive Transform Acoustic Coding 9 (ATRAC9) pub const CODEC_TYPE_ATRAC9: CodecType = CodecType(0x100b); /// AC-3, E-AC-3, Dolby Digital (ATSC A/52) pub const CODEC_TYPE_EAC3: CodecType = CodecType(0x100c); /// Dolby AC-4 (ETSI TS 103 190) pub const CODEC_TYPE_AC4: CodecType = CodecType(0x100d); /// DTS Coherent Acoustics (DCA/DTS) pub const CODEC_TYPE_DCA: CodecType = CodecType(0x100e); /// Windows Media Audio pub const CODEC_TYPE_WMA: CodecType = CodecType(0x100f); // Compressed lossless audio codecs //--------------------------------- /// Free Lossless Audio Codec (FLAC) pub const CODEC_TYPE_FLAC: CodecType = CodecType(0x2000); /// WavPack pub const CODEC_TYPE_WAVPACK: CodecType = CodecType(0x2001); /// Monkey's Audio (APE) pub const CODEC_TYPE_MONKEYS_AUDIO: CodecType = CodecType(0x2002); /// Apple Lossless Audio Codec (ALAC) pub const CODEC_TYPE_ALAC: CodecType = CodecType(0x2003); /// True Audio (TTA) pub const CODEC_TYPE_TTA: CodecType = CodecType(0x2004); /// A method and expected value to perform verification on the decoded audio. #[derive(Copy, Clone, Debug)] pub enum VerificationCheck { /// CRC8 of interleaved PCM audio samples. Crc8(u8), /// CRC16 of interleaved PCM audio samples. Crc16([u8; 2]), /// CRC32 of interleaved PCM audio samples. Crc32([u8; 4]), /// MD5 of interleaved PCM audio samples. Md5([u8; 16]), /// Codec defined, up-to 16-byte code. Other([u8; 16]), } /// Codec parameters stored in a container format's headers and metadata may be passed to a codec /// using the `CodecParameters` structure. #[derive(Clone, Debug)] pub struct CodecParameters { /// The codec type. pub codec: CodecType, /// The sample rate of the audio in Hz. pub sample_rate: Option, /// The timebase of the stream. /// /// The timebase is the length of time in seconds of a single tick of a timestamp or duration. /// It can be used to convert any timestamp or duration related to the stream into seconds. pub time_base: Option, /// The length of the stream in number of frames. /// /// If a timebase is available, this field can be used to calculate the total duration of the /// stream in seconds by using [`TimeBase::calc_time`] and passing the number of frames as the /// timestamp. pub n_frames: Option, /// The timestamp of the first frame. pub start_ts: u64, /// The sample format of an audio sample. pub sample_format: Option, /// The number of bits per one decoded audio sample. pub bits_per_sample: Option, /// The number of bits per one encoded audio sample. pub bits_per_coded_sample: Option, /// A bitmask of all channels in the stream. pub channels: Option, /// The channel layout. pub channel_layout: Option, /// The number of leading frames inserted by the encoder that should be skipped during playback. pub delay: Option, /// The number of trailing frames inserted by the encoder for padding that should be skipped /// during playback. pub padding: Option, /// The maximum number of frames a packet will contain. pub max_frames_per_packet: Option, /// The demuxer guarantees packet data integrity. pub packet_data_integrity: bool, /// A method and expected value that may be used to perform verification on the decoded audio. pub verification_check: Option, /// The number of frames per block, in case packets are seperated in multiple blocks. pub frames_per_block: Option, /// Extra data (defined by the codec). pub extra_data: Option>, } impl CodecParameters { pub fn new() -> CodecParameters { CodecParameters { codec: CODEC_TYPE_NULL, sample_rate: None, time_base: None, n_frames: None, start_ts: 0, sample_format: None, bits_per_sample: None, bits_per_coded_sample: None, channels: None, channel_layout: None, delay: None, padding: None, max_frames_per_packet: None, packet_data_integrity: false, verification_check: None, frames_per_block: None, extra_data: None, } } /// Provide the `CodecType`. pub fn for_codec(&mut self, codec: CodecType) -> &mut Self { self.codec = codec; self } /// Provide the sample rate in Hz. pub fn with_sample_rate(&mut self, sample_rate: u32) -> &mut Self { self.sample_rate = Some(sample_rate); self } /// Provide the `TimeBase`. pub fn with_time_base(&mut self, time_base: TimeBase) -> &mut Self { self.time_base = Some(time_base); self } /// Provide the total number of frames. pub fn with_n_frames(&mut self, n_frames: u64) -> &mut Self { self.n_frames = Some(n_frames); self } /// Provide the timestamp of the first frame. pub fn with_start_ts(&mut self, start_ts: u64) -> &mut Self { self.start_ts = start_ts; self } /// Provide the codec's decoded audio sample format. pub fn with_sample_format(&mut self, sample_format: SampleFormat) -> &mut Self { self.sample_format = Some(sample_format); self } /// Provide the bit per sample of a decoded audio sample. pub fn with_bits_per_sample(&mut self, bits_per_sample: u32) -> &mut Self { self.bits_per_sample = Some(bits_per_sample); self } /// Provide the bits per sample of an encoded audio sample. pub fn with_bits_per_coded_sample(&mut self, bits_per_coded_sample: u32) -> &mut Self { self.bits_per_coded_sample = Some(bits_per_coded_sample); self } /// Provide the channel map. pub fn with_channels(&mut self, channels: Channels) -> &mut Self { self.channels = Some(channels); self } /// Provide the channel layout. pub fn with_channel_layout(&mut self, channel_layout: Layout) -> &mut Self { self.channel_layout = Some(channel_layout); self } /// Provide the number of delay frames. pub fn with_delay(&mut self, delay: u32) -> &mut Self { self.delay = Some(delay); self } /// Provide the number of padding frames. pub fn with_padding(&mut self, padding: u32) -> &mut Self { self.padding = Some(padding); self } /// Provide the maximum number of frames per packet. pub fn with_max_frames_per_packet(&mut self, len: u64) -> &mut Self { self.max_frames_per_packet = Some(len); self } /// Specify if the packet's data integrity was guaranteed. pub fn with_packet_data_integrity(&mut self, integrity: bool) -> &mut Self { self.packet_data_integrity = integrity; self } /// Provide the maximum number of frames per packet. pub fn with_frames_per_block(&mut self, len: u64) -> &mut Self { self.frames_per_block = Some(len); self } /// Provide codec extra data. pub fn with_extra_data(&mut self, data: Box<[u8]>) -> &mut Self { self.extra_data = Some(data); self } /// Provide a verification code of the final decoded audio. pub fn with_verification_code(&mut self, code: VerificationCheck) -> &mut Self { self.verification_check = Some(code); self } } impl Default for CodecParameters { fn default() -> Self { Self::new() } } /// `FinalizeResult` contains optional information that can only be found, calculated, or /// determined after decoding is complete. #[derive(Copy, Clone, Debug, Default)] pub struct FinalizeResult { /// If verification is enabled and supported by the decoder, provides the verification result /// if available. pub verify_ok: Option, } /// `DecoderOptions` is a common set of options that all decoders use. #[derive(Copy, Clone, Debug, Default)] pub struct DecoderOptions { /// The decoded audio should be verified if possible during the decode process. pub verify: bool, } /// A `Decoder` implements a codec's decode algorithm. It consumes `Packet`s and produces /// `AudioBuffer`s. pub trait Decoder: Send + Sync { /// Attempts to instantiates a `Decoder` using the provided `CodecParameters`. fn try_new(params: &CodecParameters, options: &DecoderOptions) -> Result where Self: Sized; /// Gets a list of codec descriptors for the codecs supported by this Decoder. fn supported_codecs() -> &'static [CodecDescriptor] where Self: Sized; /// Reset the `Decoder`. /// /// A decoder must be reset when the next packet is discontinuous with respect to the last /// decoded packet. Most notably, this occurs after a seek. /// /// For codecs that do a lot of pre-computation, reset should only reset the absolute minimum /// amount of state. fn reset(&mut self); /// Gets a reference to an updated set of `CodecParameters` based on the parameters the /// `Decoder` was instantiated with. fn codec_params(&self) -> &CodecParameters; /// Decodes a `Packet` of audio data and returns a copy-on-write generic (untyped) audio buffer /// of the decoded audio. /// /// If a `DecodeError` or `IoError` is returned, the packet is undecodeable and should be /// discarded. Decoding may be continued with the next packet. If `ResetRequired` is returned, /// consumers of the decoded audio data should expect the duration and `SignalSpec` of the /// decoded audio buffer to change. All other errors are unrecoverable. /// /// Implementors of decoders *must* `clear` the internal buffer if an error occurs. fn decode(&mut self, packet: &Packet) -> Result; /// Optionally, obtain post-decode information such as the verification status. fn finalize(&mut self) -> FinalizeResult; /// Allows read access to the internal audio buffer. /// /// After a successful call to `decode`, this will contain the audio content of the last decoded /// `Packet`. If the last call to `decode` resulted in an error, then implementors *must* ensure /// the returned audio buffer has zero length. fn last_decoded(&self) -> AudioBufferRef; } /// A `CodecDescriptor` stores a description of a single logical codec. Common information such as /// the `CodecType`, a short name, and a long name are provided. The `CodecDescriptor` also provides /// an instantiation function. When the instantiation function is called, a `Decoder` for the codec /// is returned. #[derive(Copy, Clone)] pub struct CodecDescriptor { /// The `CodecType` identifier. pub codec: CodecType, /// A short ASCII-only string identifying the codec. pub short_name: &'static str, /// A longer, more descriptive, string identifying the codec. pub long_name: &'static str, // An instantiation function for the codec. pub inst_func: fn(&CodecParameters, &DecoderOptions) -> Result>, } /// A `CodecRegistry` allows the registration of codecs, and provides a method to instantiate a /// `Decoder` given a `CodecParameters` object. pub struct CodecRegistry { codecs: HashMap, } impl CodecRegistry { /// Instantiate a new `CodecRegistry`. pub fn new() -> Self { CodecRegistry { codecs: HashMap::new() } } /// Gets the `CodecDescriptor` for a registered codec. pub fn get_codec(&self, codec: CodecType) -> Option<&CodecDescriptor> { self.codecs.get(&codec) } /// Registers all codecs supported by `Decoder`. If a supported codec was previously registered /// by another `Decoder` it will be replaced within the registry. pub fn register_all(&mut self) { for descriptor in D::supported_codecs() { self.register(descriptor); } } /// Register a single codec. If the codec was previously registered it will be replaced within /// the registry. pub fn register(&mut self, descriptor: &CodecDescriptor) { self.codecs.insert(descriptor.codec, *descriptor); } /// Searches the registry for a `Decoder` that supports the codec. If one is found, it will be /// instantiated with the provided `CodecParameters` and returned. If a `Decoder` could not be /// found, or the `CodecParameters` are either insufficient or invalid for the `Decoder`, an /// error will be returned. pub fn make( &self, params: &CodecParameters, options: &DecoderOptions, ) -> Result> { if let Some(descriptor) = self.codecs.get(¶ms.codec) { Ok((descriptor.inst_func)(params, options)?) } else { unsupported_error("core (codec):unsupported codec") } } } impl Default for CodecRegistry { fn default() -> Self { Self::new() } } /// Convenience macro for declaring a `CodecDescriptor`. #[macro_export] macro_rules! support_codec { ($type:expr, $short_name:expr, $long_name:expr) => { CodecDescriptor { codec: $type, short_name: $short_name, long_name: $long_name, inst_func: |params, opt| Ok(Box::new(Self::try_new(¶ms, &opt)?)), } }; } symphonia-core-0.5.4/src/conv.rs000064400000000000000000001213431046102023000146750ustar 00000000000000// Symphonia // Copyright (c) 2019-2022 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/. //! The `conv` module provides methods to convert samples between different sample types (formats). use crate::sample::{i24, u24, Sample}; pub mod dither { //! The `dither` module provides methods to apply a dither to a sample. //! //! Dithering is the process of adding noise to the least significant digits of a sample before //! down-converting (quantizing) it to a smaller sample type. The purpose of dithering is to //! decorrelate the quantization error of the down-conversion from the source signal. //! //! Dithering is only applied on lossy conversions. Therefore the `dither` module will only //! apply a dither to the following down-conversions: //! //! * { `i32`, `u32` } to { `i24`, `u24`, `i16`, `u16`, `i8`, `u8` } //! * { `i24`, `u24` } to { `i16`, `u16`, `i8`, `u8` } //! * { `i16`, `u16` } to { `i8`, `u8` } //! //! Multiple dithering algorithms are provided, each drawing noise from a different probability //! distribution. In addition to different distributions, a dithering algorithm may also shape //! the noise such that the bulk of the noise is placed in an inaudible frequency range. use super::FromSample; use crate::sample::Sample; use crate::sample::{i24, u24}; use std::marker::PhantomData; mod prng { #[inline] fn split_mix_64(x: &mut u64) -> u64 { *x = x.wrapping_add(0x9e37_79b9_7f4a_7c15); let mut z = *x; z = (z ^ (z >> 30)).wrapping_mul(0xbf58_476d_1ce4_e5b9); z = (z ^ (z >> 27)).wrapping_mul(0x94d0_49bb_1331_11eb); z ^ (z >> 31) } /// `Xoshiro128pp` implements the xoshiro128++ pseudo-random number generator. /// /// This PRNG is the basis for all built-in dithering algorithms. It is one of, if not the /// most, performant PRNGs that generate statistically valid random numbers. Note that it is /// not cryptographically secure, but for dithering audio it is more than sufficient. /// /// `Xoshiro128pp` should be initialized with a reasonably random 64-bit seed, however the /// seed will be further randomized via the SplitMix64 algorithm. pub struct Xoshiro128pp { s: [u32; 4], } impl Xoshiro128pp { pub fn new(mut seed: u64) -> Self { let a = split_mix_64(&mut seed); let b = split_mix_64(&mut seed); Xoshiro128pp { s: [ (a & 0xffff_ffff) as u32, (a >> 32) as u32, (b & 0xffff_ffff) as u32, (b >> 32) as u32, ], } } #[inline(always)] fn rotl(x: u32, k: u32) -> u32 { (x << k) | (x >> (32 - k)) } #[inline] pub fn next(&mut self) -> u32 { let x = self.s[0].wrapping_add(self.s[3]); let result = Xoshiro128pp::rotl(x, 7).wrapping_add(self.s[0]); let t = self.s[1] << 9; self.s[2] ^= self.s[0]; self.s[3] ^= self.s[1]; self.s[1] ^= self.s[2]; self.s[0] ^= self.s[3]; self.s[2] ^= t; self.s[3] = Xoshiro128pp::rotl(self.s[3], 11); result } } } /// `RandomNoise` represents a sample of noise of a specified length in bits. /// /// TODO: `RandomNoise` should be parameterized by the number of bits once const generics land. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Default)] pub struct RandomNoise(pub i32); impl RandomNoise { /// Instantiate a noise sample from a random 32-bit source. pub fn from(random: i32, n_bits: u32) -> Self { RandomNoise(random >> (32 - n_bits)) } } /// `AddNoise` is a trait for converting random noise into a `Sample`. pub trait AddNoise { fn add_noise(self, sample: S) -> S; } macro_rules! add_noise_impl { ($sample_type:ty, $self:ident, $sample:ident, $conv:expr) => ( impl AddNoise<$sample_type> for RandomNoise { #[inline] fn add_noise($self, $sample: $sample_type) -> $sample_type { $conv } } ) } add_noise_impl!(i8, self, s, { i8::from_sample(f32::from_sample(s) + f32::from_sample(self.0)) }); add_noise_impl!(u8, self, s, { u8::from_sample(f32::from_sample(s) + f32::from_sample(self.0)) }); add_noise_impl!(i16, self, s, { i16::from_sample(f32::from_sample(s) + f32::from_sample(self.0)) }); add_noise_impl!(u16, self, s, { u16::from_sample(f32::from_sample(s) + f32::from_sample(self.0)) }); add_noise_impl!(i24, self, s, { i24::from_sample(f32::from_sample(s) + f32::from_sample(self.0)) }); add_noise_impl!(u24, self, s, { u24::from_sample(f32::from_sample(s) + f32::from_sample(self.0)) }); add_noise_impl!(i32, self, s, { i32::from_sample(f64::from_sample(s) + f64::from_sample(self.0)) }); add_noise_impl!(u32, self, s, { u32::from_sample(f64::from_sample(s) + f64::from_sample(self.0)) }); add_noise_impl!(f32, self, s, s + f32::from_sample(self.0)); add_noise_impl!(f64, self, s, s + f64::from_sample(self.0)); /// `Dither` is a trait for implementing dithering algorithms. pub trait Dither { /// Dithers a `Sample` of source sample format `F` for an eventual conversion to the /// destination sample format `T`. fn dither(&mut self, sample: F) -> F; } /// The `Identity` dithering algorithm performs no dithering and returns the original sample. pub struct Identity { from_type: PhantomData, to_type: PhantomData, } impl Identity { pub fn new() -> Self { Identity { from_type: PhantomData, to_type: PhantomData } } } impl Dither for Identity { fn dither(&mut self, sample: F) -> F { sample } } impl Default for Identity { fn default() -> Self { Self::new() } } /// `Rectangular` implements a dither using uniformly distributed (white) noise without shaping. pub struct Rectangular { prng: prng::Xoshiro128pp, from_type: PhantomData, to_type: PhantomData, } impl Rectangular { pub fn new() -> Self { Rectangular { prng: prng::Xoshiro128pp::new(0xb2c1_01f4_425b_987e), from_type: PhantomData, to_type: PhantomData, } } } impl Dither for Rectangular where RandomNoise: AddNoise, { fn dither(&mut self, sample: F) -> F { // A dither should be applied if and only if the effective number of bits of the source // sample format is greater than that of the destination sample format. debug_assert!(F::EFF_BITS > T::EFF_BITS); // The number of low-order bits being truncated by the conversion will be dithered. let dither_bits = 32 - T::EFF_BITS; // Add the noise to the sample. let noise = RandomNoise::from(self.prng.next() as i32, dither_bits); noise.add_noise(sample) } } impl Default for Rectangular { fn default() -> Self { Self::new() } } /// `Triangular` implements a dither using a triangular distribution of noise without shaping. pub struct Triangular { prng: prng::Xoshiro128pp, from_type: PhantomData, to_type: PhantomData, } impl Triangular { pub fn new() -> Self { Triangular { prng: prng::Xoshiro128pp::new(0xb2c1_01f4_425b_987e), from_type: PhantomData, to_type: PhantomData, } } } impl Dither for Triangular where RandomNoise: AddNoise, { fn dither(&mut self, sample: F) -> F { debug_assert!(F::EFF_BITS > T::EFF_BITS); let dither_bits = 32 - T::EFF_BITS; // Generate a triangular distribution from the uniform distribution. let tpdf = (self.prng.next() as i32 >> 1) + (self.prng.next() as i32 >> 1); // Add the noise to the sample. let noise = RandomNoise::from(tpdf, dither_bits); noise.add_noise(sample) } } impl Default for Triangular { fn default() -> Self { Self::new() } } /// Enumeration of dither algorithms. pub enum DitherType { /// No dithering. Identity, /// Apply rectangular dithering. See `Rectangular` for more details. Rectangular, /// Apply triangular dithering. See `Triangular` for more details. Triangular, } /// `MaybeDither` conditionally applies a dither to a sample depending on the source and /// destination sample types. pub trait MaybeDither: Sample { const DITHERABLE: bool; fn maybe_dither>(self, dither: &mut D) -> Self; } /// Never apply a dither for this conversion. macro_rules! dither_never { ($to:ty, $from:ty) => { impl MaybeDither<$to> for $from { const DITHERABLE: bool = false; #[inline(always)] fn maybe_dither>(self, _: &mut D) -> Self { self } } }; } /// Maybe apply a dither for this conversion. macro_rules! dither_maybe { ($to:ty, $from:ty) => { impl MaybeDither<$to> for $from { const DITHERABLE: bool = true; #[inline(always)] fn maybe_dither>(self, dither: &mut D) -> Self { dither.dither(self) } } }; } // Dither table for conversions to u8 dither_never!(u8, u8); dither_maybe!(u8, u16); dither_maybe!(u8, u24); dither_maybe!(u8, u32); dither_never!(u8, i8); dither_maybe!(u8, i16); dither_maybe!(u8, i24); dither_maybe!(u8, i32); dither_never!(u8, f32); dither_never!(u8, f64); // Dither table for conversions to u16 dither_never!(u16, u8); dither_never!(u16, u16); dither_maybe!(u16, u24); dither_maybe!(u16, u32); dither_never!(u16, i8); dither_never!(u16, i16); dither_maybe!(u16, i24); dither_maybe!(u16, i32); dither_never!(u16, f32); dither_never!(u16, f64); // Dither table for conversions to u24 dither_never!(u24, u8); dither_never!(u24, u16); dither_never!(u24, u24); dither_maybe!(u24, u32); dither_never!(u24, i8); dither_never!(u24, i16); dither_never!(u24, i24); dither_maybe!(u24, i32); dither_never!(u24, f32); dither_never!(u24, f64); // Dither table for conversions to u32 dither_never!(u32, u8); dither_never!(u32, u16); dither_never!(u32, u24); dither_never!(u32, u32); dither_never!(u32, i8); dither_never!(u32, i16); dither_never!(u32, i24); dither_never!(u32, i32); dither_never!(u32, f32); dither_never!(u32, f64); // Dither table for conversions to i8 dither_never!(i8, u8); dither_maybe!(i8, u16); dither_maybe!(i8, u24); dither_maybe!(i8, u32); dither_never!(i8, i8); dither_maybe!(i8, i16); dither_maybe!(i8, i24); dither_maybe!(i8, i32); dither_never!(i8, f32); dither_never!(i8, f64); // Dither table for conversions to i16 dither_never!(i16, u8); dither_never!(i16, u16); dither_maybe!(i16, u24); dither_maybe!(i16, u32); dither_never!(i16, i8); dither_never!(i16, i16); dither_maybe!(i16, i24); dither_maybe!(i16, i32); dither_never!(i16, f32); dither_never!(i16, f64); // Dither table for conversions to i24 dither_never!(i24, u8); dither_never!(i24, u16); dither_never!(i24, u24); dither_maybe!(i24, u32); dither_never!(i24, i8); dither_never!(i24, i16); dither_never!(i24, i24); dither_maybe!(i24, i32); dither_never!(i24, f32); dither_never!(i24, f64); // Dither table for conversions to i32 dither_never!(i32, u8); dither_never!(i32, u16); dither_never!(i32, u24); dither_never!(i32, u32); dither_never!(i32, i8); dither_never!(i32, i16); dither_never!(i32, i24); dither_never!(i32, i32); dither_never!(i32, f32); dither_never!(i32, f64); // Dither table for conversions to f32 dither_never!(f32, u8); dither_never!(f32, u16); dither_never!(f32, u24); dither_never!(f32, u32); dither_never!(f32, i8); dither_never!(f32, i16); dither_never!(f32, i24); dither_never!(f32, i32); dither_never!(f32, f32); dither_never!(f32, f64); // Dither table for conversions to f64 dither_never!(f64, u8); dither_never!(f64, u16); dither_never!(f64, u24); dither_never!(f64, u32); dither_never!(f64, i8); dither_never!(f64, i16); dither_never!(f64, i24); dither_never!(f64, i32); dither_never!(f64, f32); dither_never!(f64, f64); } /// `FromSample` implements a conversion from `Sample` type `F` to `Self`. /// /// This may be a lossy conversion if converting from a sample type of higher precision to one of /// lower precision. No dithering is applied. pub trait FromSample { fn from_sample(val: F) -> Self; } // Notes on sample format converters // // In total there are 10 different sample formats, so there are 100 different sample format // converters. Of the 100 sample format converters, there are 64 int <-> int, 32 int <-> float, and // 4 float <-> float converters. // // A minimum version of Rust 1.45 is required. As of Rust 1.45 a ` as ` cast // saturates (clamps) to the bounds of the integer. Therefore, no clamping is required. Symphonia // takes advantage of this behaviour. macro_rules! impl_convert { ($from:ty, $to:ty, $sample:ident, $func:expr) => { impl FromSample<$from> for $to { #[inline(always)] fn from_sample($sample: $from) -> Self { $func } } }; } // i8 to ... #[inline(always)] fn i8_to_u8(s: i8) -> u8 { (s as u8).wrapping_add(0x80) } impl_convert!(i8, u8, s, i8_to_u8(s)); // u8 impl_convert!(i8, u16, s, (i8_to_u8(s) as u16) << 8); // u16 impl_convert!(i8, u24, s, u24::from((i8_to_u8(s) as u32) << 16)); // u24 impl_convert!(i8, u32, s, (i8_to_u8(s) as u32) << 24); // u3 impl_convert!(i8, i8, s, s); // i8 impl_convert!(i8, i16, s, (s as i16) << 8); // i16 impl_convert!(i8, i24, s, i24::from((s as i32) << 16)); // i24 impl_convert!(i8, i32, s, (s as i32) << 24); // i32 impl_convert!(i8, f32, s, s as f32 / 128.0); // f32 impl_convert!(i8, f64, s, s as f64 / 128.0); // f64 // i16 to ... #[inline(always)] fn i16_to_u16(s: i16) -> u16 { (s as u16).wrapping_add(0x8000) } impl_convert!(i16, u8, s, (i16_to_u16(s) >> 8) as u8); // u8 impl_convert!(i16, u16, s, i16_to_u16(s)); // u16 impl_convert!(i16, u24, s, u24::from((i16_to_u16(s) as u32) << 8)); // u24 impl_convert!(i16, u32, s, (i16_to_u16(s) as u32) << 16); // u32 impl_convert!(i16, i8, s, (s >> 8) as i8); // i8 impl_convert!(i16, i16, s, s); // i16 impl_convert!(i16, i24, s, i24::from((s as i32) << 8)); // i24 impl_convert!(i16, i32, s, (s as i32) << 16); // i32 impl_convert!(i16, f32, s, s as f32 / 32_768.0); // f32 impl_convert!(i16, f64, s, s as f64 / 32_768.0); // f64 // i24 to ... #[inline(always)] fn i24_to_u32(s: i24) -> u32 { ((s.clamped().inner() << 8) as u32).wrapping_add(0x8000_0000) } impl_convert!(i24, u8, s, (i24_to_u32(s) >> 24) as u8); // u8 impl_convert!(i24, u16, s, (i24_to_u32(s) >> 16) as u16); // u16 impl_convert!(i24, u24, s, u24::from(i24_to_u32(s) >> 8)); // u24 impl_convert!(i24, u32, s, i24_to_u32(s)); // u32 impl_convert!(i24, i8, s, (s.clamped().inner() >> 16) as i8); // i8 impl_convert!(i24, i16, s, (s.clamped().inner() >> 8) as i16); // i16 impl_convert!(i24, i24, s, s); // i24 impl_convert!(i24, i32, s, (s.clamped().inner()) << 8); // i32 impl_convert!(i24, f32, s, s.clamped().inner() as f32 / 8_388_608.0); // f32 impl_convert!(i24, f64, s, s.clamped().inner() as f64 / 8_388_608.0); // f64 // i32 to ... #[inline(always)] fn i32_to_u32(s: i32) -> u32 { (s as u32).wrapping_add(0x8000_0000) } impl_convert!(i32, u8, s, (i32_to_u32(s) >> 24) as u8); // u8 impl_convert!(i32, u16, s, (i32_to_u32(s) >> 16) as u16); // u16 impl_convert!(i32, u24, s, u24::from(i32_to_u32(s) >> 8)); // u24 impl_convert!(i32, u32, s, i32_to_u32(s)); // u32 impl_convert!(i32, i8, s, (s >> 24) as i8); // i8 impl_convert!(i32, i16, s, (s >> 16) as i16); // i16 impl_convert!(i32, i24, s, i24::from(s >> 8)); // i24 impl_convert!(i32, i32, s, s); // i32 impl_convert!(i32, f32, s, (s as f64 / 2_147_483_648.0) as f32); // f32 impl_convert!(i32, f64, s, s as f64 / 2_147_483_648.0); // f64 // u8 to ... impl_convert!(u8, u8, s, s); // u8 impl_convert!(u8, u16, s, (s as u16) << 8); // u16 impl_convert!(u8, u24, s, u24::from((s as u32) << 16)); // u24 impl_convert!(u8, u32, s, (s as u32) << 24); // u32 impl_convert!(u8, i8, s, s.wrapping_sub(0x80) as i8); // i8 impl_convert!(u8, i16, s, ((s.wrapping_sub(0x80) as i8) as i16) << 8); // i16 impl_convert!(u8, i24, s, i24::from(((s.wrapping_sub(0x80) as i8) as i32) << 16)); // i24 impl_convert!(u8, i32, s, ((s.wrapping_sub(0x80) as i8) as i32) << 24); // i32 impl_convert!(u8, f32, s, ((s as f32) / 128.0) - 1.0); // f32 impl_convert!(u8, f64, s, ((s as f64) / 128.0) - 1.0); // f64 // u16 to ... impl_convert!(u16, u8, s, (s >> 8) as u8); // u8 impl_convert!(u16, u16, s, s); // u16 impl_convert!(u16, u24, s, u24::from((s as u32) << 8)); // u24 impl_convert!(u16, u32, s, (s as u32) << 16); // u32 impl_convert!(u16, i8, s, (s.wrapping_sub(0x8000) >> 8) as i8); // i8 impl_convert!(u16, i16, s, s.wrapping_sub(0x8000) as i16); // i16 impl_convert!(u16, i24, s, i24::from(((s.wrapping_sub(0x8000) as i16) as i32) << 8)); // i24 impl_convert!(u16, i32, s, ((s.wrapping_sub(0x8000) as i16) as i32) << 16); // i32 impl_convert!(u16, f32, s, ((s as f32) / 32_768.0) - 1.0); // f32 impl_convert!(u16, f64, s, ((s as f64) / 32_768.0) - 1.0); // f64 // u24 to ... impl_convert!(u24, u8, s, (s.clamped().inner() >> 16) as u8); // u8 impl_convert!(u24, u16, s, (s.clamped().inner() >> 8) as u16); // u16 impl_convert!(u24, u24, s, s); // u24 impl_convert!(u24, u32, s, s.clamped().inner() << 8); // u32 impl_convert!(u24, i8, s, (s.clamped().inner().wrapping_sub(0x80_0000) >> 16) as i8); // i8 impl_convert!(u24, i16, s, (s.clamped().inner().wrapping_sub(0x80_0000) >> 8) as i16); // i16 impl_convert!(u24, i24, s, i24::from(s.clamped().inner().wrapping_sub(0x80_0000) as i32)); // i24 impl_convert!(u24, i32, s, (s.clamped().inner().wrapping_sub(0x80_0000) << 8) as i32); // i32 impl_convert!(u24, f32, s, ((s.clamped().inner() as f32) / 8_388_608.0) - 1.0); // f32 impl_convert!(u24, f64, s, ((s.clamped().inner() as f64) / 8_388_608.0) - 1.0); // f64 // u32 to ... impl_convert!(u32, u8, s, (s >> 24) as u8); // u8 impl_convert!(u32, u16, s, (s >> 16) as u16); // u16 impl_convert!(u32, u24, s, u24::from(s >> 8)); // u24 impl_convert!(u32, u32, s, s); // u32 impl_convert!(u32, i8, s, (s.wrapping_sub(0x8000_0000) >> 24) as i8); // i8 impl_convert!(u32, i16, s, (s.wrapping_sub(0x8000_0000) >> 16) as i16); // i16 impl_convert!(u32, i24, s, i24::from((s.wrapping_sub(0x8000_0000) as i32) >> 8)); // i24 impl_convert!(u32, i32, s, s.wrapping_sub(0x8000_0000) as i32); // i32 impl_convert!(u32, f32, s, (((s as f64) / 2_147_483_648.0) - 1.0) as f32); // f32 impl_convert!(u32, f64, s, ((s as f64) / 2_147_483_648.0) - 1.0); // f64 // f32 to ... impl_convert!(f32, u8, s, ((s.clamped() + 1.0) * 128.0) as u8); // u8 impl_convert!(f32, u16, s, ((s.clamped() + 1.0) * 32_768.0) as u16); // u16 impl_convert!(f32, u24, s, u24::from(((s.clamped() + 1.0) * 8_388_608.0) as u32)); // u24 impl_convert!(f32, u32, s, ((s.clamped() + 1.0) as f64 * 2_147_483_648.0) as u32); // u32 impl_convert!(f32, i8, s, (s.clamped() * 128.0) as i8); // i8 impl_convert!(f32, i16, s, (s.clamped() * 32_768.0) as i16); // i16 impl_convert!(f32, i24, s, i24::from((s.clamped() * 8_388_608.0) as i32)); // i24 impl_convert!(f32, i32, s, (s.clamped() as f64 * 2_147_483_648.0) as i32); // i32 impl_convert!(f32, f32, s, s); // f32 impl_convert!(f32, f64, s, s as f64); // f64 // f64 to ... impl_convert!(f64, u8, s, ((s.clamped() + 1.0) * 128.0) as u8); // u8 impl_convert!(f64, u16, s, ((s.clamped() + 1.0) * 32_768.0) as u16); // u16 impl_convert!(f64, u24, s, u24::from(((s.clamped() + 1.0) * 8_388_608.0) as u32)); // u24 impl_convert!(f64, u32, s, ((s.clamped() + 1.0) * 2_147_483_648.0) as u32); // u32 impl_convert!(f64, i8, s, (s.clamped() * 128.0) as i8); // i8 impl_convert!(f64, i16, s, (s.clamped() * 32_768.0) as i16); // i16 impl_convert!(f64, i24, s, i24::from((s.clamped() * 8_388_608.0) as i32)); // i24 impl_convert!(f64, i32, s, (s.clamped() * 2_147_483_648.0) as i32); // i32 impl_convert!(f64, f32, s, s as f32); // f32 impl_convert!(f64, f64, s, s); // f64 /// `IntoSample` implements a conversion from `Self` to `Sample` type `T`. /// /// This may be a lossy conversion if converting from a sample type of higher precision to one of /// lower precision. No dithering is applied. pub trait IntoSample { fn into_sample(self) -> T; } impl> IntoSample for F { #[inline] fn into_sample(self) -> T { T::from_sample(self) } } /// `ReversibleSample` is a trait that when implemented for `Self`, that `Sample` type implements /// reversible conversions between `Self` and the parameterized `Sample` type `S`. pub trait ReversibleSample: Sample + FromSample + IntoSample {} impl ReversibleSample for T where T: Sample + FromSample + IntoSample {} pub trait ConvertibleSample: Sample + FromSample + FromSample + FromSample + FromSample + FromSample + FromSample + FromSample + FromSample + FromSample + FromSample { } impl ConvertibleSample for S where S: Sample + FromSample + FromSample + FromSample + FromSample + FromSample + FromSample + FromSample + FromSample + FromSample + FromSample { } #[cfg(test)] mod tests { use super::FromSample; use crate::sample::{i24, u24, Sample}; use std::{i16, i32, i8, u16, u32, u8}; #[test] fn verify_u8_from_sample() { assert_eq!(u8::from_sample(u8::MAX), u8::MAX); assert_eq!(u8::from_sample(u8::MID), u8::MID); assert_eq!(u8::from_sample(u8::MIN), u8::MIN); assert_eq!(u8::from_sample(u16::MAX), u8::MAX); assert_eq!(u8::from_sample(u16::MID), u8::MID); assert_eq!(u8::from_sample(u16::MIN), u8::MIN); assert_eq!(u8::from_sample(u24::MAX), u8::MAX); assert_eq!(u8::from_sample(u24::MID), u8::MID); assert_eq!(u8::from_sample(u24::MIN), u8::MIN); assert_eq!(u8::from_sample(u32::MAX), u8::MAX); assert_eq!(u8::from_sample(u32::MID), u8::MID); assert_eq!(u8::from_sample(u32::MIN), u8::MIN); assert_eq!(u8::from_sample(i8::MAX), u8::MAX); assert_eq!(u8::from_sample(i8::MID), u8::MID); assert_eq!(u8::from_sample(i8::MIN), u8::MIN); assert_eq!(u8::from_sample(i16::MAX), u8::MAX); assert_eq!(u8::from_sample(i16::MID), u8::MID); assert_eq!(u8::from_sample(i16::MIN), u8::MIN); assert_eq!(u8::from_sample(i24::MAX), u8::MAX); assert_eq!(u8::from_sample(i24::MID), u8::MID); assert_eq!(u8::from_sample(i24::MIN), u8::MIN); assert_eq!(u8::from_sample(i32::MAX), u8::MAX); assert_eq!(u8::from_sample(i32::MID), u8::MID); assert_eq!(u8::from_sample(i32::MIN), u8::MIN); assert_eq!(u8::from_sample(1.0f32), u8::MAX); assert_eq!(u8::from_sample(0f32), u8::MID); assert_eq!(u8::from_sample(-1.0f32), u8::MIN); assert_eq!(u8::from_sample(1.0f64), u8::MAX); assert_eq!(u8::from_sample(0f64), u8::MID); assert_eq!(u8::from_sample(-1.0f64), u8::MIN); } #[test] fn verify_u16_from_sample() { assert_eq!(u16::from_sample(u8::MAX), u16::MAX - 255); assert_eq!(u16::from_sample(u8::MID), u16::MID); assert_eq!(u16::from_sample(u8::MIN), u16::MIN); assert_eq!(u16::from_sample(u16::MAX), u16::MAX); assert_eq!(u16::from_sample(u16::MID), u16::MID); assert_eq!(u16::from_sample(u16::MIN), u16::MIN); assert_eq!(u16::from_sample(u24::MAX), u16::MAX); assert_eq!(u16::from_sample(u24::MID), u16::MID); assert_eq!(u16::from_sample(u24::MIN), u16::MIN); assert_eq!(u16::from_sample(u32::MAX), u16::MAX); assert_eq!(u16::from_sample(u32::MID), u16::MID); assert_eq!(u16::from_sample(u32::MIN), u16::MIN); assert_eq!(u16::from_sample(i8::MAX), u16::MAX - 255); assert_eq!(u16::from_sample(i8::MID), u16::MID); assert_eq!(u16::from_sample(i8::MIN), u16::MIN); assert_eq!(u16::from_sample(i16::MAX), u16::MAX); assert_eq!(u16::from_sample(i16::MID), u16::MID); assert_eq!(u16::from_sample(i16::MIN), u16::MIN); assert_eq!(u16::from_sample(i24::MAX), u16::MAX); assert_eq!(u16::from_sample(i24::MID), u16::MID); assert_eq!(u16::from_sample(i24::MIN), u16::MIN); assert_eq!(u16::from_sample(i32::MAX), u16::MAX); assert_eq!(u16::from_sample(i32::MID), u16::MID); assert_eq!(u16::from_sample(i32::MIN), u16::MIN); assert_eq!(u16::from_sample(1.0f32), u16::MAX); assert_eq!(u16::from_sample(0f32), u16::MID); assert_eq!(u16::from_sample(-1.0f32), u16::MIN); assert_eq!(u16::from_sample(1.0f64), u16::MAX); assert_eq!(u16::from_sample(0f64), u16::MID); assert_eq!(u16::from_sample(-1.0f64), u16::MIN); } #[test] fn verify_u24_from_sample() { assert_eq!(u24::from_sample(u8::MAX), u24::MAX - u24::from(65_535u32)); assert_eq!(u24::from_sample(u8::MID), u24::MID); assert_eq!(u24::from_sample(u8::MIN), u24::MIN); assert_eq!(u24::from_sample(u16::MAX), u24::MAX - u24::from(255u32)); assert_eq!(u24::from_sample(u16::MID), u24::MID); assert_eq!(u24::from_sample(u16::MIN), u24::MIN); assert_eq!(u24::from_sample(u24::MAX), u24::MAX); assert_eq!(u24::from_sample(u24::MID), u24::MID); assert_eq!(u24::from_sample(u24::MIN), u24::MIN); assert_eq!(u24::from_sample(u32::MAX), u24::MAX); assert_eq!(u24::from_sample(u32::MID), u24::MID); assert_eq!(u24::from_sample(u32::MIN), u24::MIN); assert_eq!(u24::from_sample(i8::MAX), u24::MAX - u24::from(65_535u32)); assert_eq!(u24::from_sample(i8::MID), u24::MID); assert_eq!(u24::from_sample(i8::MIN), u24::MIN); assert_eq!(u24::from_sample(i16::MAX), u24::MAX - u24::from(255u32)); assert_eq!(u24::from_sample(i16::MID), u24::MID); assert_eq!(u24::from_sample(i16::MIN), u24::MIN); assert_eq!(u24::from_sample(i24::MAX), u24::MAX); assert_eq!(u24::from_sample(i24::MID), u24::MID); assert_eq!(u24::from_sample(i24::MIN), u24::MIN); assert_eq!(u24::from_sample(i32::MAX), u24::MAX); assert_eq!(u24::from_sample(i32::MID), u24::MID); assert_eq!(u24::from_sample(i32::MIN), u24::MIN); assert_eq!(u24::from_sample(1.0f32), u24::MAX); assert_eq!(u24::from_sample(0f32), u24::MID); assert_eq!(u24::from_sample(-1.0f32), u24::MIN); assert_eq!(u24::from_sample(1.0f64), u24::MAX); assert_eq!(u24::from_sample(0f64), u24::MID); assert_eq!(u24::from_sample(-1.0f64), u24::MIN); } #[test] fn verify_u32_from_sample() { assert_eq!(u32::from_sample(u8::MAX), u32::MAX - 16_777_215); assert_eq!(u32::from_sample(u8::MID), u32::MID); assert_eq!(u32::from_sample(u8::MIN), u32::MIN); assert_eq!(u32::from_sample(u16::MAX), u32::MAX - 65_535); assert_eq!(u32::from_sample(u16::MID), u32::MID); assert_eq!(u32::from_sample(u16::MIN), u32::MIN); assert_eq!(u32::from_sample(u24::MAX), u32::MAX - 255); assert_eq!(u32::from_sample(u24::MID), u32::MID); assert_eq!(u32::from_sample(u24::MIN), u32::MIN); assert_eq!(u32::from_sample(u32::MAX), u32::MAX); assert_eq!(u32::from_sample(u32::MID), u32::MID); assert_eq!(u32::from_sample(u32::MIN), u32::MIN); assert_eq!(u32::from_sample(i8::MAX), u32::MAX - 16_777_215); assert_eq!(u32::from_sample(i8::MID), u32::MID); assert_eq!(u32::from_sample(i8::MIN), u32::MIN); assert_eq!(u32::from_sample(i16::MAX), u32::MAX - 65_535); assert_eq!(u32::from_sample(i16::MID), u32::MID); assert_eq!(u32::from_sample(i16::MIN), u32::MIN); assert_eq!(u32::from_sample(i24::MAX), u32::MAX - 255); assert_eq!(u32::from_sample(i24::MID), u32::MID); assert_eq!(u32::from_sample(i24::MIN), u32::MIN); assert_eq!(u32::from_sample(i32::MAX), u32::MAX); assert_eq!(u32::from_sample(i32::MID), u32::MID); assert_eq!(u32::from_sample(i32::MIN), u32::MIN); assert_eq!(u32::from_sample(1.0f32), u32::MAX); assert_eq!(u32::from_sample(0f32), u32::MID); assert_eq!(u32::from_sample(-1.0f32), u32::MIN); assert_eq!(u32::from_sample(1.0f64), u32::MAX); assert_eq!(u32::from_sample(0f64), u32::MID); assert_eq!(u32::from_sample(-1.0f64), u32::MIN); } #[test] fn verify_i8_from_sample() { assert_eq!(i8::from_sample(u8::MAX), i8::MAX); assert_eq!(i8::from_sample(u8::MID), i8::MID); assert_eq!(i8::from_sample(u8::MIN), i8::MIN); assert_eq!(i8::from_sample(u16::MAX), i8::MAX); assert_eq!(i8::from_sample(u16::MID), i8::MID); assert_eq!(i8::from_sample(u16::MIN), i8::MIN); assert_eq!(i8::from_sample(u24::MAX), i8::MAX); assert_eq!(i8::from_sample(u24::MID), i8::MID); assert_eq!(i8::from_sample(u24::MIN), i8::MIN); assert_eq!(i8::from_sample(u32::MAX), i8::MAX); assert_eq!(i8::from_sample(u32::MID), i8::MID); assert_eq!(i8::from_sample(u32::MIN), i8::MIN); assert_eq!(i8::from_sample(i8::MAX), i8::MAX); assert_eq!(i8::from_sample(i8::MID), i8::MID); assert_eq!(i8::from_sample(i8::MIN), i8::MIN); assert_eq!(i8::from_sample(i16::MAX), i8::MAX); assert_eq!(i8::from_sample(i16::MID), i8::MID); assert_eq!(i8::from_sample(i16::MIN), i8::MIN); assert_eq!(i8::from_sample(i24::MAX), i8::MAX); assert_eq!(i8::from_sample(i24::MID), i8::MID); assert_eq!(i8::from_sample(i24::MIN), i8::MIN); assert_eq!(i8::from_sample(i32::MAX), i8::MAX); assert_eq!(i8::from_sample(i32::MID), i8::MID); assert_eq!(i8::from_sample(i32::MIN), i8::MIN); assert_eq!(i8::from_sample(1.0f32), i8::MAX); assert_eq!(i8::from_sample(0f32), i8::MID); assert_eq!(i8::from_sample(-1.0f32), i8::MIN); assert_eq!(i8::from_sample(1.0f64), i8::MAX); assert_eq!(i8::from_sample(0f64), i8::MID); assert_eq!(i8::from_sample(-1.0f64), i8::MIN); } #[test] fn verify_i16_from_sample() { assert_eq!(i16::from_sample(u8::MAX), i16::MAX - 255); assert_eq!(i16::from_sample(u8::MID), i16::MID); assert_eq!(i16::from_sample(u8::MIN), i16::MIN); assert_eq!(i16::from_sample(u16::MAX), i16::MAX); assert_eq!(i16::from_sample(u16::MID), i16::MID); assert_eq!(i16::from_sample(u16::MIN), i16::MIN); assert_eq!(i16::from_sample(u24::MAX), i16::MAX); assert_eq!(i16::from_sample(u24::MID), i16::MID); assert_eq!(i16::from_sample(u24::MIN), i16::MIN); assert_eq!(i16::from_sample(u32::MAX), i16::MAX); assert_eq!(i16::from_sample(u32::MID), i16::MID); assert_eq!(i16::from_sample(u32::MIN), i16::MIN); assert_eq!(i16::from_sample(i8::MAX), i16::MAX - 255); assert_eq!(i16::from_sample(i8::MID), i16::MID); assert_eq!(i16::from_sample(i8::MIN), i16::MIN); assert_eq!(i16::from_sample(i16::MAX), i16::MAX); assert_eq!(i16::from_sample(i16::MID), i16::MID); assert_eq!(i16::from_sample(i16::MIN), i16::MIN); assert_eq!(i16::from_sample(i24::MAX), i16::MAX); assert_eq!(i16::from_sample(i24::MID), i16::MID); assert_eq!(i16::from_sample(i24::MIN), i16::MIN); assert_eq!(i16::from_sample(i32::MAX), i16::MAX); assert_eq!(i16::from_sample(i32::MID), i16::MID); assert_eq!(i16::from_sample(i32::MIN), i16::MIN); assert_eq!(i16::from_sample(1.0f32), i16::MAX); assert_eq!(i16::from_sample(0f32), i16::MID); assert_eq!(i16::from_sample(-1.0f32), i16::MIN); assert_eq!(i16::from_sample(1.0f64), i16::MAX); assert_eq!(i16::from_sample(0f64), i16::MID); assert_eq!(i16::from_sample(-1.0f64), i16::MIN); } #[test] fn verify_i24_from_sample() { assert_eq!(i24::from_sample(u8::MAX), i24::MAX - i24::from(65_535)); assert_eq!(i24::from_sample(u8::MID), i24::MID); assert_eq!(i24::from_sample(u8::MIN), i24::MIN); assert_eq!(i24::from_sample(u16::MAX), i24::MAX - i24::from(255)); assert_eq!(i24::from_sample(u16::MID), i24::MID); assert_eq!(i24::from_sample(u16::MIN), i24::MIN); assert_eq!(i24::from_sample(u24::MAX), i24::MAX); assert_eq!(i24::from_sample(u24::MID), i24::MID); assert_eq!(i24::from_sample(u24::MIN), i24::MIN); assert_eq!(i24::from_sample(u32::MAX), i24::MAX); assert_eq!(i24::from_sample(u32::MID), i24::MID); assert_eq!(i24::from_sample(u32::MIN), i24::MIN); assert_eq!(i24::from_sample(i8::MAX), i24::MAX - i24::from(65_535)); assert_eq!(i24::from_sample(i8::MID), i24::MID); assert_eq!(i24::from_sample(i8::MIN), i24::MIN); assert_eq!(i24::from_sample(i16::MAX), i24::MAX - i24::from(255)); assert_eq!(i24::from_sample(i16::MID), i24::MID); assert_eq!(i24::from_sample(i16::MIN), i24::MIN); assert_eq!(i24::from_sample(i24::MAX), i24::MAX); assert_eq!(i24::from_sample(i24::MID), i24::MID); assert_eq!(i24::from_sample(i24::MIN), i24::MIN); assert_eq!(i24::from_sample(i32::MAX), i24::MAX); assert_eq!(i24::from_sample(i32::MID), i24::MID); assert_eq!(i24::from_sample(i32::MIN), i24::MIN); assert_eq!(i24::from_sample(1.0f32), i24::MAX); assert_eq!(i24::from_sample(0f32), i24::MID); assert_eq!(i24::from_sample(-1.0f32), i24::MIN); assert_eq!(i24::from_sample(1.0f64), i24::MAX); assert_eq!(i24::from_sample(0f64), i24::MID); assert_eq!(i24::from_sample(-1.0f64), i24::MIN); } #[test] fn verify_i32_from_sample() { assert_eq!(i32::from_sample(u8::MAX), i32::MAX - 16_777_215); assert_eq!(i32::from_sample(u8::MID), i32::MID); assert_eq!(i32::from_sample(u8::MIN), i32::MIN); assert_eq!(i32::from_sample(u16::MAX), i32::MAX - 65_535); assert_eq!(i32::from_sample(u16::MID), i32::MID); assert_eq!(i32::from_sample(u16::MIN), i32::MIN); assert_eq!(i32::from_sample(u24::MAX), i32::MAX - 255); assert_eq!(i32::from_sample(u24::MID), i32::MID); assert_eq!(i32::from_sample(u24::MIN), i32::MIN); assert_eq!(i32::from_sample(u32::MAX), i32::MAX); assert_eq!(i32::from_sample(u32::MID), i32::MID); assert_eq!(i32::from_sample(u32::MIN), i32::MIN); assert_eq!(i32::from_sample(i8::MAX), i32::MAX - 16_777_215); assert_eq!(i32::from_sample(i8::MID), i32::MID); assert_eq!(i32::from_sample(i8::MIN), i32::MIN); assert_eq!(i32::from_sample(i16::MAX), i32::MAX - 65_535); assert_eq!(i32::from_sample(i16::MID), i32::MID); assert_eq!(i32::from_sample(i16::MIN), i32::MIN); assert_eq!(i32::from_sample(i24::MAX), i32::MAX - 255); assert_eq!(i32::from_sample(i24::MID), i32::MID); assert_eq!(i32::from_sample(i24::MIN), i32::MIN); assert_eq!(i32::from_sample(i32::MAX), i32::MAX); assert_eq!(i32::from_sample(i32::MID), i32::MID); assert_eq!(i32::from_sample(i32::MIN), i32::MIN); assert_eq!(i32::from_sample(1.0f32), i32::MAX); assert_eq!(i32::from_sample(0f32), i32::MID); assert_eq!(i32::from_sample(-1.0f32), i32::MIN); assert_eq!(i32::from_sample(1.0f64), i32::MAX); assert_eq!(i32::from_sample(0f64), i32::MID); assert_eq!(i32::from_sample(-1.0f64), i32::MIN); } #[test] fn verify_f64_from_sample() { assert_eq!(f64::from_sample(u8::MAX), 127.0 / 128.0); assert_eq!(f64::from_sample(u8::MID), 0.0); assert_eq!(f64::from_sample(u8::MIN), -1.0); assert_eq!(f64::from_sample(u16::MAX), 32_767.0 / 32_768.0); assert_eq!(f64::from_sample(u16::MID), 0.0); assert_eq!(f64::from_sample(u16::MIN), -1.0); assert_eq!(f64::from_sample(u24::MAX), 8_388_607.0 / 8_388_608.0); assert_eq!(f64::from_sample(u24::MID), 0.0); assert_eq!(f64::from_sample(u24::MIN), -1.0); assert_eq!(f64::from_sample(u32::MAX), 2_147_483_647.0 / 2_147_483_648.0); assert_eq!(f64::from_sample(u32::MID), 0.0); assert_eq!(f64::from_sample(u32::MIN), -1.0); assert_eq!(f64::from_sample(i8::MAX), 127.0 / 128.0); assert_eq!(f64::from_sample(i8::MID), 0.0); assert_eq!(f64::from_sample(i8::MIN), -1.0); assert_eq!(f64::from_sample(i16::MAX), 32_767.0 / 32_768.0); assert_eq!(f64::from_sample(i16::MID), 0.0); assert_eq!(f64::from_sample(i16::MIN), -1.0); assert_eq!(f64::from_sample(i24::MAX), 8_388_607.0 / 8_388_608.0); assert_eq!(f64::from_sample(i24::MID), 0.0); assert_eq!(f64::from_sample(i24::MIN), -1.0); assert_eq!(f64::from_sample(i32::MAX), 2_147_483_647.0 / 2_147_483_648.0); assert_eq!(f64::from_sample(i32::MID), 0.0); assert_eq!(f64::from_sample(i32::MIN), -1.0); assert_eq!(f64::from_sample(1.0f32), 1.0); assert_eq!(f64::from_sample(0f32), 0.0); assert_eq!(f64::from_sample(-1.0f32), -1.0); assert_eq!(f64::from_sample(1.0f64), 1.0); assert_eq!(f64::from_sample(0f64), 0.0); assert_eq!(f64::from_sample(-1.0f64), -1.0); } #[test] fn verify_f32_from_sample() { assert_eq!(f32::from_sample(u8::MAX), 127.0 / 128.0); assert_eq!(f32::from_sample(u8::MID), 0.0); assert_eq!(f32::from_sample(u8::MIN), -1.0); assert_eq!(f32::from_sample(u16::MAX), 32_767.0 / 32_768.0); assert_eq!(f32::from_sample(u16::MID), 0.0); assert_eq!(f32::from_sample(u16::MIN), -1.0); assert_eq!(f32::from_sample(u24::MAX), 8_388_607.0 / 8_388_608.0); assert_eq!(f32::from_sample(u24::MID), 0.0); assert_eq!(f32::from_sample(u24::MIN), -1.0); assert_eq!(f32::from_sample(u32::MAX), 2_147_483_647.0 / 2_147_483_648.0); assert_eq!(f32::from_sample(u32::MID), 0.0); assert_eq!(f32::from_sample(u32::MIN), -1.0); assert_eq!(f32::from_sample(i8::MAX), 127.0 / 128.0); assert_eq!(f32::from_sample(i8::MID), 0.0); assert_eq!(f32::from_sample(i8::MIN), -1.0); assert_eq!(f32::from_sample(i16::MAX), 32_767.0 / 32_768.0); assert_eq!(f32::from_sample(i16::MID), 0.0); assert_eq!(f32::from_sample(i16::MIN), -1.0); assert_eq!(f32::from_sample(i24::MAX), 8_388_607.0 / 8_388_608.0); assert_eq!(f32::from_sample(i24::MID), 0.0); assert_eq!(f32::from_sample(i24::MIN), -1.0); assert_eq!(f32::from_sample(i32::MAX), 2_147_483_647.0 / 2_147_483_648.0); assert_eq!(f32::from_sample(i32::MID), 0.0); assert_eq!(f32::from_sample(i32::MIN), -1.0); assert_eq!(f32::from_sample(1.0f32), 1.0); assert_eq!(f32::from_sample(0f32), 0.0); assert_eq!(f32::from_sample(-1.0f32), -1.0); assert_eq!(f32::from_sample(1.0f64), 1.0); assert_eq!(f32::from_sample(0f64), 0.0); assert_eq!(f32::from_sample(-1.0f64), -1.0); } } symphonia-core-0.5.4/src/dsp/complex.rs000064400000000000000000000104641046102023000161660ustar 00000000000000// Symphonia // Copyright (c) 2019-2022 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/. //! The `complex` module implements a 32-bit floating point complex number. /// A complex number. #[derive(Copy, Clone, Default, Debug, PartialEq)] #[repr(C)] pub struct Complex { /// The real component. pub re: f32, /// The imaginary component. pub im: f32, } impl Complex { /// Create a new complex number. #[inline(always)] pub fn new(re: f32, im: f32) -> Self { Self { re, im } } /// Create a complex number with a value of `0 + j1`. #[inline(always)] pub fn j() -> Self { Self { re: 0.0, im: 1.0 } } /// Scale the complex number. #[inline(always)] pub fn scale(&self, scale: f32) -> Self { Self { re: self.re * scale, im: self.im * scale } } /// Take the complex conjugate of `self`. /// /// For a complex number defined as `a + jb` the complex conjugate is defined to be `a - jb`. #[inline(always)] pub fn conj(&self) -> Self { Self { re: self.re, im: -self.im } } } impl core::ops::Add for Complex { type Output = Complex; #[inline(always)] fn add(self, rhs: Self) -> Self::Output { Self::Output { re: self.re + rhs.re, im: self.im + rhs.im } } } impl core::ops::AddAssign for Complex { #[inline(always)] fn add_assign(&mut self, rhs: Self) { *self = *self + rhs; } } impl core::ops::Sub for Complex { type Output = Complex; #[inline(always)] fn sub(self, rhs: Self) -> Self::Output { Self::Output { re: self.re - rhs.re, im: self.im - rhs.im } } } impl core::ops::SubAssign for Complex { #[inline(always)] fn sub_assign(&mut self, rhs: Self) { *self = *self - rhs; } } impl core::ops::Mul for Complex { type Output = Complex; #[inline(always)] fn mul(self, rhs: Self) -> Self::Output { Self::Output { re: (self.re * rhs.re) - (self.im * rhs.im), im: (self.re * rhs.im) + (self.im * rhs.re), } } } impl core::ops::MulAssign for Complex { #[inline(always)] fn mul_assign(&mut self, rhs: Self) { *self = *self * rhs; } } impl core::ops::Div for Complex { type Output = Complex; #[inline(always)] fn div(self, rhs: Self) -> Self::Output { let denom = rhs.re * rhs.re + rhs.im * rhs.im; Self::Output { re: (self.re * rhs.re + self.im * rhs.im) / denom, im: (self.im * rhs.re - self.re * rhs.im) / denom, } } } impl core::ops::DivAssign for Complex { #[inline(always)] fn div_assign(&mut self, rhs: Self) { *self = *self / rhs; } } impl core::ops::Mul for Complex { type Output = Complex; #[inline(always)] fn mul(self, rhs: f32) -> Self::Output { Self::Output { re: self.re * rhs, im: self.im * rhs } } } impl core::ops::Div for Complex { type Output = Complex; #[inline(always)] fn div(self, rhs: f32) -> Self::Output { Self::Output { re: self.re / rhs, im: self.im / rhs } } } #[cfg(test)] mod tests { use super::*; #[test] fn verify_complex() { assert_eq!(Complex::j(), Complex::new(0.0, 1.0)); // Conjugate assert_eq!(Complex::new(1.0, 10.0).conj(), Complex::new(1.0, -10.0)); // Scale assert_eq!(Complex::new(5.0, 2.0).scale(3.0), Complex::new(15.0, 6.0)); // Addition assert_eq!(Complex::new(3.0, 13.0) + Complex::new(7.0, 17.0), Complex::new(10.0, 30.0)); // Subtraction assert_eq!(Complex::new(3.0, 13.0) - Complex::new(7.0, 17.0), Complex::new(-4.0, -4.0)); // Multiplication assert_eq!(Complex::new(3.0, 13.0) * Complex::new(7.0, 17.0), Complex::new(-200.0, 142.0)); // Division assert_eq!( Complex::new(3.0, 13.0) / Complex::new(7.0, 17.0), Complex::new(121.0 / 169.0, 20.0 / 169.0) ); // Scalar Multiplication assert_eq!(Complex::new(5.0, 2.0) * 3.0, Complex::new(15.0, 6.0)); // Scalar Division assert_eq!(Complex::new(4.0, 2.0) / 2.0, Complex::new(2.0, 1.0)); } } symphonia-core-0.5.4/src/dsp/fft.rs000064400000000000000000000462321046102023000153000ustar 00000000000000// Symphonia // Copyright (c) 2019-2022 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/. //! The `fft` module implements the Fast Fourier Transform (FFT). //! //! The complex (I)FFT in this module supports a size up-to 65536. The FFT is implemented using the //! radix-2 Cooley-Tukey algorithm. use std::convert::TryInto; use std::f32; use lazy_static::lazy_static; use super::complex::Complex; macro_rules! fft_twiddle_table { ($bi:expr, $name:ident) => { lazy_static! { static ref $name: [Complex; (1 << $bi) >> 1] = { const N: usize = 1 << $bi; let mut table = [Default::default(); N >> 1]; let theta = std::f64::consts::PI / (N >> 1) as f64; for (k, t) in table.iter_mut().enumerate() { let angle = theta * k as f64; *t = Complex::new(angle.cos() as f32, -angle.sin() as f32); } table }; } }; } fft_twiddle_table!(6, FFT_TWIDDLE_TABLE_64); fft_twiddle_table!(7, FFT_TWIDDLE_TABLE_128); fft_twiddle_table!(8, FFT_TWIDDLE_TABLE_256); fft_twiddle_table!(9, FFT_TWIDDLE_TABLE_512); fft_twiddle_table!(10, FFT_TWIDDLE_TABLE_1024); fft_twiddle_table!(11, FFT_TWIDDLE_TABLE_2048); fft_twiddle_table!(12, FFT_TWIDDLE_TABLE_4096); fft_twiddle_table!(13, FFT_TWIDDLE_TABLE_8192); fft_twiddle_table!(14, FFT_TWIDDLE_TABLE_16384); fft_twiddle_table!(15, FFT_TWIDDLE_TABLE_32768); fft_twiddle_table!(16, FFT_TWIDDLE_TABLE_65536); /// Get the twiddle factors for a FFT of size `n`. fn fft_twiddle_factors(n: usize) -> &'static [Complex] { // FFT sizes <= 32 use unrolled FFT implementations with hard-coded twiddle factors. match n { 64 => FFT_TWIDDLE_TABLE_64.as_ref(), 128 => FFT_TWIDDLE_TABLE_128.as_ref(), 256 => FFT_TWIDDLE_TABLE_256.as_ref(), 512 => FFT_TWIDDLE_TABLE_512.as_ref(), 1024 => FFT_TWIDDLE_TABLE_1024.as_ref(), 2048 => FFT_TWIDDLE_TABLE_2048.as_ref(), 4096 => FFT_TWIDDLE_TABLE_4096.as_ref(), 8192 => FFT_TWIDDLE_TABLE_8192.as_ref(), 16384 => FFT_TWIDDLE_TABLE_16384.as_ref(), 32768 => FFT_TWIDDLE_TABLE_32768.as_ref(), 65536 => FFT_TWIDDLE_TABLE_65536.as_ref(), _ => panic!("fft size too large"), } } /// The complex Fast Fourier Transform (FFT). pub struct Fft { perm: Box<[u16]>, } impl Fft { /// The maximum FFT size. pub const MAX_SIZE: usize = 1 << 16; pub fn new(n: usize) -> Self { // The FFT size must be a power of two. assert!(n.is_power_of_two()); // The permutation table uses 16-bit indicies. Therefore, the absolute maximum FFT size is // limited to 2^16. assert!(n <= Fft::MAX_SIZE); // Calculate the bit reversal table. let n = n as u16; let shift = n.leading_zeros() + 1; let perm = (0..n).map(|i| i.reverse_bits() >> shift).collect(); Self { perm } } /// Get the size of the FFT. pub fn size(&self) -> usize { self.perm.len() } /// Calculate the inverse FFT. pub fn ifft(&self, x: &[Complex], y: &mut [Complex]) { let n = x.len(); assert_eq!(n, y.len()); assert_eq!(n, self.perm.len()); // Bit reversal using pre-computed permutation table. for (x, y) in self.perm.iter().map(|&i| x[usize::from(i)]).zip(y.iter_mut()) { *y = Complex { re: x.im, im: x.re }; } // Do the forward FFT. Self::transform(y, n); // Output scale. let c = 1.0 / n as f32; for y in y.iter_mut() { *y = Complex { re: c * y.im, im: c * y.re }; } } /// Calculate the inverse FFT in-place. pub fn ifft_inplace(&self, x: &mut [Complex]) { let n = x.len(); assert_eq!(n, self.perm.len()); // Bit reversal using pre-computed permutation table. for (i, &j) in self.perm.iter().enumerate() { let j = usize::from(j); if i <= j { // Swap real and imaginary components while swapping for bit-reversal. let xi = x[i]; let xj = x[j]; x[i] = Complex::new(xj.im, xj.re); x[j] = Complex::new(xi.im, xi.re); } } // Do the forward FFT. Self::transform(x, n); // Output scale. let c = 1.0 / n as f32; for x in x.iter_mut() { *x = Complex { re: c * x.im, im: c * x.re }; } } /// Calculate the FFT in-place. pub fn fft_inplace(&self, x: &mut [Complex]) { let n = x.len(); assert_eq!(n, x.len()); assert_eq!(n, self.perm.len()); for (i, &j) in self.perm.iter().enumerate() { let j = usize::from(j); if i < j { x.swap(i, j); } } // Start FFT recursion. match n { 1 => (), 2 => fft2(x.try_into().unwrap()), 4 => fft4(x.try_into().unwrap()), 8 => fft8(x.try_into().unwrap()), 16 => fft16(x.try_into().unwrap()), _ => Self::transform(x, n), } } /// Calculate the FFT. pub fn fft(&self, x: &[Complex], y: &mut [Complex]) { let n = x.len(); assert_eq!(n, y.len()); assert_eq!(n, self.perm.len()); // Bit reversal using pre-computed permutation table. for (x, y) in self.perm.iter().map(|&i| x[usize::from(i)]).zip(y.iter_mut()) { *y = x; } // Start FFT recursion. match n { 1 => (), 2 => fft2(y.try_into().unwrap()), 4 => fft4(y.try_into().unwrap()), 8 => fft8(y.try_into().unwrap()), 16 => fft16(y.try_into().unwrap()), _ => Self::transform(y, n), } } fn transform(x: &mut [Complex], n: usize) { fn to_arr(x: &mut [Complex]) -> Option<&mut [Complex; 32]> { x.try_into().ok() } if let Some(x) = to_arr(x) { fft32(x); } else { let n_half = n >> 1; let (even, odd) = x.split_at_mut(n_half); Self::transform(even, n_half); Self::transform(odd, n_half); let twiddle = fft_twiddle_factors(n); for ((e, o), w) in even.chunks_exact_mut(2).zip(odd.chunks_exact_mut(2)).zip(twiddle.chunks_exact(2)) { let p0 = e[0]; let q0 = o[0] * w[0]; e[0] = p0 + q0; o[0] = p0 - q0; let p1 = e[1]; let q1 = o[1] * w[1]; e[1] = p1 + q1; o[1] = p1 - q1; } } } } macro_rules! complex { ($re:expr, $im:expr) => { Complex { re: $re, im: $im } }; } fn fft32(x: &mut [Complex; 32]) { let mut x0 = [ x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12], x[13], x[14], x[15], ]; let mut x1 = [ x[16], x[17], x[18], x[19], x[20], x[21], x[22], x[23], x[24], x[25], x[26], x[27], x[28], x[29], x[30], x[31], ]; fft16(&mut x0); fft16(&mut x1); let a4 = f32::consts::FRAC_1_SQRT_2 * x1[4].re; let b4 = f32::consts::FRAC_1_SQRT_2 * x1[4].im; let a12 = -f32::consts::FRAC_1_SQRT_2 * x1[12].re; let b12 = -f32::consts::FRAC_1_SQRT_2 * x1[12].im; let x1p = [ x1[0], complex!(0.98078528040323044913, -0.19509032201612826785) * x1[1], complex!(0.92387953251128675613, -0.38268343236508977173) * x1[2], complex!(0.83146961230254523708, -0.55557023301960222474) * x1[3], complex!(a4 + b4, b4 - a4), complex!(0.55557023301960222474, -0.83146961230254523708) * x1[5], complex!(0.38268343236508977173, -0.92387953251128675613) * x1[6], complex!(0.19509032201612826785, -0.98078528040323044913) * x1[7], complex!(x1[8].im, -x1[8].re), complex!(-0.19509032201612826785, -0.98078528040323044913) * x1[9], complex!(-0.38268343236508977173, -0.92387953251128675613) * x1[10], complex!(-0.55557023301960222474, -0.83146961230254523708) * x1[11], complex!(a12 - b12, a12 + b12), complex!(-0.83146961230254523708, -0.55557023301960222474) * x1[13], complex!(-0.92387953251128675613, -0.38268343236508977173) * x1[14], complex!(-0.98078528040323044913, -0.19509032201612826785) * x1[15], ]; x[0] = x0[0] + x1p[0]; x[1] = x0[1] + x1p[1]; x[2] = x0[2] + x1p[2]; x[3] = x0[3] + x1p[3]; x[4] = x0[4] + x1p[4]; x[5] = x0[5] + x1p[5]; x[6] = x0[6] + x1p[6]; x[7] = x0[7] + x1p[7]; x[8] = x0[8] + x1p[8]; x[9] = x0[9] + x1p[9]; x[10] = x0[10] + x1p[10]; x[11] = x0[11] + x1p[11]; x[12] = x0[12] + x1p[12]; x[13] = x0[13] + x1p[13]; x[14] = x0[14] + x1p[14]; x[15] = x0[15] + x1p[15]; x[16] = x0[0] - x1p[0]; x[17] = x0[1] - x1p[1]; x[18] = x0[2] - x1p[2]; x[19] = x0[3] - x1p[3]; x[20] = x0[4] - x1p[4]; x[21] = x0[5] - x1p[5]; x[22] = x0[6] - x1p[6]; x[23] = x0[7] - x1p[7]; x[24] = x0[8] - x1p[8]; x[25] = x0[9] - x1p[9]; x[26] = x0[10] - x1p[10]; x[27] = x0[11] - x1p[11]; x[28] = x0[12] - x1p[12]; x[29] = x0[13] - x1p[13]; x[30] = x0[14] - x1p[14]; x[31] = x0[15] - x1p[15]; } #[inline(always)] fn fft16(x: &mut [Complex; 16]) { let mut x0 = [x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7]]; let mut x1 = [x[8], x[9], x[10], x[11], x[12], x[13], x[14], x[15]]; fft8(&mut x0); fft8(&mut x1); let a2 = f32::consts::FRAC_1_SQRT_2 * x1[2].re; let b2 = f32::consts::FRAC_1_SQRT_2 * x1[2].im; let a6 = -f32::consts::FRAC_1_SQRT_2 * x1[6].re; let b6 = -f32::consts::FRAC_1_SQRT_2 * x1[6].im; let x1p = [ x1[0], complex!(0.92387953251128675613, -0.38268343236508977173) * x1[1], complex!(a2 + b2, b2 - a2), complex!(0.38268343236508977173, -0.92387953251128675613) * x1[3], complex!(x1[4].im, -x1[4].re), complex!(-0.38268343236508977173, -0.92387953251128675613) * x1[5], complex!(a6 - b6, a6 + b6), complex!(-0.92387953251128675613, -0.38268343236508977173) * x1[7], ]; x[0] = x0[0] + x1p[0]; x[1] = x0[1] + x1p[1]; x[2] = x0[2] + x1p[2]; x[3] = x0[3] + x1p[3]; x[4] = x0[4] + x1p[4]; x[5] = x0[5] + x1p[5]; x[6] = x0[6] + x1p[6]; x[7] = x0[7] + x1p[7]; x[8] = x0[0] - x1p[0]; x[9] = x0[1] - x1p[1]; x[10] = x0[2] - x1p[2]; x[11] = x0[3] - x1p[3]; x[12] = x0[4] - x1p[4]; x[13] = x0[5] - x1p[5]; x[14] = x0[6] - x1p[6]; x[15] = x0[7] - x1p[7]; } #[inline(always)] fn fft8(x: &mut [Complex; 8]) { let mut x0 = [x[0], x[1], x[2], x[3]]; let mut x1 = [x[4], x[5], x[6], x[7]]; fft4(&mut x0); fft4(&mut x1); let a1 = f32::consts::FRAC_1_SQRT_2 * x1[1].re; let b1 = f32::consts::FRAC_1_SQRT_2 * x1[1].im; let a3 = -f32::consts::FRAC_1_SQRT_2 * x1[3].re; let b3 = -f32::consts::FRAC_1_SQRT_2 * x1[3].im; let x1p = [ x1[0], complex!(a1 + b1, b1 - a1), complex!(x1[2].im, -x1[2].re), complex!(a3 - b3, a3 + b3), ]; x[0] = x0[0] + x1p[0]; x[1] = x0[1] + x1p[1]; x[2] = x0[2] + x1p[2]; x[3] = x0[3] + x1p[3]; x[4] = x0[0] - x1p[0]; x[5] = x0[1] - x1p[1]; x[6] = x0[2] - x1p[2]; x[7] = x0[3] - x1p[3]; } #[inline(always)] fn fft4(x: &mut [Complex; 4]) { let x0 = [x[0] + x[1], x[0] - x[1]]; let x1 = [x[2] + x[3], x[2] - x[3]]; let x1p1 = complex!(x1[1].im, -x1[1].re); x[0] = x0[0] + x1[0]; x[1] = x0[1] + x1p1; x[2] = x0[0] - x1[0]; x[3] = x0[1] - x1p1; } #[inline(always)] fn fft2(x: &mut [Complex; 2]) { let x0 = x[0]; x[0] = x0 + x[1]; x[1] = x0 - x[1]; } #[cfg(test)] mod tests { use super::*; use std::f64; /// Compute a naive DFT. fn dft_naive(x: &[Complex], y: &mut [Complex]) { assert_eq!(x.len(), y.len()); let n = x.len() as u64; let theta = 2.0 * f64::consts::PI / (x.len() as f64); for (i, y) in y.iter_mut().enumerate() { let mut re = 0f64; let mut im = 0f64; for (j, &x) in x.iter().enumerate() { let xre = f64::from(x.re); let xim = f64::from(x.im); let ij = ((i as u64) * (j as u64)) & (n - 1); let wre = (theta * ij as f64).cos(); let wim = -(theta * ij as f64).sin(); re += (xre * wre) - (xim * wim); im += (xre * wim) + (xim * wre); } *y = Complex { re: re as f32, im: im as f32 }; } } /// Compute a naive IDFT. fn idft_naive(x: &[Complex], y: &mut [Complex]) { let n = x.len() as u64; let z = x.iter().map(|x| Complex { re: x.im, im: x.re }).collect::>(); dft_naive(&z, y); let c = 1.0 / n as f32; for y in y.iter_mut() { *y = Complex { re: c * y.im, im: c * y.re }; } } /// Returns true if both real and imaginary complex number components deviate by less than /// `epsilon` between the left-hand side and right-hand side. fn check_complex(lhs: Complex, rhs: Complex, epsilon: f32) -> bool { (lhs.re - rhs.re).abs() < epsilon && (lhs.im - rhs.im).abs() < epsilon } #[rustfmt::skip] const TEST_VECTOR: [Complex; 64] = [ Complex { re: -1.82036, im: -0.72591 }, Complex { re: 1.21002, im: 0.75897 }, Complex { re: 1.31084, im: -0.51285 }, Complex { re: 1.26443, im: 1.57430 }, Complex { re: -1.93680, im: 0.69987 }, Complex { re: 0.85269, im: -0.20148 }, Complex { re: 1.10078, im: 0.88904 }, Complex { re: -1.20634, im: -0.07612 }, Complex { re: 1.43358, im: -1.91248 }, Complex { re: 0.10594, im: -0.30743 }, Complex { re: 1.51258, im: 0.99538 }, Complex { re: -1.33673, im: 0.23797 }, Complex { re: 0.43738, im: -1.69900 }, Complex { re: -0.95355, im: -0.33534 }, Complex { re: -0.05479, im: -0.32739 }, Complex { re: -1.85529, im: -1.93157 }, Complex { re: -1.04220, im: 1.04277 }, Complex { re: -0.17585, im: 0.40640 }, Complex { re: 0.09893, im: 1.89538 }, Complex { re: 1.25018, im: -0.85052 }, Complex { re: -1.60696, im: -1.41320 }, Complex { re: -0.25171, im: -0.13830 }, Complex { re: 1.17782, im: -1.41225 }, Complex { re: -0.35389, im: -0.30323 }, Complex { re: -0.16485, im: -0.83675 }, Complex { re: -1.66729, im: -0.52132 }, Complex { re: 1.41246, im: 1.58295 }, Complex { re: -1.84041, im: 0.15331 }, Complex { re: -1.38897, im: 1.16180 }, Complex { re: 0.27927, im: -1.84254 }, Complex { re: -0.46229, im: 0.09699 }, Complex { re: 1.21027, im: -0.31551 }, Complex { re: 0.26195, im: -1.19340 }, Complex { re: 1.60673, im: 1.07094 }, Complex { re: -0.07456, im: -0.63058 }, Complex { re: -1.77397, im: 1.39608 }, Complex { re: -0.80300, im: 0.08858 }, Complex { re: -0.06289, im: 1.48840 }, Complex { re: 0.66399, im: 0.49451 }, Complex { re: -1.49827, im: 1.61856 }, Complex { re: -1.39006, im: 0.67652 }, Complex { re: -0.90232, im: 0.18255 }, Complex { re: 0.00525, im: -1.05797 }, Complex { re: 0.53688, im: 0.88532 }, Complex { re: 0.52712, im: -0.58205 }, Complex { re: -1.77624, im: -0.66799 }, Complex { re: 1.65335, im: -1.72668 }, Complex { re: -0.24568, im: 1.50477 }, Complex { re: -0.15051, im: 0.67824 }, Complex { re: -1.96744, im: 0.81734 }, Complex { re: -1.62630, im: -0.73233 }, Complex { re: -1.98698, im: 0.63824 }, Complex { re: 0.78115, im: 0.97909 }, Complex { re: 0.97392, im: 1.82166 }, Complex { re: 1.30982, im: -1.23975 }, Complex { re: 0.85813, im: 0.80842 }, Complex { re: -1.13934, im: 0.81352 }, Complex { re: -1.22092, im: 0.98348 }, Complex { re: -1.67949, im: 0.78278 }, Complex { re: -1.77411, im: 0.00424 }, Complex { re: 1.93204, im: -0.03273 }, Complex { re: 1.38529, im: 1.31798 }, Complex { re: 0.61666, im: -0.09798 }, Complex { re: 1.02132, im: 1.70293 }, ]; #[test] fn verify_fft() { let mut actual = [Default::default(); TEST_VECTOR.len()]; let mut expected = [Default::default(); TEST_VECTOR.len()]; // Expected dft_naive(&TEST_VECTOR, &mut expected); // Actual Fft::new(TEST_VECTOR.len()).fft(&TEST_VECTOR, &mut actual); for (&a, &e) in actual.iter().zip(expected.iter()) { assert!(check_complex(a, e, 0.00001)); } } #[test] fn verify_fft_inplace() { let mut actual = [Default::default(); TEST_VECTOR.len()]; let mut expected = [Default::default(); TEST_VECTOR.len()]; // Expected dft_naive(&TEST_VECTOR, &mut expected); // Actual actual.copy_from_slice(&TEST_VECTOR); Fft::new(TEST_VECTOR.len()).fft_inplace(&mut actual); for (&a, &e) in actual.iter().zip(expected.iter()) { assert!(check_complex(a, e, 0.00001)); } } #[test] fn verify_ifft() { let mut actual = [Default::default(); TEST_VECTOR.len()]; let mut expected = [Default::default(); TEST_VECTOR.len()]; // Expected idft_naive(&TEST_VECTOR, &mut expected); // Actual Fft::new(TEST_VECTOR.len()).ifft(&TEST_VECTOR, &mut actual); for (&a, &e) in actual.iter().zip(expected.iter()) { assert!(check_complex(a, e, 0.00001)); } } #[test] fn verify_ifft_inplace() { let mut actual = [Default::default(); TEST_VECTOR.len()]; let mut expected = [Default::default(); TEST_VECTOR.len()]; // Expected idft_naive(&TEST_VECTOR, &mut expected); // Actual actual.copy_from_slice(&TEST_VECTOR); Fft::new(TEST_VECTOR.len()).ifft_inplace(&mut actual); for (&a, &e) in actual.iter().zip(expected.iter()) { assert!(check_complex(a, e, 0.00001)); } } #[test] fn verify_fft_reversible() { let mut fft_out = [Default::default(); TEST_VECTOR.len()]; let mut ifft_out = [Default::default(); TEST_VECTOR.len()]; let fft = Fft::new(TEST_VECTOR.len()); fft.fft(&TEST_VECTOR, &mut fft_out); fft.ifft(&fft_out, &mut ifft_out); for (&a, &e) in ifft_out.iter().zip(TEST_VECTOR.iter()) { assert!(check_complex(a, e, 0.000001)); } } #[test] fn verify_fft_inplace_reversible() { let mut out = [Default::default(); TEST_VECTOR.len()]; out.copy_from_slice(&TEST_VECTOR); let fft = Fft::new(TEST_VECTOR.len()); fft.fft_inplace(&mut out); fft.ifft_inplace(&mut out); for (&a, &e) in out.iter().zip(TEST_VECTOR.iter()) { assert!(check_complex(a, e, 0.000001)); } } } symphonia-core-0.5.4/src/dsp/mdct/mod.rs000064400000000000000000000046111046102023000162220ustar 00000000000000// Symphonia // Copyright (c) 2019-2022 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/. //! The `mdct` module implements the Modified Discrete Cosine Transform (MDCT). //! //! The MDCT in this module is implemented in-terms of a forward FFT. #[cfg(any(feature = "opt-simd-sse", feature = "opt-simd-avx", feature = "opt-simd-neon"))] mod simd; #[cfg(any(feature = "opt-simd-sse", feature = "opt-simd-avx", feature = "opt-simd-neon"))] pub use simd::*; #[cfg(not(any(feature = "opt-simd-sse", feature = "opt-simd-avx", feature = "opt-simd-neon")))] mod no_simd; #[cfg(not(any( feature = "opt-simd-sse", feature = "opt-simd-avx", feature = "opt-simd-neon" )))] pub use no_simd::*; #[cfg(test)] mod tests { use super::*; use std::f64; fn imdct_analytical(x: &[f32], y: &mut [f32], scale: f64) { assert!(y.len() == 2 * x.len()); // Generates 2N outputs from N inputs. let n_in = x.len(); let n_out = x.len() << 1; let pi_2n = f64::consts::PI / (2 * n_out) as f64; for (i, item) in y.iter_mut().enumerate().take(n_out) { let accum: f64 = x .iter() .copied() .map(f64::from) .enumerate() .take(n_in) .map(|(j, jtem)| jtem * (pi_2n * ((2 * i + 1 + n_in) * (2 * j + 1)) as f64).cos()) .sum(); *item = (scale * accum) as f32; } } #[test] fn verify_imdct() { #[rustfmt::skip] const TEST_VECTOR: [f32; 32] = [ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0, 29.0, 30.0, 31.0, 32.0, ]; let mut actual = [0f32; 64]; let mut expected = [0f32; 64]; let scale = (2.0f64 / 64.0).sqrt(); imdct_analytical(&TEST_VECTOR, &mut expected, scale); let mut mdct = Imdct::new_scaled(32, scale); mdct.imdct(&TEST_VECTOR, &mut actual); for i in 0..64 { let delta = f64::from(actual[i]) - f64::from(expected[i]); assert!(delta.abs() < 0.00001); } } } symphonia-core-0.5.4/src/dsp/mdct/no_simd.rs000064400000000000000000000141111046102023000170670ustar 00000000000000// Symphonia // Copyright (c) 2019-2023 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/. //! The Modified Discrete Cosine Transform (MDCT) implemented without SIMD optimizations. use crate::dsp::complex::Complex; use crate::dsp::fft::*; /// The Inverse Modified Discrete Transform (IMDCT). pub struct Imdct { fft: Fft, fft_in: Box<[Complex]>, fft_out: Box<[Complex]>, twiddle: Box<[Complex]>, } impl Imdct { /// Instantiate a N-point IMDCT with no scaling. /// /// The value of `n` is the number of spectral samples and must be a power-of-2 and less-than or /// equal to `2 * Fft::MAX_SIZE`. pub fn new(n: usize) -> Self { Imdct::new_scaled(n, 1.0) } /// Instantiate a N-point IMDCT with scaling. /// /// The value of `n` is the number of spectral samples and must be a power-of-2 and less-than or /// equal to `2 * Fft::MAX_SIZE`. pub fn new_scaled(n: usize, scale: f64) -> Self { // The FFT requires a power-of-two N. assert!(n.is_power_of_two(), "n must be a power of two"); // A complex FFT of size N/2 is used to compute the IMDCT. Therefore, the maximum value of N // is 2 * Fft::MAX_SIZE. assert!(n <= 2 * Fft::MAX_SIZE, "maximum size exceeded"); let n2 = n / 2; let mut twiddle = Vec::with_capacity(n2); let alpha = 1.0 / 8.0 + if scale.is_sign_positive() { 0.0 } else { n2 as f64 }; let pi_n = std::f64::consts::PI / n as f64; let sqrt_scale = scale.abs().sqrt(); for k in 0..n2 { let theta = pi_n * (alpha + k as f64); let re = sqrt_scale * theta.cos(); let im = sqrt_scale * theta.sin(); twiddle.push(Complex::new(re as f32, im as f32)); } let fft_in = vec![Default::default(); n2].into_boxed_slice(); let fft_out = vec![Default::default(); n2].into_boxed_slice(); Imdct { fft: Fft::new(n2), fft_in, fft_out, twiddle: twiddle.into_boxed_slice() } } /// Performs the the N-point Inverse Modified Discrete Cosine Transform. /// /// The number of input spectral samples provided by the slice `spec` must equal the value of N /// that the IMDCT was instantiated with. The length of the output slice, `out`, must be of /// length 2N. Failing to meet these requirements will throw an assertion. pub fn imdct(&mut self, spec: &[f32], out: &mut [f32]) { // Spectral length: 2x FFT size, 0.5x output length. let n = self.fft.size() << 1; // 1x FFT size, 0.25x output length. let n2 = n >> 1; // 0.5x FFT size. let n4 = n >> 2; // The spectrum length must be the same as N. assert_eq!(spec.len(), n); // The output length must be 2x the spectrum length. assert_eq!(out.len(), 2 * n); // Pre-FFT twiddling and packing of the real input signal values into complex signal values. for (i, (&w, t)) in self.twiddle.iter().zip(self.fft_in.iter_mut()).enumerate() { let even = spec[i * 2]; let odd = -spec[n - 1 - i * 2]; let re = odd * w.im - even * w.re; let im = odd * w.re + even * w.im; *t = Complex::new(re, im); } // Do the FFT. self.fft.fft(&self.fft_in, &mut self.fft_out); // Split the output vector (2N samples) into 4 vectors (N/2 samples each). let (vec0, vec1) = out.split_at_mut(n2); let (vec1, vec2) = vec1.split_at_mut(n2); let (vec2, vec3) = vec2.split_at_mut(n2); // Post-FFT twiddling and processing to expand the N/2 complex output values into 2N real // output samples. for (i, (x, &w)) in self.fft_out[..n4].iter().zip(self.twiddle[..n4].iter()).enumerate() { // The real and imaginary components of the post-twiddled FFT samples are used to // generate 4 reak output samples. Using the first half of the complex FFT output, // populate each of the 4 output vectors. let val = w * x.conj(); // Forward and reverse order indicies that will be populated. let fi = 2 * i; let ri = n2 - 1 - 2 * i; // The odd indicies in vec0 are populated reverse order. vec0[ri] = -val.im; // The even indicies in vec1 are populated forward order. vec1[fi] = val.im; // The odd indicies in vec2 are populated reverse order. vec2[ri] = val.re; // The even indicies in vec3 are populated forward order. vec3[fi] = val.re; } for (i, (x, &w)) in self.fft_out[n4..].iter().zip(self.twiddle[n4..].iter()).enumerate() { // Using the second half of the FFT output samples, finish populating each of the 4 // output vectors. let val = w * x.conj(); // Forward and reverse order indicies that will be populated. let fi = 2 * i; let ri = n2 - 1 - 2 * i; // The even indicies in vec0 are populated in forward order. vec0[fi] = -val.re; // The odd indicies in vec1 are populated in reverse order. vec1[ri] = val.re; // The even indicies in vec2 are populated in forward order. vec2[fi] = val.im; // The odd indicies in vec3 are populated in reverse order. vec3[ri] = val.im; } // Note: As of Rust 1.58, there doesn't appear to be any measurable difference between using // iterators or indexing like above. Either the bounds checks are elided above, or they are // not elided using iterators. Therefore, for clarity, the indexing method is used. // // Additionally, note that vectors 0 and 3 are reversed copies (+ negation for vector 0) of // vectors 1 and 2, respectively. Pulling these copies out into a separate loop using // iterators yielded no measureable difference either. } } symphonia-core-0.5.4/src/dsp/mdct/simd.rs000064400000000000000000000144151046102023000164020ustar 00000000000000// Symphonia // Copyright (c) 2019-2023 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/. //! The Modified Discrete Cosine Transform (MDCT) implemented with SIMD optimizations. use std::sync::Arc; use rustfft::num_complex::Complex; /// The Inverse Modified Discrete Transform (IMDCT). pub struct Imdct { fft: Arc>, fft_scratch: Box<[Complex]>, scratch: Box<[Complex]>, twiddle: Box<[Complex]>, } impl Imdct { /// Instantiate a N-point IMDCT with no scaling. /// /// The value of `n` is the number of spectral samples and must be a power-of-2 and less-than or /// equal to `2 * Fft::MAX_SIZE`. pub fn new(n: usize) -> Self { Imdct::new_scaled(n, 1.0) } /// Instantiate a N-point IMDCT with scaling. /// /// The value of `n` is the number of spectral samples and must be a power-of-2 and less-than or /// equal to `2 * Fft::MAX_SIZE`. pub fn new_scaled(n: usize, scale: f64) -> Self { // The algorithm requires a power-of-two N. assert!(n.is_power_of_two(), "n must be a power of two"); let n2 = n / 2; // Pre-compute the twiddle factors. let mut twiddle = Vec::with_capacity(n2); let alpha = 1.0 / 8.0 + if scale.is_sign_positive() { 0.0 } else { n2 as f64 }; let pi_n = std::f64::consts::PI / n as f64; let sqrt_scale = scale.abs().sqrt(); for k in 0..n2 { let theta = pi_n * (alpha + k as f64); let re = sqrt_scale * theta.cos(); let im = sqrt_scale * theta.sin(); twiddle.push(Complex::new(re as f32, im as f32)); } // Instantiate a half-length forward FFT. let mut planner = rustfft::FftPlanner::::new(); let fft = planner.plan_fft_forward(n2); // Allocate scratch for the FFT. let fft_scratch = vec![Default::default(); fft.get_inplace_scratch_len()].into_boxed_slice(); // Allocate scratch for the IMDCT. let scratch = vec![Default::default(); n2].into_boxed_slice(); Imdct { fft, fft_scratch, scratch, twiddle: twiddle.into_boxed_slice() } } /// Performs the the N-point Inverse Modified Discrete Cosine Transform. /// /// The number of input spectral samples provided by the slice `spec` must equal the value of N /// that the IMDCT was instantiated with. The length of the output slice, `out`, must be of /// length 2N. Failing to meet these requirements will throw an assertion. pub fn imdct(&mut self, spec: &[f32], out: &mut [f32]) { // Spectral length: 2x FFT size, 0.5x output length. let n = self.fft.len() << 1; // 1x FFT size, 0.25x output length. let n2 = n >> 1; // 0.5x FFT size. let n4 = n >> 2; // The spectrum length must be the same as N. assert_eq!(spec.len(), n); // The output length must be 2x the spectrum length. assert_eq!(out.len(), 2 * n); // Pre-FFT twiddling and packing of the real input signal values into complex signal values. for (i, (&w, t)) in self.twiddle.iter().zip(self.scratch.iter_mut()).enumerate() { let even = spec[i * 2]; let odd = -spec[n - 1 - i * 2]; let re = odd * w.im - even * w.re; let im = odd * w.re + even * w.im; *t = Complex::new(re, im); } // Do the FFT. self.fft.process_with_scratch(&mut self.scratch, &mut self.fft_scratch); // Split the output vector (2N samples) into 4 vectors (N/2 samples each). let (vec0, vec1) = out.split_at_mut(n2); let (vec1, vec2) = vec1.split_at_mut(n2); let (vec2, vec3) = vec2.split_at_mut(n2); // Post-FFT twiddling and processing to expand the N/2 complex output values into 2N real // output samples. for (i, (x, &w)) in self.scratch[..n4].iter().zip(self.twiddle[..n4].iter()).enumerate() { // The real and imaginary components of the post-twiddled FFT samples are used to // generate 4 reak output samples. Using the first half of the complex FFT output, // populate each of the 4 output vectors. let val = w * x.conj(); // Forward and reverse order indicies that will be populated. let fi = 2 * i; let ri = n2 - 1 - 2 * i; // The odd indicies in vec0 are populated reverse order. vec0[ri] = -val.im; // The even indicies in vec1 are populated forward order. vec1[fi] = val.im; // The odd indicies in vec2 are populated reverse order. vec2[ri] = val.re; // The even indicies in vec3 are populated forward order. vec3[fi] = val.re; } for (i, (x, &w)) in self.scratch[n4..].iter().zip(self.twiddle[n4..].iter()).enumerate() { // Using the second half of the FFT output samples, finish populating each of the 4 // output vectors. let val = w * x.conj(); // Forward and reverse order indicies that will be populated. let fi = 2 * i; let ri = n2 - 1 - 2 * i; // The even indicies in vec0 are populated in forward order. vec0[fi] = -val.re; // The odd indicies in vec1 are populated in reverse order. vec1[ri] = val.re; // The even indicies in vec2 are populated in forward order. vec2[fi] = val.im; // The odd indicies in vec3 are populated in reverse order. vec3[ri] = val.im; } // Note: As of Rust 1.58, there doesn't appear to be any measurable difference between using // iterators or indexing like above. Either the bounds checks are elided above, or they are // not elided using iterators. Therefore, for clarity, the indexing method is used. // // Additionally, note that vectors 0 and 3 are reversed copies (+ negation for vector 0) of // vectors 1 and 2, respectively. Pulling these copies out into a separate loop using // iterators yielded no measureable difference either. } } symphonia-core-0.5.4/src/dsp/mod.rs000064400000000000000000000006461046102023000152770ustar 00000000000000// Symphonia // Copyright (c) 2019-2022 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/. //! The `dsp` module provides efficient implementations of common signal processing algorithms. pub mod complex; pub mod fft; pub mod mdct; symphonia-core-0.5.4/src/errors.rs000064400000000000000000000101501046102023000152350ustar 00000000000000// Symphonia // Copyright (c) 2019-2022 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/. //! The `errors` module defines the common error type. use std::error; use std::fmt; use std::io; use std::result; /// `SeekErrorKind` is a list of generic reasons why a seek may fail. #[derive(Debug)] pub enum SeekErrorKind { /// The stream is not seekable at all. Unseekable, /// The stream can only be seeked forward. ForwardOnly, /// The timestamp to seek to is out of range. OutOfRange, /// The track ID provided is invalid. InvalidTrack, } impl SeekErrorKind { fn as_str(&self) -> &'static str { match *self { SeekErrorKind::Unseekable => "stream is not seekable", SeekErrorKind::ForwardOnly => "stream can only be seeked forward", SeekErrorKind::OutOfRange => "requested seek timestamp is out-of-range for stream", SeekErrorKind::InvalidTrack => "invalid track id", } } } /// `Error` provides an enumeration of all possible errors reported by Symphonia. #[derive(Debug)] pub enum Error { /// An IO error occured while reading, writing, or seeking the stream. IoError(std::io::Error), /// The stream contained malformed data and could not be decoded or demuxed. DecodeError(&'static str), /// The stream could not be seeked. SeekError(SeekErrorKind), /// An unsupported container or codec feature was encounted. Unsupported(&'static str), /// A default or user-defined limit was reached while decoding or demuxing the stream. Limits /// are used to prevent denial-of-service attacks from malicious streams. LimitError(&'static str), /// The demuxer or decoder needs to be reset before continuing. ResetRequired, } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Error::IoError(ref err) => err.fmt(f), Error::DecodeError(msg) => { write!(f, "malformed stream: {}", msg) } Error::SeekError(ref kind) => { write!(f, "seek error: {}", kind.as_str()) } Error::Unsupported(feature) => { write!(f, "unsupported feature: {}", feature) } Error::LimitError(constraint) => { write!(f, "limit reached: {}", constraint) } Error::ResetRequired => { write!(f, "decoder needs to be reset") } } } } impl std::error::Error for Error { fn cause(&self) -> Option<&dyn error::Error> { match *self { Error::IoError(ref err) => Some(err), Error::DecodeError(_) => None, Error::SeekError(_) => None, Error::Unsupported(_) => None, Error::LimitError(_) => None, Error::ResetRequired => None, } } } impl From for Error { fn from(err: io::Error) -> Error { Error::IoError(err) } } pub type Result = result::Result; /// Convenience function to create a decode error. pub fn decode_error(desc: &'static str) -> Result { Err(Error::DecodeError(desc)) } /// Convenience function to create a seek error. pub fn seek_error(kind: SeekErrorKind) -> Result { Err(Error::SeekError(kind)) } /// Convenience function to create an unsupport feature error. pub fn unsupported_error(feature: &'static str) -> Result { Err(Error::Unsupported(feature)) } /// Convenience function to create a limit error. pub fn limit_error(constraint: &'static str) -> Result { Err(Error::LimitError(constraint)) } /// Convenience function to create a reset required error. pub fn reset_error() -> Result { Err(Error::ResetRequired) } /// Convenience function to create an end-of-stream error. pub fn end_of_stream_error() -> Result { Err(Error::IoError(io::Error::new(io::ErrorKind::UnexpectedEof, "end of stream"))) } symphonia-core-0.5.4/src/formats.rs000064400000000000000000000515561046102023000154130ustar 00000000000000// Symphonia // Copyright (c) 2019-2022 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/. //! The `format` module provides the traits and support structures necessary to implement media //! demuxers. use crate::codecs::CodecParameters; use crate::errors::Result; use crate::io::{BufReader, MediaSourceStream}; use crate::meta::{Metadata, Tag}; use crate::units::{Time, TimeStamp}; pub mod prelude { //! The `formats` module prelude. pub use crate::units::{Duration, TimeBase, TimeStamp}; pub use super::{Cue, FormatOptions, FormatReader, Packet, SeekMode, SeekTo, SeekedTo, Track}; } /// `SeekTo` specifies a position to seek to. pub enum SeekTo { /// Seek to a `Time` in regular time units. Time { /// The `Time` to seek to. time: Time, /// If `Some`, specifies which track's timestamp should be returned after the seek. If /// `None`, then the default track's timestamp is returned. If the container does not have /// a default track, then the first track's timestamp is returned. track_id: Option, }, /// Seek to a track's `TimeStamp` in that track's timebase units. TimeStamp { /// The `TimeStamp` to seek to. ts: TimeStamp, /// Specifies which track `ts` is relative to. track_id: u32, }, } /// `SeekedTo` is the result of a seek. #[derive(Copy, Clone, Debug)] pub struct SeekedTo { /// The track the seek was relative to. pub track_id: u32, /// The `TimeStamp` required for the requested seek. pub required_ts: TimeStamp, /// The `TimeStamp` that was seeked to. pub actual_ts: TimeStamp, } /// `SeekMode` selects the precision of a seek. #[derive(Copy, Clone, Debug)] pub enum SeekMode { /// Coarse seek mode is a best-effort attempt to seek to the requested position. The actual /// position seeked to may be before or after the requested position. Coarse seeking is an /// optional performance enhancement. If a `FormatReader` does not support this mode an /// accurate seek will be performed instead. Coarse, /// Accurate (aka sample-accurate) seek mode will be always seek to a position before the /// requested position. Accurate, } /// `FormatOptions` is a common set of options that all demuxers use. #[derive(Copy, Clone, Debug)] pub struct FormatOptions { /// If a `FormatReader` requires a seek index, but the container does not provide one, build the /// seek index during instantiation instead of building it progressively. Default: `false`. pub prebuild_seek_index: bool, /// If a seek index needs to be built, this value determines how often in seconds of decoded /// content an entry is added to the index. Default: `20`. /// /// Note: This is a CPU vs. memory trade-off. A high value will increase the amount of IO /// required during a seek, whereas a low value will require more memory. The default chosen is /// a good compromise for casual playback of music, podcasts, movies, etc. However, for /// highly-interactive applications, this value should be decreased. pub seek_index_fill_rate: u16, /// Enable support for gapless playback. Default: `false`. /// /// When enabled, the reader will provide trim information in packets that may be used by /// decoders to trim any encoder delay or padding. /// /// When enabled, this option will also alter the value and interpretation of timestamps and /// durations such that they are relative to the non-trimmed region. pub enable_gapless: bool, } impl Default for FormatOptions { fn default() -> Self { FormatOptions { prebuild_seek_index: false, seek_index_fill_rate: 20, enable_gapless: false, } } } /// A `Cue` is a designated point of time within a media stream. /// /// A `Cue` may be a mapping from either a source track, a chapter, cuesheet, or a timestamp /// depending on the source media. A `Cue`'s duration is the difference between the `Cue`'s /// timestamp and the next. Each `Cue` may contain an optional index of points relative to the `Cue` /// that never exceed the timestamp of the next `Cue`. A `Cue` may also have associated `Tag`s. #[derive(Clone, Debug)] pub struct Cue { /// A unique index for the `Cue`. pub index: u32, /// The starting timestamp in number of frames from the start of the stream. pub start_ts: u64, /// A list of `Tag`s associated with the `Cue`. pub tags: Vec, /// A list of `CuePoints`s that are contained within this `Cue`. These points are children of /// the `Cue` since the `Cue` itself is an implicit `CuePoint`. pub points: Vec, } /// A `CuePoint` is a point, represented as a frame offset, within a `Cue`. /// /// A `CuePoint` provides more precise indexing within a parent `Cue`. Additional `Tag`s may be /// associated with a `CuePoint`. #[derive(Clone, Debug)] pub struct CuePoint { /// The offset of the first frame in the `CuePoint` relative to the start of the parent `Cue`. pub start_offset_ts: u64, /// A list of `Tag`s associated with the `CuePoint`. pub tags: Vec, } /// A `Track` is an independently coded media bitstream. A media format may contain multiple tracks /// in one container. Each of those tracks are represented by one `Track`. #[derive(Clone, Debug)] pub struct Track { /// A unique identifier for the track. pub id: u32, /// The codec parameters for the track. pub codec_params: CodecParameters, /// The language of the track. May be unknown. pub language: Option, } impl Track { pub fn new(id: u32, codec_params: CodecParameters) -> Self { Track { id, codec_params, language: None } } } /// A `FormatReader` is a container demuxer. It provides methods to probe a media container for /// information and access the tracks encapsulated in the container. /// /// Most, if not all, media containers contain metadata, then a number of packetized, and /// interleaved codec bitstreams. These bitstreams are usually referred to as tracks. Generally, /// the encapsulated bitstreams are independently encoded using some codec. The allowed codecs for a /// container are defined in the specification of the container format. /// /// While demuxing, packets are read one-by-one and may be discarded or decoded at the choice of /// the caller. The contents of a packet is undefined: it may be a frame of video, a millisecond /// of audio, or a subtitle, but a packet will never contain data from two different bitstreams. /// Therefore the caller can be selective in what tracks(s) should be decoded and consumed. /// /// `FormatReader` provides an Iterator-like interface over packets for easy consumption and /// filtering. Seeking will invalidate the state of any `Decoder` processing packets from the /// `FormatReader` and should be reset after a successful seek operation. pub trait FormatReader: Send + Sync { /// Attempt to instantiate a `FormatReader` using the provided `FormatOptions` and /// `MediaSourceStream`. The reader will probe the container to verify format support, determine /// the number of tracks, and read any initial metadata. fn try_new(source: MediaSourceStream, options: &FormatOptions) -> Result where Self: Sized; /// Gets a list of all `Cue`s. fn cues(&self) -> &[Cue]; /// Gets the metadata revision log. fn metadata(&mut self) -> Metadata<'_>; /// Seek, as precisely as possible depending on the mode, to the `Time` or track `TimeStamp` /// requested. Returns the requested and actual `TimeStamps` seeked to, as well as the `Track`. /// /// After a seek, all `Decoder`s consuming packets from this reader should be reset. /// /// Note: The `FormatReader` by itself cannot seek to an exact audio frame, it is only capable /// of seeking to the nearest `Packet`. Therefore, to seek to an exact frame, a `Decoder` must /// decode packets until the requested position is reached. When using the accurate `SeekMode`, /// the seeked position will always be before the requested position. If the coarse `SeekMode` /// is used, then the seek position may be after the requested position. Coarse seeking is an /// optional performance enhancement, therefore, a coarse seek may sometimes be an accurate /// seek. fn seek(&mut self, mode: SeekMode, to: SeekTo) -> Result; /// Gets a list of tracks in the container. fn tracks(&self) -> &[Track]; /// Gets the default track. If the `FormatReader` has a method of determining the default track, /// this function should return it. Otherwise, the first track is returned. If no tracks are /// present then `None` is returned. fn default_track(&self) -> Option<&Track> { self.tracks().first() } /// Get the next packet from the container. /// /// If `ResetRequired` is returned, then the track list must be re-examined and all `Decoder`s /// re-created. All other errors are unrecoverable. fn next_packet(&mut self) -> Result; /// Destroys the `FormatReader` and returns the underlying media source stream fn into_inner(self: Box) -> MediaSourceStream; } /// A `Packet` contains a discrete amount of encoded data for a single codec bitstream. The exact /// amount of data is bounded, but not defined, and is dependant on the container and/or the /// encapsulated codec. #[derive(Clone)] pub struct Packet { /// The track id. track_id: u32, /// The timestamp of the packet. When gapless support is enabled, this timestamp is relative to /// the end of the encoder delay. /// /// This timestamp is in `TimeBase` units. pub ts: u64, /// The duration of the packet. When gapless support is enabled, the duration does not include /// the encoder delay or padding. /// /// The duration is in `TimeBase` units. pub dur: u64, /// When gapless support is enabled, this is the number of decoded frames that should be trimmed /// from the start of the packet to remove the encoder delay. Must be 0 in all other cases. pub trim_start: u32, /// When gapless support is enabled, this is the number of decoded frames that should be trimmed /// from the end of the packet to remove the encoder padding. Must be 0 in all other cases. pub trim_end: u32, /// The packet buffer. pub data: Box<[u8]>, } impl Packet { /// Create a new `Packet` from a slice. pub fn new_from_slice(track_id: u32, ts: u64, dur: u64, buf: &[u8]) -> Self { Packet { track_id, ts, dur, trim_start: 0, trim_end: 0, data: Box::from(buf) } } /// Create a new `Packet` from a boxed slice. pub fn new_from_boxed_slice(track_id: u32, ts: u64, dur: u64, data: Box<[u8]>) -> Self { Packet { track_id, ts, dur, trim_start: 0, trim_end: 0, data } } /// Create a new `Packet` with trimming information from a slice. pub fn new_trimmed_from_slice( track_id: u32, ts: u64, dur: u64, trim_start: u32, trim_end: u32, buf: &[u8], ) -> Self { Packet { track_id, ts, dur, trim_start, trim_end, data: Box::from(buf) } } /// Create a new `Packet` with trimming information from a boxed slice. pub fn new_trimmed_from_boxed_slice( track_id: u32, ts: u64, dur: u64, trim_start: u32, trim_end: u32, data: Box<[u8]>, ) -> Self { Packet { track_id, ts, dur, trim_start, trim_end, data } } /// The track identifier of the track this packet belongs to. pub fn track_id(&self) -> u32 { self.track_id } /// Get the timestamp of the packet in `TimeBase` units. /// /// If gapless support is enabled, then this timestamp is relative to the end of the encoder /// delay. pub fn ts(&self) -> u64 { self.ts } /// Get the duration of the packet in `TimeBase` units. /// /// If gapless support is enabled, then this is the duration after the encoder delay and padding /// is trimmed. pub fn dur(&self) -> u64 { self.dur } /// Get the duration of the packet in `TimeBase` units if no decoded frames are trimmed. /// /// If gapless support is disabled, then this is the same as the duration. pub fn block_dur(&self) -> u64 { self.dur + u64::from(self.trim_start) + u64::from(self.trim_end) } /// Get the number of frames to trim from the start of the decoded packet. pub fn trim_start(&self) -> u32 { self.trim_start } /// Get the number of frames to trim from the end of the decoded packet. pub fn trim_end(&self) -> u32 { self.trim_end } /// Get an immutable slice to the packet buffer. pub fn buf(&self) -> &[u8] { &self.data } /// Get a `BufStream` to read the packet data buffer sequentially. pub fn as_buf_reader(&self) -> BufReader { BufReader::new(&self.data) } } pub mod util { //! Helper utilities for implementing `FormatReader`s. use super::Packet; /// A `SeekPoint` is a mapping between a sample or frame number to byte offset within a media /// stream. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct SeekPoint { /// The frame or sample timestamp of the `SeekPoint`. pub frame_ts: u64, /// The byte offset of the `SeekPoint`s timestamp relative to a format-specific location. pub byte_offset: u64, /// The number of frames the `SeekPoint` covers. pub n_frames: u32, } impl SeekPoint { fn new(frame_ts: u64, byte_offset: u64, n_frames: u32) -> Self { SeekPoint { frame_ts, byte_offset, n_frames } } } /// A `SeekIndex` stores `SeekPoint`s (generally a sample or frame number to byte offset) within /// a media stream and provides methods to efficiently search for the nearest `SeekPoint`(s) /// given a timestamp. /// /// A `SeekIndex` does not require complete coverage of the entire media stream. However, the /// better the coverage, the smaller the manual search range the `SeekIndex` will return. #[derive(Default)] pub struct SeekIndex { points: Vec, } /// `SeekSearchResult` is the return value for a search on a `SeekIndex`. It returns a range of /// `SeekPoint`s a `FormatReader` should search to find the desired timestamp. Ranges are /// lower-bound inclusive, and upper-bound exclusive. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum SeekSearchResult { /// The `SeekIndex` is empty so the desired timestamp could not be found. The entire stream /// should be searched for the desired timestamp. Stream, /// The desired timestamp can be found before, the `SeekPoint`. The stream should be /// searched for the desired timestamp from the start of the stream up-to, but not /// including, the `SeekPoint`. Upper(SeekPoint), /// The desired timestamp can be found at, or after, the `SeekPoint`. The stream should be /// searched for the desired timestamp starting at the provided `SeekPoint` up-to the end of /// the stream. Lower(SeekPoint), /// The desired timestamp can be found within the range. The stream should be searched for /// the desired starting at the first `SeekPoint` up-to, but not-including, the second /// `SeekPoint`. Range(SeekPoint, SeekPoint), } impl SeekIndex { /// Create an empty `SeekIndex` pub fn new() -> SeekIndex { SeekIndex { points: Vec::new() } } /// Insert a `SeekPoint` into the index. pub fn insert(&mut self, ts: u64, byte_offset: u64, n_frames: u32) { // Create the seek point. let seek_point = SeekPoint::new(ts, byte_offset, n_frames); // Get the timestamp of the last entry in the index. let last_ts = self.points.last().map_or(u64::MAX, |p| p.frame_ts); // If the seek point has a timestamp greater-than the last entry in the index, then // simply append it to the index. if ts > last_ts { self.points.push(seek_point) } else if ts < last_ts { // If the seek point has a timestamp less-than the last entry in the index, then the // insertion point must be found. This case should rarely occur. // TODO: Use when Rust 1.52 is stable. // let i = self.points.partition_point(|p| p.frame_ts < ts); let i = self.points.iter().position(|p| p.frame_ts > ts).unwrap_or(self.points.len()); self.points.insert(i, seek_point); } } /// Search the index to find a bounded range of bytes wherein the specified frame timestamp /// will be contained. If the index is empty, this function simply returns a result /// indicating the entire stream should be searched manually. pub fn search(&self, frame_ts: u64) -> SeekSearchResult { // The index must contain atleast one SeekPoint to return a useful result. if !self.points.is_empty() { let mut lower = 0; let mut upper = self.points.len() - 1; // If the desired timestamp is less than the first SeekPoint within the index, // indicate that the stream should be searched from the beginning. if frame_ts < self.points[lower].frame_ts { return SeekSearchResult::Upper(self.points[lower]); } // If the desired timestamp is greater than or equal to the last SeekPoint within // the index, indicate that the stream should be searched from the last SeekPoint. else if frame_ts >= self.points[upper].frame_ts { return SeekSearchResult::Lower(self.points[upper]); } // Desired timestamp is between the lower and upper indicies. Perform a binary // search to find a range of SeekPoints containing the desired timestamp. The binary // search exits when either two adjacent SeekPoints or a single SeekPoint is found. while upper - lower > 1 { let mid = (lower + upper) / 2; let mid_ts = self.points[mid].frame_ts; if frame_ts < mid_ts { upper = mid; } else { lower = mid; } } return SeekSearchResult::Range(self.points[lower], self.points[upper]); } // The index is empty, the stream must be searched manually. SeekSearchResult::Stream } } /// Given a `Packet`, the encoder delay in frames, and the number of non-delay or padding /// frames, adjust the packet's timestamp and duration, and populate the trim information. pub fn trim_packet(packet: &mut Packet, delay: u32, num_frames: Option) { packet.trim_start = if packet.ts < u64::from(delay) { let trim = (u64::from(delay) - packet.ts).min(packet.dur); packet.ts = 0; packet.dur -= trim; trim as u32 } else { packet.ts -= u64::from(delay); 0 }; if let Some(num_frames) = num_frames { packet.trim_end = if packet.ts + packet.dur > num_frames { let trim = (packet.ts + packet.dur - num_frames).min(packet.dur); packet.dur -= trim; trim as u32 } else { 0 }; } } #[cfg(test)] mod tests { use super::{SeekIndex, SeekPoint, SeekSearchResult}; #[test] fn verify_seek_index_search() { let mut index = SeekIndex::new(); index.insert(50, 0, 45); index.insert(120, 0, 4); index.insert(320, 0, 100); index.insert(421, 0, 10); index.insert(500, 0, 12); index.insert(600, 0, 12); assert_eq!(index.search(25), SeekSearchResult::Upper(SeekPoint::new(50, 0, 45))); assert_eq!(index.search(700), SeekSearchResult::Lower(SeekPoint::new(600, 0, 12))); assert_eq!( index.search(110), SeekSearchResult::Range(SeekPoint::new(50, 0, 45), SeekPoint::new(120, 0, 4)) ); assert_eq!( index.search(340), SeekSearchResult::Range(SeekPoint::new(320, 0, 100), SeekPoint::new(421, 0, 10)) ); assert_eq!( index.search(320), SeekSearchResult::Range(SeekPoint::new(320, 0, 100), SeekPoint::new(421, 0, 10)) ); } } } symphonia-core-0.5.4/src/io/bit.rs000064400000000000000000002154211046102023000151160ustar 00000000000000// Symphonia // Copyright (c) 2019-2022 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/. use std::cmp::min; use std::io; use crate::io::ReadBytes; use crate::util::bits::*; fn end_of_bitstream_error() -> io::Result { Err(io::Error::new(io::ErrorKind::Other, "unexpected end of bitstream")) } pub mod vlc { //! The `vlc` module provides support for decoding variable-length codes (VLC). use std::cmp::max; use std::collections::{BTreeMap, VecDeque}; use std::io; fn codebook_error(desc: &'static str) -> io::Result { Err(io::Error::new(io::ErrorKind::Other, desc)) } /// `BitOrder` describes the relationship between the order of bits in the provided codewords /// and the order in which bits are read. #[derive(Copy, Clone)] pub enum BitOrder { /// The provided codewords have bits in the same order as the order in which they're being /// read. Verbatim, /// The provided codeword have bits in the reverse order as the order in which they're /// being read. Reverse, } /// `CodebookEntry` provides the functions required for an entry in the `Codebook`. pub trait CodebookEntry: Copy + Clone + Default { /// The type of a value in this entry. type ValueType: Copy + From; /// The type of a jump offset in this entry. type OffsetType: Copy; /// The maximum jump offset. const JUMP_OFFSET_MAX: u32; /// Creates a new value entry. fn new_value(value: Self::ValueType, len: u8) -> Self; /// Create a new jump entry. fn new_jump(offset: u32, len: u8) -> Self; /// Returns `true` if this entry is a value entry. fn is_value(&self) -> bool; /// Returns `true` if this entry is a jump entry. fn is_jump(&self) -> bool; /// Gets the value. fn value(&self) -> Self::ValueType; /// Get the length of the value in bits. fn value_len(&self) -> u32; /// Get the position in the table to jump to. fn jump_offset(&self) -> usize; /// Get the number of bits to read after jumping in the table. fn jump_len(&self) -> u32; } macro_rules! decl_entry { ( #[doc = $expr:expr] $name:ident, $value_type:ty, $offset_type:ty, $offset_max:expr, $jump_flag:expr ) => { #[doc = $expr] #[derive(Copy, Clone, Default)] pub struct $name($value_type, $offset_type); impl CodebookEntry for $name { type ValueType = $value_type; type OffsetType = $offset_type; const JUMP_OFFSET_MAX: u32 = $offset_max; #[inline(always)] fn new_value(value: Self::ValueType, len: u8) -> Self { $name(value, len.into()) } #[inline(always)] fn new_jump(offset: u32, len: u8) -> Self { $name(len.into(), $jump_flag | offset as Self::OffsetType) } #[inline(always)] fn is_jump(&self) -> bool { self.1 & $jump_flag != 0 } #[inline(always)] fn is_value(&self) -> bool { self.1 & $jump_flag == 0 } #[inline(always)] fn value(&self) -> Self::ValueType { debug_assert!(self.is_value()); self.0 } #[inline(always)] fn value_len(&self) -> u32 { debug_assert!(self.is_value()); (self.1 & (!$jump_flag)).into() } #[inline(always)] fn jump_offset(&self) -> usize { debug_assert!(self.is_jump()); (self.1 & (!$jump_flag)) as usize } #[inline(always)] fn jump_len(&self) -> u32 { debug_assert!(self.is_jump()); self.0.into() } } }; } decl_entry!( /// `Entry8x8` is a codebook entry for 8-bit values with codes up-to 8-bits. Entry8x8, u8, u8, 0x7f, 0x80 ); decl_entry!( /// `Entry8x16` is a codebook entry for 8-bit values with codes up-to 16-bits. Entry8x16, u8, u16, 0x7fff, 0x8000 ); decl_entry!( /// `Entry8x32` is a codebook entry for 8-bit values with codes up-to 32-bits. Entry8x32, u8, u32, 0x7fff_ffff, 0x8000_0000 ); decl_entry!( /// `Entry16x8` is a codebook entry for 16-bit values with codes up-to 8-bits. Entry16x8, u16, u8, 0x7f, 0x80 ); decl_entry!( /// `Entry16x16` is a codebook entry for 16-bit values with codes up-to 16-bits. Entry16x16, u16, u16, 0x7fff, 0x8000 ); decl_entry!( /// `Entry16x32` is a codebook entry for 16-bit values with codes up-to 32-bits. Entry16x32, u16, u32, 0x7fff_ffff, 0x8000_0000 ); decl_entry!( /// `Entry32x8` is a codebook entry for 32-bit values with codes up-to 8-bits. Entry32x8, u32, u8, 0x7fff, 0x80 ); decl_entry!( /// `Entry32x16` is a codebook entry for 32-bit values with codes up-to 16-bits. Entry32x16, u32, u16, 0x7fff, 0x8000 ); decl_entry!( /// `Entry32x32` is a codebook entry for 32-bit values with codes up-to 32-bits. Entry32x32, u32, u32, 0x7fff_ffff, 0x8000_0000 ); /// `Codebook` is a variable-length code decoding table that may be used to efficiently read /// symbols from a source of bits. #[derive(Default)] pub struct Codebook { pub table: Vec, pub max_code_len: u32, pub init_block_len: u32, } impl Codebook { /// Returns `true` if the `Codebook` is empty. pub fn is_empty(&self) -> bool { self.table.is_empty() } } #[derive(Default)] struct CodebookValue { prefix: u16, width: u8, value: E::ValueType, } impl CodebookValue { fn new(prefix: u16, width: u8, value: E::ValueType) -> Self { CodebookValue { prefix, width, value } } } #[derive(Default)] struct CodebookBlock { width: u8, nodes: BTreeMap, values: Vec>, } /// `CodebookBuilder` generates a `Codebook` using a provided codebook specification and /// description. pub struct CodebookBuilder { max_bits_per_block: u8, bit_order: BitOrder, is_sparse: bool, } impl CodebookBuilder { /// Instantiates a new `CodebookBuilder`. /// /// The `bit_order` parameter specifies if the codeword bits should be reversed when /// constructing the codebook. If the `BitReader` or `BitStream` reading the constructed /// codebook reads bits in an order different from the order of the provided codewords, /// then this option can be used to make them compatible. pub fn new(bit_order: BitOrder) -> Self { CodebookBuilder { max_bits_per_block: 4, bit_order, is_sparse: false } } /// Instantiates a new `CodebookBuilder` for sparse codebooks. /// /// A sparse codebook is one in which not all codewords are valid. These invalid codewords /// are effectively "unused" and have no value. Therefore, it is illegal for a bitstream to /// contain the codeword bit pattern. /// /// Unused codewords are marked by having a length of 0. pub fn new_sparse(bit_order: BitOrder) -> Self { CodebookBuilder { max_bits_per_block: 4, bit_order, is_sparse: true } } /// Specify the maximum number of bits that should be consumed from the source at a time. /// This value must be within the range 1 <= `max_bits_per_read` <= 16. Values outside of /// this range will cause this function to panic. If not provided, a value will be /// automatically chosen. pub fn bits_per_read(&mut self, max_bits_per_read: u8) -> &mut Self { assert!(max_bits_per_read <= 16); assert!(max_bits_per_read > 0); self.max_bits_per_block = max_bits_per_read; self } fn generate_lut( bit_order: BitOrder, is_sparse: bool, blocks: &[CodebookBlock], ) -> io::Result> { // The codebook table. let mut table = Vec::new(); let mut queue = VecDeque::new(); // The computed end of the table given the blocks in the queue. let mut table_end = 0u32; if !blocks.is_empty() { // Start traversal at the first block. queue.push_front(0); // The first entry in the table is always a jump to the first block. let block = &blocks[0]; table.push(CodebookEntry::new_jump(1, block.width)); table_end += 1 + (1 << block.width); } // Traverse the tree in breadth-first order. while !queue.is_empty() { // Count of the total number of entries added to the table by this block. let mut entry_count = 0; // Get the block id at the front of the queue. let block_id = queue.pop_front().unwrap(); // Get the block at the front of the queue. let block = &blocks[block_id]; let block_len = 1 << block.width; // The starting index of the current block. let table_base = table.len(); // Resize the table to accomodate all entries within the block. table.resize(table_base + block_len, Default::default()); // Push child blocks onto the queue and record the jump entries in the table. Jumps // will be in order of increasing prefix because of the implicit sorting provided // by BTreeMap, thus traversing a level of the tree left-to-right. for (&child_block_prefix, &child_block_id) in block.nodes.iter() { queue.push_back(child_block_id); // The width of the child block in bits. let child_block_width = blocks[child_block_id].width; // Verify the jump offset does not exceed the entry's jump maximum. if table_end > E::JUMP_OFFSET_MAX { return codebook_error("core (io): codebook overflow"); } // Determine the offset into the table depending on the bit-order. let offset = match bit_order { BitOrder::Verbatim => child_block_prefix, BitOrder::Reverse => { child_block_prefix.reverse_bits().rotate_left(u32::from(block.width)) } } as usize; // Add a jump entry to table. let jump_entry = CodebookEntry::new_jump(table_end, child_block_width); table[table_base + offset] = jump_entry; // Add the length of the child block to the end of the table. table_end += 1 << child_block_width; // Update the entry count. entry_count += 1; } // Add value entries into the table. If a value has a prefix width less than the // block width, then do-not-care bits must added to the end of the prefix to pad it // to the block width. for value in block.values.iter() { // The number of do-not-care bits to add to the value's prefix. let num_dnc_bits = block.width - value.width; // Extend the value's prefix to the block's width. let base_prefix = (value.prefix << num_dnc_bits) as usize; // Using the base prefix, synthesize all prefixes for this value. let count = 1 << num_dnc_bits; // The value entry that will be duplicated. let value_entry = CodebookEntry::new_value(value.value, value.width); match bit_order { BitOrder::Verbatim => { // For verbatim bit order, the do-not-care bits are in the LSb // position. let start = table_base + base_prefix; let end = start + count; for entry in table[start..end].iter_mut() { *entry = value_entry; } } BitOrder::Reverse => { // For reverse bit order, the do-not-care bits are in the MSb position. let start = base_prefix; let end = start + count; for prefix in start..end { let offset = prefix.reverse_bits().rotate_left(u32::from(block.width)); table[table_base + offset] = value_entry; } } } // Update the entry count. entry_count += count; } // If the decoding tree is not sparse, the number of entries added to the table // should equal the block length if the. It is a fatal error if this is not true. if !is_sparse && entry_count != block_len { return codebook_error("core (io): codebook is incomplete"); } } Ok(table) } /// Construct a `Codebook` using the given codewords, their respective lengths, and values. /// /// This function may fail if the provided codewords do not form a complete VLC tree, or if /// the `CodebookEntry` is undersized. /// /// This function will panic if the number of code words, code lengths, and values differ. pub fn make( &mut self, code_words: &[u32], code_lens: &[u8], values: &[E::ValueType], ) -> io::Result> { assert!(code_words.len() == code_lens.len()); assert!(code_words.len() == values.len()); let mut blocks = Vec::>::new(); let mut max_code_len = 0; // Only attempt to generate something if there are code words. if !code_words.is_empty() { let prefix_mask = !(!0 << self.max_bits_per_block); // Push a root block. blocks.push(Default::default()); // Populate the tree for ((&code, &code_len), &value) in code_words.iter().zip(code_lens).zip(values) { let mut parent_block_id = 0; let mut len = code_len; // A zero length codeword in a spare codebook is allowed, but not in a regular // codebook. if code_len == 0 { if self.is_sparse { continue; } else { return codebook_error("core (io): zero length codeword"); } } while len > self.max_bits_per_block { len -= self.max_bits_per_block; let prefix = ((code >> len) & prefix_mask) as u16; // Recurse down the tree. if let Some(&block_id) = blocks[parent_block_id].nodes.get(&prefix) { parent_block_id = block_id; } else { // Add a child block to the parent block. let block_id = blocks.len(); let block = &mut blocks[parent_block_id]; block.nodes.insert(prefix, block_id); // The parent's block width must accomodate the prefix of the child. // This is always max_bits_per_block bits. block.width = self.max_bits_per_block; // Append the new block. blocks.push(Default::default()); parent_block_id = block_id; } } // The final chunk of code bits always has <= max_bits_per_block bits. Obtain // the final prefix. let prefix = code & (prefix_mask >> (self.max_bits_per_block - len)); let block = &mut blocks[parent_block_id]; // Push the value. block.values.push(CodebookValue::new(prefix as u16, len, value)); // Update the block's width. block.width = max(block.width, len); // Update maximum observed codeword. max_code_len = max(max_code_len, code_len); } } // Generate the codebook lookup table. let table = CodebookBuilder::generate_lut(self.bit_order, self.is_sparse, &blocks)?; // Determine the first block length if skipping the initial jump entry. let init_block_len = table.first().map(|block| block.jump_len()).unwrap_or(0); Ok(Codebook { table, max_code_len: u32::from(max_code_len), init_block_len }) } } } mod private { use std::io; pub trait FetchBitsLtr { /// Discard any remaining bits in the source and fetch new bits. fn fetch_bits(&mut self) -> io::Result<()>; /// Fetch new bits, and append them after the remaining bits. fn fetch_bits_partial(&mut self) -> io::Result<()>; /// Get all the bits in the source. fn get_bits(&self) -> u64; /// Get the number of bits left in the source. fn num_bits_left(&self) -> u32; /// Consume `num` bits from the source. fn consume_bits(&mut self, num: u32); } pub trait FetchBitsRtl { /// Discard any remaining bits in the source and fetch new bits. fn fetch_bits(&mut self) -> io::Result<()>; /// Fetch new bits, and append them after the remaining bits. fn fetch_bits_partial(&mut self) -> io::Result<()>; /// Get all the bits in the source. fn get_bits(&self) -> u64; /// Get the number of bits left in the source. fn num_bits_left(&self) -> u32; /// Consume `num` bits from the source. fn consume_bits(&mut self, num: u32); } } /// A `FiniteBitStream` is a bit stream that has a known length in bits. pub trait FiniteBitStream { /// Gets the number of bits left unread. fn bits_left(&self) -> u64; } /// `ReadBitsLtr` reads bits from most-significant to least-significant. pub trait ReadBitsLtr: private::FetchBitsLtr { /// Discards any saved bits and resets the `BitStream` to prepare it for a byte-aligned read. #[inline(always)] fn realign(&mut self) { let skip = self.num_bits_left() & 0x7; self.consume_bits(skip); } /// Ignores the specified number of bits from the stream or returns an error. #[inline(always)] fn ignore_bits(&mut self, mut num_bits: u32) -> io::Result<()> { if num_bits <= self.num_bits_left() { self.consume_bits(num_bits); } else { // Consume whole bit caches directly. while num_bits > self.num_bits_left() { num_bits -= self.num_bits_left(); self.fetch_bits()?; } if num_bits > 0 { // Shift out in two parts to prevent panicing when num_bits == 64. self.consume_bits(num_bits - 1); self.consume_bits(1); } } Ok(()) } /// Ignores one bit from the stream or returns an error. #[inline(always)] fn ignore_bit(&mut self) -> io::Result<()> { self.ignore_bits(1) } /// Read a single bit as a boolean value or returns an error. #[inline(always)] fn read_bool(&mut self) -> io::Result { if self.num_bits_left() < 1 { self.fetch_bits()?; } let bit = self.get_bits() & (1 << 63) != 0; self.consume_bits(1); Ok(bit) } /// Reads and returns a single bit or returns an error. #[inline(always)] fn read_bit(&mut self) -> io::Result { if self.num_bits_left() < 1 { self.fetch_bits()?; } let bit = self.get_bits() >> 63; self.consume_bits(1); Ok(bit as u32) } /// Reads and returns up to 32-bits or returns an error. #[inline(always)] fn read_bits_leq32(&mut self, mut bit_width: u32) -> io::Result { debug_assert!(bit_width <= u32::BITS); // Shift in two 32-bit operations instead of a single 64-bit operation to avoid panicing // when bit_width == 0 (and thus shifting right 64-bits). This is preferred to branching // the bit_width == 0 case, since reading up-to 32-bits at a time is a hot code-path. let mut bits = (self.get_bits() >> u32::BITS) >> (u32::BITS - bit_width); while bit_width > self.num_bits_left() { bit_width -= self.num_bits_left(); self.fetch_bits()?; // Unlike the first shift, bit_width is always > 0 here so this operation will never // shift by > 63 bits. bits |= self.get_bits() >> (u64::BITS - bit_width); } self.consume_bits(bit_width); Ok(bits as u32) } /// Reads up to 32-bits and interprets them as a signed two's complement integer or returns an /// error. #[inline(always)] fn read_bits_leq32_signed(&mut self, bit_width: u32) -> io::Result { let value = self.read_bits_leq32(bit_width)?; Ok(sign_extend_leq32_to_i32(value, bit_width)) } /// Reads and returns up to 64-bits or returns an error. #[inline(always)] fn read_bits_leq64(&mut self, mut bit_width: u32) -> io::Result { debug_assert!(bit_width <= u64::BITS); // Hard-code the bit_width == 0 case as it's not possible to handle both the bit_width == 0 // and bit_width == 64 cases branchlessly. This should be optimized out when bit_width is // known at compile time. Since it's generally rare to need to read up-to 64-bits at a time // (as oppopsed to 32-bits), this is an acceptable solution. if bit_width == 0 { Ok(0) } else { // Since bit_width is always > 0, this shift operation is always < 64, and will // therefore never panic. let mut bits = self.get_bits() >> (u64::BITS - bit_width); while bit_width > self.num_bits_left() { bit_width -= self.num_bits_left(); self.fetch_bits()?; bits |= self.get_bits() >> (u64::BITS - bit_width); } // Shift in two parts to prevent panicing when bit_width == 64. self.consume_bits(bit_width - 1); self.consume_bits(1); Ok(bits) } } /// Reads up to 64-bits and interprets them as a signed two's complement integer or returns an /// error. #[inline(always)] fn read_bits_leq64_signed(&mut self, bit_width: u32) -> io::Result { let value = self.read_bits_leq64(bit_width)?; Ok(sign_extend_leq64_to_i64(value, bit_width)) } /// Reads and returns a unary zeros encoded integer or an error. #[inline(always)] fn read_unary_zeros(&mut self) -> io::Result { let mut num = 0; loop { // Get the number of leading zeros. let num_zeros = self.get_bits().leading_zeros(); if num_zeros >= self.num_bits_left() { // If the number of zeros exceeds the number of bits left then all the remaining // bits were 0. num += self.num_bits_left(); self.fetch_bits()?; } else { // Otherwise, a 1 bit was encountered after `n_zeros` 0 bits. num += num_zeros; // Since bits are shifted off the cache after they're consumed, for there to be a // 1 bit there must be atleast one extra available bit in the cache that can be // consumed after the 0 bits. self.consume_bits(num_zeros); self.consume_bits(1); // Done decoding. break; } } Ok(num) } /// Reads and returns a unary zeros encoded integer that is capped to a maximum value. #[inline(always)] fn read_unary_zeros_capped(&mut self, mut limit: u32) -> io::Result { let mut num = 0; loop { // Get the number of leading zeros, capped to the limit. let num_bits_left = self.num_bits_left(); let num_zeros = min(self.get_bits().leading_zeros(), num_bits_left); if num_zeros >= limit { // There are more ones than the limit. A terminator cannot be encountered. num += limit; self.consume_bits(limit); break; } else { // There are less ones than the limit. A terminator was encountered OR more bits // are needed. limit -= num_zeros; num += num_zeros; if num_zeros < num_bits_left { // There are less ones than the number of bits left in the reader. Thus, a // terminator was not encountered and not all bits have not been consumed. self.consume_bits(num_zeros); self.consume_bits(1); break; } } self.fetch_bits()?; } Ok(num) } /// Reads and returns a unary ones encoded integer or an error. #[inline(always)] fn read_unary_ones(&mut self) -> io::Result { // Note: This algorithm is identical to read_unary_zeros except flipped for 1s. let mut num = 0; loop { let num_ones = self.get_bits().leading_ones(); if num_ones >= self.num_bits_left() { num += self.num_bits_left(); self.fetch_bits()?; } else { num += num_ones; self.consume_bits(num_ones); self.consume_bits(1); break; } } Ok(num) } /// Reads and returns a unary ones encoded integer that is capped to a maximum value. #[inline(always)] fn read_unary_ones_capped(&mut self, mut limit: u32) -> io::Result { // Note: This algorithm is identical to read_unary_zeros_capped except flipped for 1s. let mut num = 0; loop { let num_bits_left = self.num_bits_left(); let num_ones = min(self.get_bits().leading_ones(), num_bits_left); if num_ones >= limit { num += limit; self.consume_bits(limit); break; } else { limit -= num_ones; num += num_ones; if num_ones < num_bits_left { self.consume_bits(num_ones); self.consume_bits(1); break; } } self.fetch_bits()?; } Ok(num) } /// Reads a codebook value from the `BitStream` using the provided `Codebook` and returns the /// decoded value or an error. #[inline(always)] fn read_codebook( &mut self, codebook: &vlc::Codebook, ) -> io::Result<(E::ValueType, u32)> { // Attempt refill the bit buffer with enough bits for the longest codeword in the codebook. // However, this does not mean the bit buffer will have enough bits to decode a codeword. if self.num_bits_left() < codebook.max_code_len { self.fetch_bits_partial()?; } // The number of bits actually buffered in the bit buffer. let num_bits_left = self.num_bits_left(); let mut bits = self.get_bits(); let mut block_len = codebook.init_block_len; let mut entry = codebook.table[(bits >> (u64::BITS - block_len)) as usize + 1]; let mut consumed = 0; while entry.is_jump() { // Consume the bits used for the initial or previous jump iteration. consumed += block_len; bits <<= block_len; // Since this is a jump entry, if there are no bits left then the bitstream ended early. if consumed > num_bits_left { return end_of_bitstream_error(); } // Prepare for the next jump. block_len = entry.jump_len(); let index = bits >> (u64::BITS - block_len); // Jump to the next entry. entry = codebook.table[entry.jump_offset() + index as usize]; } // The entry is always a value entry at this point. Consume the bits containing the value. consumed += entry.value_len(); if consumed > num_bits_left { return end_of_bitstream_error(); } self.consume_bits(consumed); Ok((entry.value(), consumed)) } } /// `BitStreamLtr` reads bits from most-significant to least-significant from any source /// that implements [`ReadBytes`]. /// /// Stated another way, if N-bits are read from a `BitReaderLtr` then bit 0, the first bit read, /// is the most-significant bit, and bit N-1, the last bit read, is the least-significant. pub struct BitStreamLtr<'a, B: ReadBytes> { reader: &'a mut B, bits: u64, n_bits_left: u32, } impl<'a, B: ReadBytes> BitStreamLtr<'a, B> { /// Instantiate a new `BitStreamLtr` with the given source. pub fn new(reader: &'a mut B) -> Self { BitStreamLtr { reader, bits: 0, n_bits_left: 0 } } } impl<'a, B: ReadBytes> private::FetchBitsLtr for BitStreamLtr<'a, B> { #[inline(always)] fn fetch_bits(&mut self) -> io::Result<()> { self.bits = u64::from(self.reader.read_u8()?) << 56; self.n_bits_left = u8::BITS; Ok(()) } #[inline(always)] fn fetch_bits_partial(&mut self) -> io::Result<()> { todo!() } #[inline(always)] fn get_bits(&self) -> u64 { self.bits } #[inline(always)] fn num_bits_left(&self) -> u32 { self.n_bits_left } #[inline(always)] fn consume_bits(&mut self, num: u32) { self.n_bits_left -= num; self.bits <<= num; } } impl<'a, B: ReadBytes> ReadBitsLtr for BitStreamLtr<'a, B> {} /// `BitReaderLtr` reads bits from most-significant to least-significant from any `&[u8]`. /// /// Stated another way, if N-bits are read from a `BitReaderLtr` then bit 0, the first bit read, /// is the most-significant bit, and bit N-1, the last bit read, is the least-significant. pub struct BitReaderLtr<'a> { buf: &'a [u8], bits: u64, n_bits_left: u32, } impl<'a> BitReaderLtr<'a> { /// Instantiate a new `BitReaderLtr` with the given buffer. pub fn new(buf: &'a [u8]) -> Self { BitReaderLtr { buf, bits: 0, n_bits_left: 0 } } } impl<'a> private::FetchBitsLtr for BitReaderLtr<'a> { #[inline] fn fetch_bits_partial(&mut self) -> io::Result<()> { let mut buf = [0u8; std::mem::size_of::()]; let read_len = min(self.buf.len(), (u64::BITS - self.n_bits_left) as usize >> 3); buf[..read_len].copy_from_slice(&self.buf[..read_len]); self.buf = &self.buf[read_len..]; self.bits |= u64::from_be_bytes(buf) >> self.n_bits_left; self.n_bits_left += (read_len as u32) << 3; Ok(()) } fn fetch_bits(&mut self) -> io::Result<()> { let mut buf = [0u8; std::mem::size_of::()]; let read_len = min(self.buf.len(), std::mem::size_of::()); if read_len == 0 { return end_of_bitstream_error(); } buf[..read_len].copy_from_slice(&self.buf[..read_len]); self.buf = &self.buf[read_len..]; self.bits = u64::from_be_bytes(buf); self.n_bits_left = (read_len as u32) << 3; Ok(()) } #[inline(always)] fn get_bits(&self) -> u64 { self.bits } #[inline(always)] fn num_bits_left(&self) -> u32 { self.n_bits_left } #[inline(always)] fn consume_bits(&mut self, num: u32) { self.n_bits_left -= num; self.bits <<= num; } } impl<'a> ReadBitsLtr for BitReaderLtr<'a> {} impl<'a> FiniteBitStream for BitReaderLtr<'a> { fn bits_left(&self) -> u64 { (8 * self.buf.len() as u64) + u64::from(self.n_bits_left) } } /// `ReadBitsRtl` reads bits from least-significant to most-significant. pub trait ReadBitsRtl: private::FetchBitsRtl { /// Discards any saved bits and resets the `BitStream` to prepare it for a byte-aligned read. #[inline(always)] fn realign(&mut self) { let skip = self.num_bits_left() & 0x7; self.consume_bits(skip); } /// Ignores the specified number of bits from the stream or returns an error. #[inline(always)] fn ignore_bits(&mut self, mut num_bits: u32) -> io::Result<()> { if num_bits <= self.num_bits_left() { self.consume_bits(num_bits); } else { // Consume whole bit caches directly. while num_bits > self.num_bits_left() { num_bits -= self.num_bits_left(); self.fetch_bits()?; } if num_bits > 0 { // Shift out in two parts to prevent panicing when num_bits == 64. self.consume_bits(num_bits - 1); self.consume_bits(1); } } Ok(()) } /// Ignores one bit from the stream or returns an error. #[inline(always)] fn ignore_bit(&mut self) -> io::Result<()> { self.ignore_bits(1) } /// Read a single bit as a boolean value or returns an error. #[inline(always)] fn read_bool(&mut self) -> io::Result { if self.num_bits_left() < 1 { self.fetch_bits()?; } let bit = (self.get_bits() & 1) == 1; self.consume_bits(1); Ok(bit) } /// Reads and returns a single bit or returns an error. #[inline(always)] fn read_bit(&mut self) -> io::Result { if self.num_bits_left() < 1 { self.fetch_bits()?; } let bit = self.get_bits() & 1; self.consume_bits(1); Ok(bit as u32) } /// Reads and returns up to 32-bits or returns an error. #[inline(always)] fn read_bits_leq32(&mut self, bit_width: u32) -> io::Result { debug_assert!(bit_width <= u32::BITS); let mut bits = self.get_bits(); let mut bits_needed = bit_width; while bits_needed > self.num_bits_left() { bits_needed -= self.num_bits_left(); self.fetch_bits()?; bits |= self.get_bits() << (bit_width - bits_needed); } self.consume_bits(bits_needed); // Since bit_width is <= 32, this shift will never panic. let mask = !(!0 << bit_width); Ok((bits & mask) as u32) } /// Reads up to 32-bits and interprets them as a signed two's complement integer or returns an /// error. #[inline(always)] fn read_bits_leq32_signed(&mut self, bit_width: u32) -> io::Result { let value = self.read_bits_leq32(bit_width)?; Ok(sign_extend_leq32_to_i32(value, bit_width)) } /// Reads and returns up to 64-bits or returns an error. #[inline(always)] fn read_bits_leq64(&mut self, bit_width: u32) -> io::Result { debug_assert!(bit_width <= u64::BITS); // Hard-code the bit_width == 0 case as it's not possible to handle both the bit_width == 0 // and bit_width == 64 cases branchlessly. This should be optimized out when bit_width is // known at compile time. Since it's generally rare to need to read up-to 64-bits at a time // (as oppopsed to 32-bits), this is an acceptable solution. if bit_width == 0 { Ok(0) } else { let mut bits = self.get_bits(); let mut bits_needed = bit_width; while bits_needed > self.num_bits_left() { bits_needed -= self.num_bits_left(); self.fetch_bits()?; // Since bits_needed will always be > 0, this will never shift by > 63 bits if // bit_width == 64 and therefore will never panic. bits |= self.get_bits() << (bit_width - bits_needed); } // Shift in two parts to prevent panicing when bit_width == 64. self.consume_bits(bits_needed - 1); self.consume_bits(1); // Generate the mask in two parts to prevent panicing when bit_width == 64. let mask = !((!0 << (bit_width - 1)) << 1); Ok(bits & mask) } } /// Reads up to 64-bits and interprets them as a signed two's complement integer or returns an /// error. #[inline(always)] fn read_bits_leq64_signed(&mut self, bit_width: u32) -> io::Result { let value = self.read_bits_leq64(bit_width)?; Ok(sign_extend_leq64_to_i64(value, bit_width)) } /// Reads and returns a unary zeros encoded integer or an error. #[inline(always)] fn read_unary_zeros(&mut self) -> io::Result { let mut num = 0; loop { // Get the number of trailing zeros. let num_zeros = self.get_bits().trailing_zeros(); if num_zeros >= self.num_bits_left() { // If the number of zeros exceeds the number of bits left then all the remaining // bits were 0. num += self.num_bits_left(); self.fetch_bits()?; } else { // Otherwise, a 1 bit was encountered after `n_zeros` 0 bits. num += num_zeros; // Since bits are shifted off the cache after they're consumed, for there to be a // 1 bit there must be atleast one extra available bit in the cache that can be // consumed after the 0 bits. self.consume_bits(num_zeros); self.consume_bits(1); // Done decoding. break; } } Ok(num) } /// Reads and returns a unary zeros encoded integer that is capped to a maximum value. #[inline(always)] fn read_unary_zeros_capped(&mut self, mut limit: u32) -> io::Result { let mut num = 0; loop { // Get the number of trailing zeros, capped to the limit. let num_bits_left = self.num_bits_left(); let num_zeros = min(self.get_bits().trailing_zeros(), num_bits_left); if num_zeros >= limit { // There are more zeros than the limit. A terminator cannot be encountered. num += limit; self.consume_bits(limit); break; } else { // There are less zeros than the limit. A terminator was encountered OR more bits // are needed. limit -= num_zeros; num += num_zeros; if num_zeros < num_bits_left { // There are less zeros than the number of bits left in the reader. Thus, a // terminator was not encountered and not all bits have not been consumed. self.consume_bits(num_zeros); self.consume_bits(1); break; } } self.fetch_bits()?; } Ok(num) } /// Reads and returns a unary ones encoded integer or an error. #[inline(always)] fn read_unary_ones(&mut self) -> io::Result { // Note: This algorithm is identical to read_unary_zeros except flipped for 1s. let mut num = 0; loop { let num_ones = self.get_bits().trailing_ones(); if num_ones >= self.num_bits_left() { num += self.num_bits_left(); self.fetch_bits()?; } else { num += num_ones; self.consume_bits(num_ones); self.consume_bits(1); break; } } Ok(num) } /// Reads and returns a unary ones encoded integer or an error. #[inline(always)] fn read_unary_ones_capped(&mut self, mut limit: u32) -> io::Result { // Note: This algorithm is identical to read_unary_zeros_capped except flipped for 1s. let mut num = 0; loop { let num_bits_left = self.num_bits_left(); let num_ones = min(self.get_bits().trailing_ones(), num_bits_left); if num_ones >= limit { num += limit; self.consume_bits(limit); break; } else { limit -= num_ones; num += num_ones; if num_ones < num_bits_left { self.consume_bits(num_ones); self.consume_bits(1); break; } } self.fetch_bits()?; } Ok(num) } #[inline(always)] fn read_codebook( &mut self, codebook: &vlc::Codebook, ) -> io::Result<(E::ValueType, u32)> { if self.num_bits_left() < codebook.max_code_len { self.fetch_bits_partial()?; } // The number of bits actually buffered in the bit buffer. let num_bits_left = self.num_bits_left(); let mut bits = self.get_bits(); let mut block_len = codebook.init_block_len; let mut entry = codebook.table[(bits & ((1 << block_len) - 1)) as usize + 1]; let mut consumed = 0; while entry.is_jump() { // Consume the bits used for the initial or previous jump iteration. consumed += block_len; bits >>= block_len; // Since this is a jump entry, if there are no bits left then the bitstream ended early. if consumed > num_bits_left { return end_of_bitstream_error(); } // Prepare for the next jump. block_len = entry.jump_len(); let index = bits & ((1 << block_len) - 1); // Jump to the next entry. entry = codebook.table[entry.jump_offset() + index as usize]; } // The entry is always a value entry at this point. Consume the bits containing the value. consumed += entry.value_len(); if consumed > num_bits_left { return end_of_bitstream_error(); } self.consume_bits(consumed); Ok((entry.value(), consumed)) } } /// `BitStreamRtl` reads bits from least-significant to most-significant from any source /// that implements [`ReadBytes`]. /// /// Stated another way, if N-bits are read from a `BitReaderLtr` then bit 0, the first bit read, /// is the least-significant bit, and bit N-1, the last bit read, is the most-significant. pub struct BitStreamRtl<'a, B: ReadBytes> { reader: &'a mut B, bits: u64, n_bits_left: u32, } impl<'a, B: ReadBytes> BitStreamRtl<'a, B> { /// Instantiate a new `BitStreamRtl` with the given buffer. pub fn new(reader: &'a mut B) -> Self { BitStreamRtl { reader, bits: 0, n_bits_left: 0 } } } impl<'a, B: ReadBytes> private::FetchBitsRtl for BitStreamRtl<'a, B> { #[inline(always)] fn fetch_bits(&mut self) -> io::Result<()> { self.bits = u64::from(self.reader.read_u8()?); self.n_bits_left = u8::BITS; Ok(()) } #[inline(always)] fn fetch_bits_partial(&mut self) -> io::Result<()> { todo!() } #[inline(always)] fn get_bits(&self) -> u64 { self.bits } #[inline(always)] fn num_bits_left(&self) -> u32 { self.n_bits_left } #[inline(always)] fn consume_bits(&mut self, num: u32) { self.n_bits_left -= num; self.bits >>= num; } } impl<'a, B: ReadBytes> ReadBitsRtl for BitStreamRtl<'a, B> {} /// `BitReaderRtl` reads bits from least-significant to most-significant from any `&[u8]`. /// /// Stated another way, if N-bits are read from a `BitReaderRtl` then bit 0, the first bit read, /// is the least-significant bit, and bit N-1, the last bit read, is the most-significant. pub struct BitReaderRtl<'a> { buf: &'a [u8], bits: u64, n_bits_left: u32, } impl<'a> BitReaderRtl<'a> { /// Instantiate a new `BitReaderRtl` with the given buffer. pub fn new(buf: &'a [u8]) -> Self { BitReaderRtl { buf, bits: 0, n_bits_left: 0 } } } impl<'a> private::FetchBitsRtl for BitReaderRtl<'a> { #[inline] fn fetch_bits_partial(&mut self) -> io::Result<()> { let mut buf = [0u8; std::mem::size_of::()]; let read_len = min(self.buf.len(), (u64::BITS - self.n_bits_left) as usize >> 3); buf[..read_len].copy_from_slice(&self.buf[..read_len]); self.buf = &self.buf[read_len..]; self.bits |= u64::from_le_bytes(buf) << self.n_bits_left; self.n_bits_left += (read_len as u32) << 3; Ok(()) } fn fetch_bits(&mut self) -> io::Result<()> { let mut buf = [0u8; std::mem::size_of::()]; let read_len = min(self.buf.len(), std::mem::size_of::()); if read_len == 0 { return end_of_bitstream_error(); } buf[..read_len].copy_from_slice(&self.buf[..read_len]); self.buf = &self.buf[read_len..]; self.bits = u64::from_le_bytes(buf); self.n_bits_left = (read_len as u32) << 3; Ok(()) } #[inline(always)] fn get_bits(&self) -> u64 { self.bits } #[inline(always)] fn num_bits_left(&self) -> u32 { self.n_bits_left } #[inline(always)] fn consume_bits(&mut self, num: u32) { self.n_bits_left -= num; self.bits >>= num; } } impl<'a> ReadBitsRtl for BitReaderRtl<'a> {} impl<'a> FiniteBitStream for BitReaderRtl<'a> { fn bits_left(&self) -> u64 { (8 * self.buf.len() as u64) + u64::from(self.n_bits_left) } } #[cfg(test)] mod tests { use super::vlc::{BitOrder, Codebook, CodebookBuilder, Entry8x8}; use super::{BitReaderLtr, ReadBitsLtr}; use super::{BitReaderRtl, ReadBitsRtl}; #[test] #[allow(clippy::bool_assert_comparison)] fn verify_bitstreamltr_ignore_bits() { let mut bs = BitReaderLtr::new(&[ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // 0xc0, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0a, // ]); assert_eq!(bs.read_bool().unwrap(), true); bs.ignore_bits(128).unwrap(); assert_eq!(bs.read_bool().unwrap(), true); assert_eq!(bs.read_bool().unwrap(), false); assert_eq!(bs.read_bool().unwrap(), false); bs.ignore_bits(7).unwrap(); assert_eq!(bs.read_bool().unwrap(), true); bs.ignore_bits(19).unwrap(); assert_eq!(bs.read_bool().unwrap(), true); assert_eq!(bs.read_bool().unwrap(), false); assert_eq!(bs.read_bool().unwrap(), false); assert_eq!(bs.read_bool().unwrap(), false); assert_eq!(bs.read_bool().unwrap(), false); bs.ignore_bits(24).unwrap(); assert_eq!(bs.read_bool().unwrap(), true); assert_eq!(bs.read_bool().unwrap(), false); assert_eq!(bs.read_bool().unwrap(), true); assert_eq!(bs.read_bool().unwrap(), false); // Lower limit test. let mut bs = BitReaderLtr::new(&[0x00]); assert!(bs.ignore_bits(0).is_ok()); let mut bs = BitReaderLtr::new(&[]); assert!(bs.ignore_bits(0).is_ok()); assert!(bs.ignore_bits(1).is_err()); // Upper limit test. let mut bs = BitReaderLtr::new(&[ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // ]); assert!(bs.ignore_bits(64).is_ok()); assert!(bs.ignore_bits(64).is_ok()); assert!(bs.ignore_bits(32).is_ok()); assert!(bs.ignore_bits(32).is_ok()); assert!(bs.ignore_bits(64).is_ok()); } #[test] #[allow(clippy::bool_assert_comparison)] fn verify_bitstreamltr_read_bool() { // General tests. let mut bs = BitReaderLtr::new(&[0b1010_1010]); assert_eq!(bs.read_bool().unwrap(), true); assert_eq!(bs.read_bool().unwrap(), false); assert_eq!(bs.read_bool().unwrap(), true); assert_eq!(bs.read_bool().unwrap(), false); assert_eq!(bs.read_bool().unwrap(), true); assert_eq!(bs.read_bool().unwrap(), false); assert_eq!(bs.read_bool().unwrap(), true); assert_eq!(bs.read_bool().unwrap(), false); // Error test. let mut bs = BitReaderLtr::new(&[]); assert!(bs.read_bool().is_err()); } #[test] fn verify_bitstreamltr_read_bit() { // General tests. let mut bs = BitReaderLtr::new(&[0b1010_1010]); assert_eq!(bs.read_bit().unwrap(), 1); assert_eq!(bs.read_bit().unwrap(), 0); assert_eq!(bs.read_bit().unwrap(), 1); assert_eq!(bs.read_bit().unwrap(), 0); assert_eq!(bs.read_bit().unwrap(), 1); assert_eq!(bs.read_bit().unwrap(), 0); assert_eq!(bs.read_bit().unwrap(), 1); assert_eq!(bs.read_bit().unwrap(), 0); // Error test. let mut bs = BitReaderLtr::new(&[]); assert!(bs.read_bool().is_err()); } #[test] fn verify_bitstreamltr_read_bits_leq32() { // General tests. let mut bs = BitReaderLtr::new(&[0b1010_0101, 0b0111_1110, 0b1101_0011]); assert_eq!(bs.read_bits_leq32(4).unwrap(), 0b0000_0000_0000_1010); assert_eq!(bs.read_bits_leq32(4).unwrap(), 0b0000_0000_0000_0101); assert_eq!(bs.read_bits_leq32(13).unwrap(), 0b0000_1111_1101_1010); assert_eq!(bs.read_bits_leq32(3).unwrap(), 0b0000_0000_0000_0011); // Lower limit test. let mut bs = BitReaderLtr::new(&[0xff, 0xff, 0xff, 0xff]); assert_eq!(bs.read_bits_leq32(0).unwrap(), 0); // Upper limit test. let mut bs = BitReaderLtr::new(&[0xff, 0xff, 0xff, 0xff, 0x01]); assert_eq!(bs.read_bits_leq32(32).unwrap(), u32::MAX); assert_eq!(bs.read_bits_leq32(8).unwrap(), 0x01); // Cache fetch test. let mut bs = BitReaderLtr::new(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01]); assert_eq!(bs.read_bits_leq32(32).unwrap(), u32::MAX); assert_eq!(bs.read_bits_leq32(32).unwrap(), u32::MAX); assert_eq!(bs.read_bits_leq32(8).unwrap(), 0x01); // Test error cases. let mut bs = BitReaderLtr::new(&[0xff]); assert!(bs.read_bits_leq32(9).is_err()); } #[test] fn verify_bitstreamltr_read_bits_leq64() { // General tests. let mut bs = BitReaderLtr::new(&[ 0x99, 0xaa, 0x55, 0xff, 0xff, 0x55, 0xaa, 0x99, // 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, // ]); assert_eq!(bs.read_bits_leq64(40).unwrap(), 0x99aa55ffff); assert_eq!(bs.read_bits_leq64(4).unwrap(), 0x05); assert_eq!(bs.read_bits_leq64(4).unwrap(), 0x05); assert_eq!(bs.read_bits_leq64(16).unwrap(), 0xaa99); assert_eq!(bs.read_bits_leq64(64).unwrap(), 0x1122334455667788); // Lower limit test. let mut bs = BitReaderLtr::new(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]); assert_eq!(bs.read_bits_leq64(0).unwrap(), 0); // Upper limit test. let mut bs = BitReaderLtr::new(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01]); assert_eq!(bs.read_bits_leq64(64).unwrap(), u64::MAX); assert_eq!(bs.read_bits_leq64(8).unwrap(), 0x01); // Test error cases. let mut bs = BitReaderLtr::new(&[0xff]); assert!(bs.read_bits_leq64(9).is_err()); } #[test] fn verify_bitstreamltr_read_unary_zeros() { // General tests let mut bs = BitReaderLtr::new(&[0b0000_0001, 0b0001_0000, 0b0000_0000, 0b1000_0000, 0b1111_1011]); assert_eq!(bs.read_unary_zeros().unwrap(), 7); assert_eq!(bs.read_unary_zeros().unwrap(), 3); assert_eq!(bs.read_unary_zeros().unwrap(), 12); assert_eq!(bs.read_unary_zeros().unwrap(), 7); assert_eq!(bs.read_unary_zeros().unwrap(), 0); assert_eq!(bs.read_unary_zeros().unwrap(), 0); assert_eq!(bs.read_unary_zeros().unwrap(), 0); assert_eq!(bs.read_unary_zeros().unwrap(), 0); assert_eq!(bs.read_unary_zeros().unwrap(), 1); assert_eq!(bs.read_unary_zeros().unwrap(), 0); // Upper limit test let mut bs = BitReaderLtr::new(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01]); assert_eq!(bs.read_unary_zeros().unwrap(), 63); // Lower limit test let mut bs = BitReaderLtr::new(&[0x80]); assert_eq!(bs.read_unary_zeros().unwrap(), 0); // Error test. let mut bs = BitReaderLtr::new(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]); assert!(bs.read_unary_zeros().is_err()); } #[test] fn verify_bitstreamltr_read_unary_zeros_capped() { // Basic test let mut bs = BitReaderLtr::new(&[0b0000_0001, 0b0000_0001]); assert_eq!(bs.read_unary_zeros_capped(8).unwrap(), 7); assert_eq!(bs.read_unary_zeros_capped(4).unwrap(), 4); // Long limit test let mut bs = BitReaderLtr::new(&[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ]); assert_eq!(bs.read_unary_zeros_capped(96).unwrap(), 79); assert_eq!(bs.read_unary_zeros_capped(104).unwrap(), 104); } #[test] fn verify_bitstreamltr_read_unary_ones() { // General tests let mut bs = BitReaderLtr::new(&[0b1111_1110, 0b1110_1111, 0b1111_1111, 0b0111_1111, 0b0000_0100]); assert_eq!(bs.read_unary_ones().unwrap(), 7); assert_eq!(bs.read_unary_ones().unwrap(), 3); assert_eq!(bs.read_unary_ones().unwrap(), 12); assert_eq!(bs.read_unary_ones().unwrap(), 7); assert_eq!(bs.read_unary_ones().unwrap(), 0); assert_eq!(bs.read_unary_ones().unwrap(), 0); assert_eq!(bs.read_unary_ones().unwrap(), 0); assert_eq!(bs.read_unary_ones().unwrap(), 0); assert_eq!(bs.read_unary_ones().unwrap(), 1); assert_eq!(bs.read_unary_ones().unwrap(), 0); // Upper limit test let mut bs = BitReaderLtr::new(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe]); assert_eq!(bs.read_unary_ones().unwrap(), 63); // Lower limit test let mut bs = BitReaderLtr::new(&[0x7f]); assert_eq!(bs.read_unary_ones().unwrap(), 0); // Error test. let mut bs = BitReaderLtr::new(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]); assert!(bs.read_unary_ones().is_err()); } #[test] fn verify_bitstreamltr_read_unary_ones_capped() { // Basic test let mut bs = BitReaderLtr::new(&[0b1111_1110, 0b1111_1110]); assert_eq!(bs.read_unary_ones_capped(8).unwrap(), 7); assert_eq!(bs.read_unary_ones_capped(4).unwrap(), 4); let mut bs = BitReaderLtr::new(&[0b1111_1110, 0b1110_1111, 0b1111_1111, 0b0111_1111, 0b0000_0100]); assert_eq!(bs.read_unary_ones_capped(9).unwrap(), 7); assert_eq!(bs.read_unary_ones_capped(9).unwrap(), 3); assert_eq!(bs.read_unary_ones_capped(9).unwrap(), 9); // Limit assert_eq!(bs.read_unary_ones_capped(9).unwrap(), 3); assert_eq!(bs.read_unary_ones_capped(9).unwrap(), 7); assert_eq!(bs.read_unary_ones_capped(9).unwrap(), 0); assert_eq!(bs.read_unary_ones_capped(9).unwrap(), 0); assert_eq!(bs.read_unary_ones_capped(9).unwrap(), 0); assert_eq!(bs.read_unary_ones_capped(9).unwrap(), 0); assert_eq!(bs.read_unary_ones_capped(9).unwrap(), 1); // Long limit test let mut bs = BitReaderLtr::new(&[ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ]); assert_eq!(bs.read_unary_ones_capped(144).unwrap(), 143); assert_eq!(bs.read_unary_ones_capped(256).unwrap(), 256); } fn generate_codebook(bit_order: BitOrder) -> (Codebook, Vec, &'static str) { // Codewords in MSb bit-order. #[rustfmt::skip] const CODE_WORDS: [u32; 25] = [ 0b001, 0b111, 0b010, 0b1001, 0b1101, 0b0001, 0b0111, 0b1000, 0b10110, 0b10111, 0b10101, 0b10100, 0b01100, 0b000010, 0b110000, 0b000011, 0b110001, 0b000001, 0b011010, 0b000000, 0b011011, 0b1100111, 0b1100110, 0b1100101, 0b1100100, ]; const CODE_LENS: [u8; 25] = [3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7]; const VALUES: [u8; 25] = [ b'i', b' ', b'e', b't', b's', b'l', b'n', b'o', b'.', b'r', b'g', b'h', b'u', b'p', b'w', b',', b'f', b'y', b'm', b'v', b'a', b'd', b'b', b'c', b'T', ]; // Encoded data in MSb bit-order. const DATA: [u8; 57] = [ 0xc9, 0x43, 0xbf, 0x48, 0xa7, 0xca, 0xbe, 0x64, 0x30, 0xf5, 0xdf, 0x31, 0xd9, 0xb6, 0xb5, 0xbb, 0x6f, 0x9f, 0xa0, 0x15, 0xc1, 0xfa, 0x5e, 0xa2, 0xb8, 0x4a, 0xfb, 0x0f, 0xe1, 0x93, 0xe6, 0x8a, 0xe8, 0x3e, 0x77, 0xe0, 0xd9, 0x92, 0xf5, 0xf8, 0xc5, 0xfb, 0x37, 0xcc, 0x7c, 0x48, 0x8f, 0x33, 0xf0, 0x33, 0x4f, 0xb0, 0xd2, 0x9a, 0x17, 0xad, 0x80, ]; const TEXT: &str = "This silence belongs to us... and every single person out \ there, is waiting for us to fill it with something."; // Reverse the bits in the data vector if testing a reverse bit-order. let data = match bit_order { BitOrder::Verbatim => DATA.to_vec(), BitOrder::Reverse => DATA.iter().map(|&b| b.reverse_bits()).collect(), }; // Construct a codebook using the tables above. let mut builder = CodebookBuilder::new(bit_order); let codebook = builder.make::(&CODE_WORDS, &CODE_LENS, &VALUES).unwrap(); (codebook, data, TEXT) } #[test] fn verify_bitstreamltr_read_codebook() { let (codebook, buf, text) = generate_codebook(BitOrder::Verbatim); let mut bs = BitReaderLtr::new(&buf); let decoded: Vec = (0..text.len()).into_iter().map(|_| bs.read_codebook(&codebook).unwrap().0).collect(); assert_eq!(text, std::str::from_utf8(&decoded).unwrap()); } // BitStreamRtl #[test] #[allow(clippy::bool_assert_comparison)] fn verify_bitstreamrtl_ignore_bits() { let mut bs = BitReaderRtl::new(&[ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // 0x02, 0x08, 0x00, 0x80, 0x00, 0x00, 0x00, 0x50, // ]); assert_eq!(bs.read_bool().unwrap(), true); bs.ignore_bits(128).unwrap(); assert_eq!(bs.read_bool().unwrap(), true); assert_eq!(bs.read_bool().unwrap(), false); assert_eq!(bs.read_bool().unwrap(), false); bs.ignore_bits(7).unwrap(); assert_eq!(bs.read_bool().unwrap(), true); bs.ignore_bits(19).unwrap(); assert_eq!(bs.read_bool().unwrap(), true); assert_eq!(bs.read_bool().unwrap(), false); assert_eq!(bs.read_bool().unwrap(), false); assert_eq!(bs.read_bool().unwrap(), false); assert_eq!(bs.read_bool().unwrap(), false); bs.ignore_bits(24).unwrap(); assert_eq!(bs.read_bool().unwrap(), true); assert_eq!(bs.read_bool().unwrap(), false); assert_eq!(bs.read_bool().unwrap(), true); assert_eq!(bs.read_bool().unwrap(), false); // Lower limit test. let mut bs = BitReaderRtl::new(&[0x00]); assert!(bs.ignore_bits(0).is_ok()); let mut bs = BitReaderRtl::new(&[]); assert!(bs.ignore_bits(0).is_ok()); assert!(bs.ignore_bits(1).is_err()); // Upper limit test. let mut bs = BitReaderRtl::new(&[ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // ]); assert!(bs.ignore_bits(64).is_ok()); assert!(bs.ignore_bits(64).is_ok()); assert!(bs.ignore_bits(32).is_ok()); assert!(bs.ignore_bits(32).is_ok()); assert!(bs.ignore_bits(64).is_ok()); } #[test] #[allow(clippy::bool_assert_comparison)] fn verify_bitstreamrtl_read_bool() { // General tests. let mut bs = BitReaderRtl::new(&[0b1010_1010]); assert_eq!(bs.read_bool().unwrap(), false); assert_eq!(bs.read_bool().unwrap(), true); assert_eq!(bs.read_bool().unwrap(), false); assert_eq!(bs.read_bool().unwrap(), true); assert_eq!(bs.read_bool().unwrap(), false); assert_eq!(bs.read_bool().unwrap(), true); assert_eq!(bs.read_bool().unwrap(), false); assert_eq!(bs.read_bool().unwrap(), true); // Error test. let mut bs = BitReaderRtl::new(&[]); assert!(bs.read_bool().is_err()); } #[test] fn verify_bitstreamrtl_read_bit() { // General tests. let mut bs = BitReaderRtl::new(&[0b1010_1010]); assert_eq!(bs.read_bit().unwrap(), 0); assert_eq!(bs.read_bit().unwrap(), 1); assert_eq!(bs.read_bit().unwrap(), 0); assert_eq!(bs.read_bit().unwrap(), 1); assert_eq!(bs.read_bit().unwrap(), 0); assert_eq!(bs.read_bit().unwrap(), 1); assert_eq!(bs.read_bit().unwrap(), 0); assert_eq!(bs.read_bit().unwrap(), 1); // Error test. let mut bs = BitReaderRtl::new(&[]); assert!(bs.read_bit().is_err()); } #[test] fn verify_bitstreamrtl_read_bits_leq32() { // General tests. let mut bs = BitReaderRtl::new(&[0b1010_0101, 0b0111_1110, 0b1101_0011]); assert_eq!(bs.read_bits_leq32(4).unwrap(), 0b0000_0000_0000_0101); assert_eq!(bs.read_bits_leq32(4).unwrap(), 0b0000_0000_0000_1010); assert_eq!(bs.read_bits_leq32(13).unwrap(), 0b0001_0011_0111_1110); assert_eq!(bs.read_bits_leq32(3).unwrap(), 0b0000_0000_0000_0110); // Lower limit test. let mut bs = BitReaderRtl::new(&[0xff, 0xff, 0xff, 0xff]); assert_eq!(bs.read_bits_leq32(0).unwrap(), 0); // Upper limit test. let mut bs = BitReaderRtl::new(&[0xff, 0xff, 0xff, 0xff, 0x01]); assert_eq!(bs.read_bits_leq32(32).unwrap(), u32::MAX); assert_eq!(bs.read_bits_leq32(8).unwrap(), 0x01); // Cache fetch test. let mut bs = BitReaderRtl::new(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01]); assert_eq!(bs.read_bits_leq32(32).unwrap(), u32::MAX); assert_eq!(bs.read_bits_leq32(32).unwrap(), u32::MAX); assert_eq!(bs.read_bits_leq32(8).unwrap(), 0x01); // Test error cases. let mut bs = BitReaderRtl::new(&[0xff]); assert!(bs.read_bits_leq32(9).is_err()); } #[test] fn verify_bitstreamrtl_read_bits_leq64() { // General tests. let mut bs = BitReaderRtl::new(&[ 0x99, 0xaa, 0x55, 0xff, 0xff, 0x55, 0xaa, 0x99, // 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, // 0x00, 0x11, 0x22, 0x33, 0x00, 0x11, 0x22, 0x33, // 0x44, 0x55, 0x66, 0x77, ]); assert_eq!(bs.read_bits_leq64(40).unwrap(), 0xffff55aa99); assert_eq!(bs.read_bits_leq64(4).unwrap(), 0x05); assert_eq!(bs.read_bits_leq64(4).unwrap(), 0x05); assert_eq!(bs.read_bits_leq64(16).unwrap(), 0x99aa); assert_eq!(bs.read_bits_leq64(64).unwrap(), 0x8877665544332211); assert_eq!(bs.read_bits_leq64(32).unwrap(), 0x33221100); assert_eq!(bs.read_bits_leq64(64).unwrap(), 0x7766554433221100); // Lower limit test. let mut bs = BitReaderRtl::new(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]); assert_eq!(bs.read_bits_leq64(0).unwrap(), 0); // Upper limit test. let mut bs = BitReaderRtl::new(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01]); assert_eq!(bs.read_bits_leq64(64).unwrap(), u64::MAX); assert_eq!(bs.read_bits_leq64(8).unwrap(), 0x01); // Test error cases. let mut bs = BitReaderRtl::new(&[0xff]); assert!(bs.read_bits_leq64(9).is_err()); } #[test] fn verify_bitstreamrtl_read_unary_zeros() { // General tests let mut bs = BitReaderRtl::new(&[0b1000_0000, 0b0000_1000, 0b0000_0000, 0b0000_0001, 0b1101_1111]); assert_eq!(bs.read_unary_zeros().unwrap(), 7); assert_eq!(bs.read_unary_zeros().unwrap(), 3); assert_eq!(bs.read_unary_zeros().unwrap(), 12); assert_eq!(bs.read_unary_zeros().unwrap(), 7); assert_eq!(bs.read_unary_zeros().unwrap(), 0); assert_eq!(bs.read_unary_zeros().unwrap(), 0); assert_eq!(bs.read_unary_zeros().unwrap(), 0); assert_eq!(bs.read_unary_zeros().unwrap(), 0); assert_eq!(bs.read_unary_zeros().unwrap(), 1); assert_eq!(bs.read_unary_zeros().unwrap(), 0); // Upper limit test let mut bs = BitReaderRtl::new(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80]); assert_eq!(bs.read_unary_zeros().unwrap(), 63); // Lower limit test let mut bs = BitReaderRtl::new(&[0x01]); assert_eq!(bs.read_unary_zeros().unwrap(), 0); // Error test. let mut bs = BitReaderRtl::new(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]); assert!(bs.read_unary_zeros().is_err()); } #[test] fn verify_bitstreamrtl_read_unary_zeros_capped() { // General tests let mut bs = BitReaderRtl::new(&[0b1000_0000, 0b1000_0000]); assert_eq!(bs.read_unary_zeros_capped(8).unwrap(), 7); assert_eq!(bs.read_unary_zeros_capped(4).unwrap(), 4); // Long limit tests let mut bs = BitReaderRtl::new(&[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ]); assert_eq!(bs.read_unary_zeros_capped(96).unwrap(), 79); assert_eq!(bs.read_unary_zeros_capped(163).unwrap(), 163); } #[test] fn verify_bitstreamrtl_read_unary_ones() { // General tests let mut bs = BitReaderRtl::new(&[0b0111_1111, 0b1111_0111, 0b1111_1111, 0b1111_1110, 0b0010_0000]); assert_eq!(bs.read_unary_ones().unwrap(), 7); assert_eq!(bs.read_unary_ones().unwrap(), 3); assert_eq!(bs.read_unary_ones().unwrap(), 12); assert_eq!(bs.read_unary_ones().unwrap(), 7); assert_eq!(bs.read_unary_ones().unwrap(), 0); assert_eq!(bs.read_unary_ones().unwrap(), 0); assert_eq!(bs.read_unary_ones().unwrap(), 0); assert_eq!(bs.read_unary_ones().unwrap(), 0); assert_eq!(bs.read_unary_ones().unwrap(), 1); assert_eq!(bs.read_unary_ones().unwrap(), 0); // Upper limit test let mut bs = BitReaderRtl::new(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f]); assert_eq!(bs.read_unary_ones().unwrap(), 63); // Lower limit test let mut bs = BitReaderRtl::new(&[0xfe]); assert_eq!(bs.read_unary_ones().unwrap(), 0); // Error test. let mut bs = BitReaderRtl::new(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]); assert!(bs.read_unary_ones().is_err()); } #[test] fn verify_bitstreamrtl_read_unary_ones_capped() { // General tests let mut bs = BitReaderRtl::new(&[0b0111_1111, 0b0111_1111]); assert_eq!(bs.read_unary_ones_capped(8).unwrap(), 7); assert_eq!(bs.read_unary_ones_capped(4).unwrap(), 4); // Long limit tests let mut bs = BitReaderRtl::new(&[ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // ]); assert_eq!(bs.read_unary_ones_capped(96).unwrap(), 79); assert_eq!(bs.read_unary_ones_capped(163).unwrap(), 163); } #[test] fn verify_bitstreamrtl_read_codebook() { // The codewords are in MSb bit-order, but reading the bitstream in LSb order. Therefore, // use the reverse bit order. let (codebook, buf, text) = generate_codebook(BitOrder::Reverse); let mut bs = BitReaderRtl::new(&buf); let decoded: Vec = (0..text.len()).into_iter().map(|_| bs.read_codebook(&codebook).unwrap().0).collect(); assert_eq!(text, std::str::from_utf8(&decoded).unwrap()); } } symphonia-core-0.5.4/src/io/buf_reader.rs000064400000000000000000000137511046102023000164400ustar 00000000000000// Symphonia // Copyright (c) 2019-2022 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/. use std::cmp; use std::io; use super::{FiniteStream, ReadBytes}; #[inline(always)] fn underrun_error() -> io::Result { Err(io::Error::new(io::ErrorKind::UnexpectedEof, "buffer underrun")) } /// A `BufReader` reads bytes from a byte buffer. pub struct BufReader<'a> { buf: &'a [u8], pos: usize, } impl<'a> BufReader<'a> { /// Instantiate a new `BufReader` with a given byte buffer. pub fn new(buf: &'a [u8]) -> Self { BufReader { buf, pos: 0 } } /// Scans up-to `scan_len` bytes from the stream until a byte pattern is matched. A reference to /// scanned bytes including the matched pattern are returned. If `scan_len` bytes are scanned /// without matching the pattern, a reference to the scanned bytes are also returned. Likewise, /// if the underlying buffer is exhausted before matching the pattern, remainder of the buffer /// is returned. #[inline(always)] pub fn scan_bytes_ref(&mut self, pattern: &[u8], scan_len: usize) -> io::Result<&'a [u8]> { self.scan_bytes_aligned_ref(pattern, 1, scan_len) } /// Scans up-to `scan_len` bytes from the stream until a byte pattern is matched on the /// specified byte alignment boundary. Operation is otherwise identical to `scan_bytes_ref`. pub fn scan_bytes_aligned_ref( &mut self, pattern: &[u8], align: usize, scan_len: usize, ) -> io::Result<&'a [u8]> { // The pattern must be atleast one byte. debug_assert!(!pattern.is_empty()); let start = self.pos; let remaining = self.buf.len() - start; let end = start + cmp::min(remaining, scan_len); // If the pattern is longer than amount of bytes remaining, or the scan length is shorter // than the pattern, then the pattern will never match. However, since unmatched patterns // return the remainder of the buffer or scan_length bytes, which ever is shorter, we return // that here. if remaining < pattern.len() || scan_len < pattern.len() { return Ok(&self.buf[start..end]); } let mut j = start; let mut i = start + pattern.len(); while i < end { if &self.buf[j..i] == pattern { break; } i += align; j += align; } self.pos = cmp::min(i, self.buf.len()); Ok(&self.buf[start..self.pos]) } /// Returns a reference to the next `len` bytes in the buffer and advances the stream. pub fn read_buf_bytes_ref(&mut self, len: usize) -> io::Result<&'a [u8]> { if self.pos + len > self.buf.len() { return underrun_error(); } self.pos += len; Ok(&self.buf[self.pos - len..self.pos]) } /// Returns a reference to the remaining bytes in the buffer and advances the stream to the end. pub fn read_buf_bytes_available_ref(&mut self) -> &'a [u8] { let pos = self.pos; self.pos = self.buf.len(); &self.buf[pos..] } } impl<'a> ReadBytes for BufReader<'a> { #[inline(always)] fn read_byte(&mut self) -> io::Result { if self.buf.len() - self.pos < 1 { return underrun_error(); } self.pos += 1; Ok(self.buf[self.pos - 1]) } #[inline(always)] fn read_double_bytes(&mut self) -> io::Result<[u8; 2]> { if self.buf.len() - self.pos < 2 { return underrun_error(); } let mut bytes: [u8; 2] = [0u8; 2]; bytes.copy_from_slice(&self.buf[self.pos..self.pos + 2]); self.pos += 2; Ok(bytes) } #[inline(always)] fn read_triple_bytes(&mut self) -> io::Result<[u8; 3]> { if self.buf.len() - self.pos < 3 { return underrun_error(); } let mut bytes: [u8; 3] = [0u8; 3]; bytes.copy_from_slice(&self.buf[self.pos..self.pos + 3]); self.pos += 3; Ok(bytes) } #[inline(always)] fn read_quad_bytes(&mut self) -> io::Result<[u8; 4]> { if self.buf.len() - self.pos < 4 { return underrun_error(); } let mut bytes: [u8; 4] = [0u8; 4]; bytes.copy_from_slice(&self.buf[self.pos..self.pos + 4]); self.pos += 4; Ok(bytes) } fn read_buf(&mut self, buf: &mut [u8]) -> io::Result { let len = cmp::min(self.buf.len() - self.pos, buf.len()); buf[..len].copy_from_slice(&self.buf[self.pos..self.pos + len]); self.pos += len; Ok(len) } fn read_buf_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { let len = buf.len(); if self.buf.len() - self.pos < len { return underrun_error(); } buf.copy_from_slice(&self.buf[self.pos..self.pos + len]); self.pos += len; Ok(()) } fn scan_bytes_aligned<'b>( &mut self, pattern: &[u8], align: usize, buf: &'b mut [u8], ) -> io::Result<&'b mut [u8]> { let scanned = self.scan_bytes_aligned_ref(pattern, align, buf.len())?; buf[..scanned.len()].copy_from_slice(scanned); Ok(&mut buf[..scanned.len()]) } fn ignore_bytes(&mut self, count: u64) -> io::Result<()> { if self.buf.len() - self.pos < count as usize { return underrun_error(); } self.pos += count as usize; Ok(()) } #[inline(always)] fn pos(&self) -> u64 { self.pos as u64 } } impl<'a> FiniteStream for BufReader<'a> { #[inline(always)] fn byte_len(&self) -> u64 { self.buf.len() as u64 } #[inline(always)] fn bytes_read(&self) -> u64 { self.pos as u64 } #[inline(always)] fn bytes_available(&self) -> u64 { (self.buf.len() - self.pos) as u64 } } symphonia-core-0.5.4/src/io/media_source_stream.rs000064400000000000000000000500721046102023000203510ustar 00000000000000// Symphonia // Copyright (c) 2019-2022 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/. use std::cmp; use std::io; use std::io::{IoSliceMut, Read, Seek}; use std::ops::Sub; use super::SeekBuffered; use super::{MediaSource, ReadBytes}; #[inline(always)] fn end_of_stream_error() -> io::Result { Err(io::Error::new(io::ErrorKind::UnexpectedEof, "end of stream")) } /// `MediaSourceStreamOptions` specifies the buffering behaviour of a `MediaSourceStream`. pub struct MediaSourceStreamOptions { /// The maximum buffer size. Must be a power of 2. Must be > 32kB. pub buffer_len: usize, } impl Default for MediaSourceStreamOptions { fn default() -> Self { MediaSourceStreamOptions { buffer_len: 64 * 1024 } } } /// `MediaSourceStream` is the main reader type for Symphonia. /// /// By using type erasure and dynamic dispatch, `MediaSourceStream` wraps and hides the inner /// reader from the consumer, allowing any typical `Read`er to be used with Symphonia in a generic /// way, selectable at runtime. /// /// `MediaSourceStream` is designed to provide speed and flexibility in a number of challenging I/O /// scenarios. /// /// First, to minimize system call and dynamic dispatch overhead on the inner reader, and to /// amortize that overhead over many bytes, `MediaSourceStream` implements an exponentially growing /// read-ahead buffer. The read-ahead length starts at 1kB, and doubles in length as more sequential /// reads are performed until it reaches 32kB. Growing the read-ahead length over time reduces the /// excess data buffered on consecutive `seek()` calls. /// /// Second, to better support non-seekable sources, `MediaSourceStream` implements a configurable /// length buffer cache. By default, the buffer caches allows backtracking by up-to the minimum of /// either `buffer_len - 32kB` or the total number of bytes read since instantiation or the last /// buffer cache invalidation. Note that regular a `seek()` will invalidate the buffer cache. pub struct MediaSourceStream { /// The source reader. inner: Box, /// The ring buffer. ring: Box<[u8]>, /// The ring buffer's wrap-around mask. ring_mask: usize, /// The read position. read_pos: usize, /// The write position. write_pos: usize, /// The current block size for a new read. read_block_len: usize, /// Absolute position of the inner stream. abs_pos: u64, /// Relative position of the inner stream from the last seek or 0. This is a count of bytes /// read from the inner reader since instantiation or the last seek. rel_pos: u64, } impl MediaSourceStream { const MIN_BLOCK_LEN: usize = 1 * 1024; const MAX_BLOCK_LEN: usize = 32 * 1024; pub fn new(source: Box, options: MediaSourceStreamOptions) -> Self { // The buffer length must be a power of 2, and > the maximum read block length. assert!(options.buffer_len.count_ones() == 1); assert!(options.buffer_len > Self::MAX_BLOCK_LEN); MediaSourceStream { inner: source, ring: vec![0; options.buffer_len].into_boxed_slice(), ring_mask: options.buffer_len - 1, read_pos: 0, write_pos: 0, read_block_len: Self::MIN_BLOCK_LEN, abs_pos: 0, rel_pos: 0, } } /// Returns if the buffer has been exhausted This is a marginally more efficient way of checking /// if `unread_buffer_len() == 0`. #[inline(always)] fn is_buffer_exhausted(&self) -> bool { self.read_pos == self.write_pos } /// If the buffer has been exhausted, fetch a new block of data to replenish the buffer. fn fetch(&mut self) -> io::Result<()> { // Only fetch when the ring buffer is empty. if self.is_buffer_exhausted() { // Split the vector at the write position to get slices of the two contiguous regions of // the ring buffer. let (vec1, vec0) = self.ring.split_at_mut(self.write_pos); // If the first contiguous region of the ring buffer starting from the write position // has sufficient space to service the entire read do a simple read into that region's // slice. let actual_read_len = if vec0.len() >= self.read_block_len { self.inner.read(&mut vec0[..self.read_block_len])? } else { // Otherwise, perform a vectored read into the two contiguous region slices. let rem = self.read_block_len - vec0.len(); let ring_vectors = &mut [IoSliceMut::new(vec0), IoSliceMut::new(&mut vec1[..rem])]; self.inner.read_vectored(ring_vectors)? }; // Increment the write position, taking into account wrap-around. self.write_pos = (self.write_pos + actual_read_len) & self.ring_mask; // Update the stream position accounting. self.abs_pos += actual_read_len as u64; self.rel_pos += actual_read_len as u64; // Grow the read block length exponentially to reduce the overhead of buffering on // consecutive seeks. self.read_block_len = cmp::min(self.read_block_len << 1, Self::MAX_BLOCK_LEN); } Ok(()) } /// If the buffer has been exhausted, fetch a new block of data to replenish the buffer. If /// no more data could be fetched, return an end-of-stream error. fn fetch_or_eof(&mut self) -> io::Result<()> { self.fetch()?; if self.is_buffer_exhausted() { return end_of_stream_error(); } Ok(()) } /// Advances the read position by `len` bytes, taking into account wrap-around. #[inline(always)] fn consume(&mut self, len: usize) { self.read_pos = (self.read_pos + len) & self.ring_mask; } /// Gets the largest contiguous slice of buffered data starting from the read position. #[inline(always)] fn continguous_buf(&self) -> &[u8] { if self.write_pos >= self.read_pos { &self.ring[self.read_pos..self.write_pos] } else { &self.ring[self.read_pos..] } } /// Resets the read-ahead buffer, and sets the absolute stream position to `pos`. fn reset(&mut self, pos: u64) { self.read_pos = 0; self.write_pos = 0; self.read_block_len = Self::MIN_BLOCK_LEN; self.abs_pos = pos; self.rel_pos = 0; } } impl MediaSource for MediaSourceStream { #[inline] fn is_seekable(&self) -> bool { self.inner.is_seekable() } #[inline] fn byte_len(&self) -> Option { self.inner.byte_len() } } impl io::Read for MediaSourceStream { fn read(&mut self, mut buf: &mut [u8]) -> io::Result { let read_len = buf.len(); while !buf.is_empty() { // Refill the the buffer cache if required. self.fetch()?; // Consume bytes from the readable portion of the buffer cache and copy them into the // remaining portion of the caller's buffer. match self.continguous_buf().read(buf) { Ok(0) => break, Ok(count) => { buf = &mut buf[count..]; self.consume(count); } Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} Err(e) => return Err(e), } } // The actual amount read is the original length of the caller's buffer minus the amount of // that buffer that is remaining. Ok(read_len - buf.len()) } } impl io::Seek for MediaSourceStream { fn seek(&mut self, pos: io::SeekFrom) -> io::Result { // The current position of the underlying reader is ahead of the current position of the // MediaSourceStream by how ever many bytes have not been read from the read-ahead buffer // yet. When seeking from the current position adjust the position delta to offset that // difference. let pos = match pos { io::SeekFrom::Current(0) => return Ok(self.pos()), io::SeekFrom::Current(delta_pos) => { let delta = delta_pos - self.unread_buffer_len() as i64; self.inner.seek(io::SeekFrom::Current(delta)) } _ => self.inner.seek(pos), }?; self.reset(pos); Ok(pos) } } impl ReadBytes for MediaSourceStream { #[inline(always)] fn read_byte(&mut self) -> io::Result { // This function, read_byte, is inlined for performance. To reduce code bloat, place the // read-ahead buffer replenishment in a seperate function. Call overhead will be negligible // compared to the actual underlying read. if self.is_buffer_exhausted() { self.fetch_or_eof()?; } let value = self.ring[self.read_pos]; self.consume(1); Ok(value) } fn read_double_bytes(&mut self) -> io::Result<[u8; 2]> { let mut bytes = [0; 2]; let buf = self.continguous_buf(); if buf.len() >= 2 { bytes.copy_from_slice(&buf[..2]); self.consume(2); } else { for byte in bytes.iter_mut() { *byte = self.read_byte()?; } }; Ok(bytes) } fn read_triple_bytes(&mut self) -> io::Result<[u8; 3]> { let mut bytes = [0; 3]; let buf = self.continguous_buf(); if buf.len() >= 3 { bytes.copy_from_slice(&buf[..3]); self.consume(3); } else { for byte in bytes.iter_mut() { *byte = self.read_byte()?; } }; Ok(bytes) } fn read_quad_bytes(&mut self) -> io::Result<[u8; 4]> { let mut bytes = [0; 4]; let buf = self.continguous_buf(); if buf.len() >= 4 { bytes.copy_from_slice(&buf[..4]); self.consume(4); } else { for byte in bytes.iter_mut() { *byte = self.read_byte()?; } }; Ok(bytes) } fn read_buf(&mut self, buf: &mut [u8]) -> io::Result { // Implemented via io::Read trait. let read = self.read(buf)?; // Unlike the io::Read trait, ByteStream returns an end-of-stream error when no more data // can be read. If a non-zero read is requested, and 0 bytes are read, return an // end-of-stream error. if !buf.is_empty() && read == 0 { end_of_stream_error() } else { Ok(read) } } fn read_buf_exact(&mut self, mut buf: &mut [u8]) -> io::Result<()> { while !buf.is_empty() { match self.read(buf) { Ok(0) => break, Ok(count) => { buf = &mut buf[count..]; } Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} Err(e) => return Err(e), } } if !buf.is_empty() { end_of_stream_error() } else { Ok(()) } } fn scan_bytes_aligned<'a>( &mut self, _: &[u8], _: usize, _: &'a mut [u8], ) -> io::Result<&'a mut [u8]> { // Intentionally left unimplemented. unimplemented!(); } fn ignore_bytes(&mut self, mut count: u64) -> io::Result<()> { // If the stream is seekable and the number of bytes to ignore is large, perform a seek // first. Note that ignored bytes are rewindable. Therefore, ensure the ring-buffer is // full after the seek just like if bytes were ignored by consuming them instead. let ring_len = self.ring.len() as u64; // Only apply the optimization if seeking 2x or more than the ring-buffer size. while count >= 2 * ring_len && self.is_seekable() { let delta = count.clamp(0, i64::MAX as u64).sub(ring_len); self.seek(io::SeekFrom::Current(delta as i64))?; count -= delta; } // Ignore the remaining bytes be consuming samples from the ring-buffer. while count > 0 { self.fetch_or_eof()?; let discard_count = cmp::min(self.unread_buffer_len() as u64, count); self.consume(discard_count as usize); count -= discard_count; } Ok(()) } fn pos(&self) -> u64 { self.abs_pos - self.unread_buffer_len() as u64 } } impl SeekBuffered for MediaSourceStream { fn ensure_seekback_buffer(&mut self, len: usize) { let ring_len = self.ring.len(); // A fetch can overwrite a maximum of MAX_BLOCK_LEN bytes in the ring. Therefore, for there // to always be `len` bytes available for seekback, the ring must be len + MAX_BLOCK_LEN in // length. Round-up to the next power-of-2 as that is an invariant of the ring. let new_ring_len = (Self::MAX_BLOCK_LEN + len).next_power_of_two(); // Only grow the ring if necessary. if ring_len < new_ring_len { // Allocate a new ring. let mut new_ring = vec![0; new_ring_len].into_boxed_slice(); // Get the readable regions of the current ring. let (vec0, vec1) = if self.write_pos >= self.read_pos { (&self.ring[self.read_pos..self.write_pos], None) } else { (&self.ring[self.read_pos..], Some(&self.ring[..self.write_pos])) }; // Copy contents from the old ring into new ring. let vec0_len = vec0.len(); new_ring[..vec0_len].copy_from_slice(vec0); self.write_pos = if let Some(vec1) = vec1 { let total_len = vec0_len + vec1.len(); new_ring[vec0_len..total_len].copy_from_slice(vec1); total_len } else { vec0_len }; self.ring = new_ring; self.ring_mask = new_ring_len - 1; self.read_pos = 0; } } fn unread_buffer_len(&self) -> usize { if self.write_pos >= self.read_pos { self.write_pos - self.read_pos } else { self.write_pos + (self.ring.len() - self.read_pos) } } fn read_buffer_len(&self) -> usize { let unread_len = self.unread_buffer_len(); cmp::min(self.ring.len(), self.rel_pos as usize) - unread_len } fn seek_buffered(&mut self, pos: u64) -> u64 { let old_pos = self.pos(); // Forward seek. let delta = if pos > old_pos { assert!(pos - old_pos < std::isize::MAX as u64); (pos - old_pos) as isize } else if pos < old_pos { // Backward seek. assert!(old_pos - pos < std::isize::MAX as u64); -((old_pos - pos) as isize) } else { 0 }; self.seek_buffered_rel(delta) } fn seek_buffered_rel(&mut self, delta: isize) -> u64 { if delta < 0 { let abs_delta = cmp::min((-delta) as usize, self.read_buffer_len()); self.read_pos = (self.read_pos + self.ring.len() - abs_delta) & self.ring_mask; } else if delta > 0 { let abs_delta = cmp::min(delta as usize, self.unread_buffer_len()); self.read_pos = (self.read_pos + abs_delta) & self.ring_mask; } self.pos() } } #[cfg(test)] mod tests { use super::{MediaSourceStream, ReadBytes, SeekBuffered}; use std::io::{Cursor, Read}; /// Generate a random vector of bytes of the specified length using a PRNG. fn generate_random_bytes(len: usize) -> Box<[u8]> { let mut lcg: u32 = 0xec57c4bf; let mut bytes = vec![0; len]; for quad in bytes.chunks_mut(4) { lcg = lcg.wrapping_mul(1664525).wrapping_add(1013904223); for (src, dest) in quad.iter_mut().zip(&lcg.to_le_bytes()) { *src = *dest; } } bytes.into_boxed_slice() } #[test] fn verify_mss_read() { let data = generate_random_bytes(5 * 96 * 1024); let ms = Cursor::new(data.clone()); let mut mss = MediaSourceStream::new(Box::new(ms), Default::default()); // Each of the following scenarios should exercise read-ahead and wrap-around the stream's // internal ring buffer. This means reading > 64kB for each scenario. Between each scenario, // ignore an odd number of bytes. let mut buf = &data[..]; // 96k single byte reads. for byte in &buf[..96 * 1024] { assert_eq!(*byte, mss.read_byte().unwrap()); } mss.ignore_bytes(11).unwrap(); buf = &buf[11 + (96 * 1024)..]; // 48k two byte reads. for bytes in buf[..2 * 48 * 1024].chunks_exact(2) { assert_eq!(bytes, &mss.read_double_bytes().unwrap()); } mss.ignore_bytes(33).unwrap(); buf = &buf[33 + (2 * 48 * 1024)..]; // 32k three byte reads. for bytes in buf[..3 * 32 * 1024].chunks_exact(3) { assert_eq!(bytes, &mss.read_triple_bytes().unwrap()); } mss.ignore_bytes(55).unwrap(); buf = &buf[55 + (3 * 32 * 1024)..]; // 24k four byte reads. for bytes in buf[..4 * 24 * 1024].chunks_exact(4) { assert_eq!(bytes, &mss.read_quad_bytes().unwrap()); } } #[test] fn verify_mss_read_to_end() { let data = generate_random_bytes(5 * 96 * 1024); let ms = Cursor::new(data.clone()); let mut mss = MediaSourceStream::new(Box::new(ms), Default::default()); let mut output: Vec = Vec::new(); assert_eq!(mss.read_to_end(&mut output).unwrap(), data.len()); assert_eq!(output.into_boxed_slice(), data); } #[test] fn verify_mss_seek_buffered() { let data = generate_random_bytes(1024 * 1024); let ms = Cursor::new(data); let mut mss = MediaSourceStream::new(Box::new(ms), Default::default()); assert_eq!(mss.read_buffer_len(), 0); assert_eq!(mss.unread_buffer_len(), 0); mss.ignore_bytes(5122).unwrap(); assert_eq!(5122, mss.pos()); assert_eq!(mss.read_buffer_len(), 5122); let upper = mss.read_byte().unwrap(); // Seek backwards. assert_eq!(mss.seek_buffered_rel(-1000), 4123); assert_eq!(mss.pos(), 4123); assert_eq!(mss.read_buffer_len(), 4123); // Seek forwards. assert_eq!(mss.seek_buffered_rel(999), 5122); assert_eq!(mss.pos(), 5122); assert_eq!(mss.read_buffer_len(), 5122); assert_eq!(upper, mss.read_byte().unwrap()); } #[test] fn verify_reading_be() { let data = generate_random_bytes(1024 * 1024); let ms = Cursor::new(data); let mut mss = MediaSourceStream::new(Box::new(ms), Default::default()); // For slightly cleaner floats mss.ignore_bytes(2).unwrap(); assert_eq!(mss.read_be_f32().unwrap(), -72818055000000000000000000000.0); assert_eq!(mss.read_be_f64().unwrap(), -0.000000000000011582640453292664); assert_eq!(mss.read_be_u16().unwrap(), 32624); assert_eq!(mss.read_be_u24().unwrap(), 6739677); assert_eq!(mss.read_be_u32().unwrap(), 1569552917); assert_eq!(mss.read_be_u64().unwrap(), 6091217585348000864); } #[test] fn verify_reading_le() { let data = generate_random_bytes(1024 * 1024); let ms = Cursor::new(data); let mut mss = MediaSourceStream::new(Box::new(ms), Default::default()); mss.ignore_bytes(1024).unwrap(); assert_eq!(mss.read_f32().unwrap(), -0.00000000000000000000000000048426285); assert_eq!(mss.read_f64().unwrap(), -6444325820119113.0); assert_eq!(mss.read_u16().unwrap(), 36195); assert_eq!(mss.read_u24().unwrap(), 6710386); assert_eq!(mss.read_u32().unwrap(), 2378776723); assert_eq!(mss.read_u64().unwrap(), 5170196279331153683); } } symphonia-core-0.5.4/src/io/mod.rs000064400000000000000000000426711046102023000151240ustar 00000000000000// Symphonia // Copyright (c) 2019-2022 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/. //! The `io` module implements composable bit- and byte-level I/O. //! //! The following nomenclature is used to denote where the data being read is sourced from: //! * A `Stream` consumes any source implementing [`ReadBytes`] one byte at a time. //! * A `Reader` consumes a `&[u8]`. //! //! The sole exception to this rule is [`MediaSourceStream`] which consumes sources implementing //! [`MediaSource`] (aka. [`std::io::Read`]). //! //! All `Reader`s and `Stream`s operating on bytes of data at a time implement the [`ReadBytes`] //! trait. Likewise, all `Reader`s and `Stream`s operating on bits of data at a time implement //! either the [`ReadBitsLtr`] or [`ReadBitsRtl`] traits depending on the order in which they //! consume bits. use std::io; use std::mem; mod bit; mod buf_reader; mod media_source_stream; mod monitor_stream; mod scoped_stream; pub use bit::*; pub use buf_reader::BufReader; pub use media_source_stream::{MediaSourceStream, MediaSourceStreamOptions}; pub use monitor_stream::{Monitor, MonitorStream}; pub use scoped_stream::ScopedStream; /// `MediaSource` is a composite trait of [`std::io::Read`] and [`std::io::Seek`]. A source *must* /// implement this trait to be used by [`MediaSourceStream`]. /// /// Despite requiring the [`std::io::Seek`] trait, seeking is an optional capability that can be /// queried at runtime. pub trait MediaSource: io::Read + io::Seek + Send + Sync { /// Returns if the source is seekable. This may be an expensive operation. fn is_seekable(&self) -> bool; /// Returns the length in bytes, if available. This may be an expensive operation. fn byte_len(&self) -> Option; } impl MediaSource for std::fs::File { /// Returns if the `std::io::File` backing the `MediaSource` is seekable. /// /// Note: This operation involves querying the underlying file descriptor for information and /// may be moderately expensive. Therefore it is recommended to cache this value if used often. fn is_seekable(&self) -> bool { // If the file's metadata is available, and the file is a regular file (i.e., not a FIFO, // etc.), then the MediaSource will be seekable. Otherwise assume it is not. Note that // metadata() follows symlinks. match self.metadata() { Ok(metadata) => metadata.is_file(), _ => false, } } /// Returns the length in bytes of the `std::io::File` backing the `MediaSource`. /// /// Note: This operation involves querying the underlying file descriptor for information and /// may be moderately expensive. Therefore it is recommended to cache this value if used often. fn byte_len(&self) -> Option { match self.metadata() { Ok(metadata) => Some(metadata.len()), _ => None, } } } impl + Send + Sync> MediaSource for io::Cursor { /// Always returns true since a `io::Cursor` is always seekable. fn is_seekable(&self) -> bool { true } /// Returns the length in bytes of the `io::Cursor` backing the `MediaSource`. fn byte_len(&self) -> Option { // Get the underlying container, usually &Vec. let inner = self.get_ref(); // Get slice from the underlying container, &[T], for the len() function. Some(inner.as_ref().len() as u64) } } /// `ReadOnlySource` wraps any source implementing [`std::io::Read`] in an unseekable /// [`MediaSource`]. pub struct ReadOnlySource { inner: R, } impl ReadOnlySource { /// Instantiates a new `ReadOnlySource` by taking ownership and wrapping the provided /// `Read`er. pub fn new(inner: R) -> Self { ReadOnlySource { inner } } /// Gets a reference to the underlying reader. pub fn get_ref(&self) -> &R { &self.inner } /// Gets a mutable reference to the underlying reader. pub fn get_mut(&mut self) -> &mut R { &mut self.inner } /// Unwraps this `ReadOnlySource`, returning the underlying reader. pub fn into_inner(self) -> R { self.inner } } impl MediaSource for ReadOnlySource { fn is_seekable(&self) -> bool { false } fn byte_len(&self) -> Option { None } } impl io::Read for ReadOnlySource { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.inner.read(buf) } } impl io::Seek for ReadOnlySource { fn seek(&mut self, _: io::SeekFrom) -> io::Result { Err(io::Error::new(io::ErrorKind::Other, "source does not support seeking")) } } /// `ReadBytes` provides methods to read bytes and interpret them as little- or big-endian /// unsigned integers or floating-point values of standard widths. pub trait ReadBytes { /// Reads a single byte from the stream and returns it or an error. fn read_byte(&mut self) -> io::Result; /// Reads two bytes from the stream and returns them in read-order or an error. fn read_double_bytes(&mut self) -> io::Result<[u8; 2]>; /// Reads three bytes from the stream and returns them in read-order or an error. fn read_triple_bytes(&mut self) -> io::Result<[u8; 3]>; /// Reads four bytes from the stream and returns them in read-order or an error. fn read_quad_bytes(&mut self) -> io::Result<[u8; 4]>; /// Reads up-to the number of bytes required to fill buf or returns an error. fn read_buf(&mut self, buf: &mut [u8]) -> io::Result; /// Reads exactly the number of bytes required to fill be provided buffer or returns an error. fn read_buf_exact(&mut self, buf: &mut [u8]) -> io::Result<()>; /// Reads a single unsigned byte from the stream and returns it or an error. #[inline(always)] fn read_u8(&mut self) -> io::Result { self.read_byte() } /// Reads a single signed byte from the stream and returns it or an error. #[inline(always)] fn read_i8(&mut self) -> io::Result { Ok(self.read_byte()? as i8) } /// Reads two bytes from the stream and interprets them as an unsigned 16-bit little-endian /// integer or returns an error. #[inline(always)] fn read_u16(&mut self) -> io::Result { Ok(u16::from_le_bytes(self.read_double_bytes()?)) } /// Reads two bytes from the stream and interprets them as an signed 16-bit little-endian /// integer or returns an error. #[inline(always)] fn read_i16(&mut self) -> io::Result { Ok(i16::from_le_bytes(self.read_double_bytes()?)) } /// Reads two bytes from the stream and interprets them as an unsigned 16-bit big-endian /// integer or returns an error. #[inline(always)] fn read_be_u16(&mut self) -> io::Result { Ok(u16::from_be_bytes(self.read_double_bytes()?)) } /// Reads two bytes from the stream and interprets them as an signed 16-bit big-endian /// integer or returns an error. #[inline(always)] fn read_be_i16(&mut self) -> io::Result { Ok(i16::from_be_bytes(self.read_double_bytes()?)) } /// Reads three bytes from the stream and interprets them as an unsigned 24-bit little-endian /// integer or returns an error. #[inline(always)] fn read_u24(&mut self) -> io::Result { let mut buf = [0u8; mem::size_of::()]; buf[0..3].clone_from_slice(&self.read_triple_bytes()?); Ok(u32::from_le_bytes(buf)) } /// Reads three bytes from the stream and interprets them as an signed 24-bit little-endian /// integer or returns an error. #[inline(always)] fn read_i24(&mut self) -> io::Result { Ok(((self.read_u24()? << 8) as i32) >> 8) } /// Reads three bytes from the stream and interprets them as an unsigned 24-bit big-endian /// integer or returns an error. #[inline(always)] fn read_be_u24(&mut self) -> io::Result { let mut buf = [0u8; mem::size_of::()]; buf[0..3].clone_from_slice(&self.read_triple_bytes()?); Ok(u32::from_be_bytes(buf) >> 8) } /// Reads three bytes from the stream and interprets them as an signed 24-bit big-endian /// integer or returns an error. #[inline(always)] fn read_be_i24(&mut self) -> io::Result { Ok(((self.read_be_u24()? << 8) as i32) >> 8) } /// Reads four bytes from the stream and interprets them as an unsigned 32-bit little-endian /// integer or returns an error. #[inline(always)] fn read_u32(&mut self) -> io::Result { Ok(u32::from_le_bytes(self.read_quad_bytes()?)) } /// Reads four bytes from the stream and interprets them as an signed 32-bit little-endian /// integer or returns an error. #[inline(always)] fn read_i32(&mut self) -> io::Result { Ok(i32::from_le_bytes(self.read_quad_bytes()?)) } /// Reads four bytes from the stream and interprets them as an unsigned 32-bit big-endian /// integer or returns an error. #[inline(always)] fn read_be_u32(&mut self) -> io::Result { Ok(u32::from_be_bytes(self.read_quad_bytes()?)) } /// Reads four bytes from the stream and interprets them as a signed 32-bit big-endian /// integer or returns an error. #[inline(always)] fn read_be_i32(&mut self) -> io::Result { Ok(i32::from_be_bytes(self.read_quad_bytes()?)) } /// Reads eight bytes from the stream and interprets them as an unsigned 64-bit little-endian /// integer or returns an error. #[inline(always)] fn read_u64(&mut self) -> io::Result { let mut buf = [0u8; mem::size_of::()]; self.read_buf_exact(&mut buf)?; Ok(u64::from_le_bytes(buf)) } /// Reads eight bytes from the stream and interprets them as an signed 64-bit little-endian /// integer or returns an error. #[inline(always)] fn read_i64(&mut self) -> io::Result { let mut buf = [0u8; mem::size_of::()]; self.read_buf_exact(&mut buf)?; Ok(i64::from_le_bytes(buf)) } /// Reads eight bytes from the stream and interprets them as an unsigned 64-bit big-endian /// integer or returns an error. #[inline(always)] fn read_be_u64(&mut self) -> io::Result { let mut buf = [0u8; mem::size_of::()]; self.read_buf_exact(&mut buf)?; Ok(u64::from_be_bytes(buf)) } /// Reads eight bytes from the stream and interprets them as an signed 64-bit big-endian /// integer or returns an error. #[inline(always)] fn read_be_i64(&mut self) -> io::Result { let mut buf = [0u8; mem::size_of::()]; self.read_buf_exact(&mut buf)?; Ok(i64::from_be_bytes(buf)) } /// Reads four bytes from the stream and interprets them as a 32-bit little-endian IEEE-754 /// floating-point value. #[inline(always)] fn read_f32(&mut self) -> io::Result { Ok(f32::from_le_bytes(self.read_quad_bytes()?)) } /// Reads four bytes from the stream and interprets them as a 32-bit big-endian IEEE-754 /// floating-point value. #[inline(always)] fn read_be_f32(&mut self) -> io::Result { Ok(f32::from_be_bytes(self.read_quad_bytes()?)) } /// Reads four bytes from the stream and interprets them as a 64-bit little-endian IEEE-754 /// floating-point value. #[inline(always)] fn read_f64(&mut self) -> io::Result { let mut buf = [0u8; mem::size_of::()]; self.read_buf_exact(&mut buf)?; Ok(f64::from_le_bytes(buf)) } /// Reads four bytes from the stream and interprets them as a 64-bit big-endian IEEE-754 /// floating-point value. #[inline(always)] fn read_be_f64(&mut self) -> io::Result { let mut buf = [0u8; mem::size_of::()]; self.read_buf_exact(&mut buf)?; Ok(f64::from_be_bytes(buf)) } /// Reads up-to the number of bytes requested, and returns a boxed slice of the data or an /// error. fn read_boxed_slice(&mut self, len: usize) -> io::Result> { let mut buf = vec![0u8; len]; let actual_len = self.read_buf(&mut buf)?; buf.truncate(actual_len); Ok(buf.into_boxed_slice()) } /// Reads exactly the number of bytes requested, and returns a boxed slice of the data or an /// error. fn read_boxed_slice_exact(&mut self, len: usize) -> io::Result> { let mut buf = vec![0u8; len]; self.read_buf_exact(&mut buf)?; Ok(buf.into_boxed_slice()) } /// Reads bytes from the stream into a supplied buffer until a byte pattern is matched. Returns /// a mutable slice to the valid region of the provided buffer. #[inline(always)] fn scan_bytes<'a>(&mut self, pattern: &[u8], buf: &'a mut [u8]) -> io::Result<&'a mut [u8]> { self.scan_bytes_aligned(pattern, 1, buf) } /// Reads bytes from a stream into a supplied buffer until a byte patter is matched on an /// aligned byte boundary. Returns a mutable slice to the valid region of the provided buffer. fn scan_bytes_aligned<'a>( &mut self, pattern: &[u8], align: usize, buf: &'a mut [u8], ) -> io::Result<&'a mut [u8]>; /// Ignores the specified number of bytes from the stream or returns an error. fn ignore_bytes(&mut self, count: u64) -> io::Result<()>; /// Gets the position of the stream. fn pos(&self) -> u64; } impl<'b, R: ReadBytes> ReadBytes for &'b mut R { #[inline(always)] fn read_byte(&mut self) -> io::Result { (*self).read_byte() } #[inline(always)] fn read_double_bytes(&mut self) -> io::Result<[u8; 2]> { (*self).read_double_bytes() } #[inline(always)] fn read_triple_bytes(&mut self) -> io::Result<[u8; 3]> { (*self).read_triple_bytes() } #[inline(always)] fn read_quad_bytes(&mut self) -> io::Result<[u8; 4]> { (*self).read_quad_bytes() } #[inline(always)] fn read_buf(&mut self, buf: &mut [u8]) -> io::Result { (*self).read_buf(buf) } #[inline(always)] fn read_buf_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { (*self).read_buf_exact(buf) } #[inline(always)] fn scan_bytes_aligned<'a>( &mut self, pattern: &[u8], align: usize, buf: &'a mut [u8], ) -> io::Result<&'a mut [u8]> { (*self).scan_bytes_aligned(pattern, align, buf) } #[inline(always)] fn ignore_bytes(&mut self, count: u64) -> io::Result<()> { (*self).ignore_bytes(count) } #[inline(always)] fn pos(&self) -> u64 { (**self).pos() } } impl<'b, S: SeekBuffered> SeekBuffered for &'b mut S { fn ensure_seekback_buffer(&mut self, len: usize) { (*self).ensure_seekback_buffer(len) } fn unread_buffer_len(&self) -> usize { (**self).unread_buffer_len() } fn read_buffer_len(&self) -> usize { (**self).read_buffer_len() } fn seek_buffered(&mut self, pos: u64) -> u64 { (*self).seek_buffered(pos) } fn seek_buffered_rel(&mut self, delta: isize) -> u64 { (*self).seek_buffered_rel(delta) } } /// `SeekBuffered` provides methods to seek within the buffered portion of a stream. pub trait SeekBuffered { /// Ensures that `len` bytes will be available for backwards seeking if `len` bytes have been /// previously read. fn ensure_seekback_buffer(&mut self, len: usize); /// Get the number of bytes buffered but not yet read. /// /// Note: This is the maximum number of bytes that can be seeked forwards within the buffer. fn unread_buffer_len(&self) -> usize; /// Gets the number of bytes buffered and read. /// /// Note: This is the maximum number of bytes that can be seeked backwards within the buffer. fn read_buffer_len(&self) -> usize; /// Seek within the buffered data to an absolute position in the stream. Returns the position /// seeked to. fn seek_buffered(&mut self, pos: u64) -> u64; /// Seek within the buffered data relative to the current position in the stream. Returns the /// position seeked to. /// /// The range of `delta` is clamped to the inclusive range defined by /// `-read_buffer_len()..=unread_buffer_len()`. fn seek_buffered_rel(&mut self, delta: isize) -> u64; /// Seek backwards within the buffered data. /// /// This function is identical to [`SeekBuffered::seek_buffered_rel`] when a negative delta is /// provided. fn seek_buffered_rev(&mut self, delta: usize) { assert!(delta < std::isize::MAX as usize); self.seek_buffered_rel(-(delta as isize)); } } impl<'b, F: FiniteStream> FiniteStream for &'b mut F { fn byte_len(&self) -> u64 { (**self).byte_len() } fn bytes_read(&self) -> u64 { (**self).bytes_read() } fn bytes_available(&self) -> u64 { (**self).bytes_available() } } /// A `FiniteStream` is a stream that has a known length in bytes. pub trait FiniteStream { /// Returns the length of the the stream in bytes. fn byte_len(&self) -> u64; /// Returns the number of bytes that have been read. fn bytes_read(&self) -> u64; /// Returns the number of bytes available for reading. fn bytes_available(&self) -> u64; } symphonia-core-0.5.4/src/io/monitor_stream.rs000064400000000000000000000070221046102023000173760ustar 00000000000000// Symphonia // Copyright (c) 2019-2022 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/. use std::io; use super::ReadBytes; /// A `Monitor` provides a common interface to examine the operations observed be /// a [`MonitorStream`]. pub trait Monitor { fn process_byte(&mut self, byte: u8); #[inline(always)] fn process_double_bytes(&mut self, buf: [u8; 2]) { self.process_byte(buf[0]); self.process_byte(buf[1]); } #[inline(always)] fn process_triple_bytes(&mut self, buf: [u8; 3]) { self.process_byte(buf[0]); self.process_byte(buf[1]); self.process_byte(buf[2]); } #[inline(always)] fn process_quad_bytes(&mut self, buf: [u8; 4]) { self.process_byte(buf[0]); self.process_byte(buf[1]); self.process_byte(buf[2]); self.process_byte(buf[3]); } fn process_buf_bytes(&mut self, buf: &[u8]); } /// A `MonitorStream` is a passive stream that observes all operations performed on the inner /// stream and forwards an immutable reference of the result to a [`Monitor`]. pub struct MonitorStream { inner: B, monitor: M, } impl MonitorStream { pub fn new(inner: B, monitor: M) -> MonitorStream { MonitorStream { inner, monitor } } pub fn inner(&self) -> &B { &self.inner } pub fn inner_mut(&mut self) -> &mut B { &mut self.inner } pub fn into_inner(self) -> B { self.inner } pub fn monitor(&self) -> &M { &self.monitor } pub fn monitor_mut(&mut self) -> &mut M { &mut self.monitor } } impl ReadBytes for MonitorStream { #[inline(always)] fn read_byte(&mut self) -> io::Result { let byte = self.inner.read_byte()?; self.monitor.process_byte(byte); Ok(byte) } #[inline(always)] fn read_double_bytes(&mut self) -> io::Result<[u8; 2]> { let bytes = self.inner.read_double_bytes()?; self.monitor.process_double_bytes(bytes); Ok(bytes) } #[inline(always)] fn read_triple_bytes(&mut self) -> io::Result<[u8; 3]> { let bytes = self.inner.read_triple_bytes()?; self.monitor.process_triple_bytes(bytes); Ok(bytes) } #[inline(always)] fn read_quad_bytes(&mut self) -> io::Result<[u8; 4]> { let bytes = self.inner.read_quad_bytes()?; self.monitor.process_quad_bytes(bytes); Ok(bytes) } fn read_buf(&mut self, buf: &mut [u8]) -> io::Result { let len = self.inner.read_buf(buf)?; self.monitor.process_buf_bytes(&buf[0..len]); Ok(len) } fn read_buf_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { self.inner.read_buf_exact(buf)?; self.monitor.process_buf_bytes(buf); Ok(()) } fn scan_bytes_aligned<'a>( &mut self, pattern: &[u8], align: usize, buf: &'a mut [u8], ) -> io::Result<&'a mut [u8]> { let result = self.inner.scan_bytes_aligned(pattern, align, buf)?; self.monitor.process_buf_bytes(result); Ok(result) } fn ignore_bytes(&mut self, count: u64) -> io::Result<()> { self.inner.ignore_bytes(count) } #[inline(always)] fn pos(&self) -> u64 { self.inner.pos() } } symphonia-core-0.5.4/src/io/scoped_stream.rs000064400000000000000000000125701046102023000171700ustar 00000000000000// Symphonia // Copyright (c) 2019-2022 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/. use std::cmp; use std::io; use super::{FiniteStream, ReadBytes, SeekBuffered}; #[inline(always)] fn out_of_bounds_error() -> io::Result { Err(io::Error::new(io::ErrorKind::UnexpectedEof, "out of bounds")) } /// A `ScopedStream` restricts the number of bytes that may be read to an upper limit. pub struct ScopedStream { inner: B, start: u64, len: u64, read: u64, } impl ScopedStream { /// Instantiates a new `ScopedStream` with an upper limit on the number of bytes that can be /// read from the inner source. pub fn new(inner: B, len: u64) -> Self { ScopedStream { start: inner.pos(), inner, len, read: 0 } } /// Returns an immutable reference to the inner stream. pub fn inner(&self) -> &B { &self.inner } /// Returns a mutable reference to the inner stream. pub fn inner_mut(&mut self) -> &mut B { &mut self.inner } /// Ignores the remainder of the `ScopedStream`. pub fn ignore(&mut self) -> io::Result<()> { self.inner.ignore_bytes(self.len - self.read) } /// Convert the `ScopedStream` to the inner stream. pub fn into_inner(self) -> B { self.inner } } impl FiniteStream for ScopedStream { /// Returns the length of the the `ScopedStream`. fn byte_len(&self) -> u64 { self.len } /// Returns the number of bytes read. fn bytes_read(&self) -> u64 { self.read } /// Returns the number of bytes available to read. fn bytes_available(&self) -> u64 { self.len - self.read } } impl ReadBytes for ScopedStream { #[inline(always)] fn read_byte(&mut self) -> io::Result { if self.len - self.read < 1 { return out_of_bounds_error(); } self.read += 1; self.inner.read_byte() } #[inline(always)] fn read_double_bytes(&mut self) -> io::Result<[u8; 2]> { if self.len - self.read < 2 { return out_of_bounds_error(); } self.read += 2; self.inner.read_double_bytes() } #[inline(always)] fn read_triple_bytes(&mut self) -> io::Result<[u8; 3]> { if self.len - self.read < 3 { return out_of_bounds_error(); } self.read += 3; self.inner.read_triple_bytes() } #[inline(always)] fn read_quad_bytes(&mut self) -> io::Result<[u8; 4]> { if self.len - self.read < 4 { return out_of_bounds_error(); } self.read += 4; self.inner.read_quad_bytes() } fn read_buf(&mut self, buf: &mut [u8]) -> io::Result { // Limit read_buf() to the remainder of the scoped bytes if buf has a greater length. let scoped_len = cmp::min(self.len - self.read, buf.len() as u64) as usize; let result = self.inner.read_buf(&mut buf[0..scoped_len])?; self.read += result as u64; Ok(result) } fn read_buf_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { if self.len - self.read < buf.len() as u64 { return out_of_bounds_error(); } self.read += buf.len() as u64; self.inner.read_buf_exact(buf) } #[inline(always)] fn scan_bytes_aligned<'a>( &mut self, pattern: &[u8], align: usize, buf: &'a mut [u8], ) -> io::Result<&'a mut [u8]> { if self.len - self.read < buf.len() as u64 { return out_of_bounds_error(); } let result = self.inner.scan_bytes_aligned(pattern, align, buf)?; self.read += result.len() as u64; Ok(result) } #[inline(always)] fn ignore_bytes(&mut self, count: u64) -> io::Result<()> { if self.len - self.read < count { return out_of_bounds_error(); } self.read += count; self.inner.ignore_bytes(count) } #[inline(always)] fn pos(&self) -> u64 { self.inner.pos() } } impl SeekBuffered for ScopedStream { #[inline(always)] fn ensure_seekback_buffer(&mut self, len: usize) { self.inner.ensure_seekback_buffer(len) } #[inline(always)] fn unread_buffer_len(&self) -> usize { self.inner.unread_buffer_len().min((self.len - self.read) as usize) } #[inline(always)] fn read_buffer_len(&self) -> usize { self.inner.read_buffer_len().min(self.read as usize) } #[inline(always)] fn seek_buffered(&mut self, pos: u64) -> u64 { // Clamp the seekable position to within the bounds of the ScopedStream. self.inner.seek_buffered(pos.clamp(self.start, self.start + self.len)) } #[inline(always)] fn seek_buffered_rel(&mut self, delta: isize) -> u64 { // Clamp the delta value such that the absolute position after the buffered seek will be // within the bounds of the ScopedStream. let max_back = self.read.min(std::isize::MAX as u64) as isize; let max_forward = (self.len - self.read).min(std::isize::MAX as u64) as isize; self.inner.seek_buffered_rel(delta.clamp(-max_back, max_forward)) } } symphonia-core-0.5.4/src/lib.rs000064400000000000000000000013661046102023000145000ustar 00000000000000// Symphonia // Copyright (c) 2019-2022 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/. #![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)] pub mod audio; pub mod checksum; pub mod codecs; pub mod conv; pub mod dsp; pub mod errors; pub mod formats; pub mod io; pub mod meta; pub mod probe; pub mod sample; pub mod units; pub mod util; symphonia-core-0.5.4/src/meta.rs000064400000000000000000000372541046102023000146650ustar 00000000000000// Symphonia // Copyright (c) 2019-2022 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/. //! The `meta` module defines basic metadata elements, and management structures. use std::borrow::Cow; use std::collections::VecDeque; use std::convert::From; use std::fmt; use std::num::NonZeroU32; use crate::errors::Result; use crate::io::MediaSourceStream; /// `Limit` defines an upper-bound on how much of a resource should be allocated when the amount to /// be allocated is specified by the media stream, which is untrusted. A limit will place an /// upper-bound on this allocation at the risk of breaking potentially valid streams. Limits are /// used to prevent denial-of-service attacks. /// /// All limits can be defaulted to a reasonable value specific to the situation. These defaults will /// generally not break any normal streams. #[derive(Copy, Clone, Debug)] pub enum Limit { /// Do not impose any limit. None, /// Use the a reasonable default specified by the `FormatReader` or `Decoder` implementation. Default, /// Specify the upper limit of the resource. Units are case specific. Maximum(usize), } impl Limit { /// Gets the numeric limit of the limit, or default value. If there is no limit, None is /// returned. pub fn limit_or_default(&self, default: usize) -> Option { match self { Limit::None => None, Limit::Default => Some(default), Limit::Maximum(max) => Some(*max), } } } impl Default for Limit { fn default() -> Self { Limit::Default } } /// `MetadataOptions` is a common set of options that all metadata readers use. #[derive(Copy, Clone, Debug, Default)] pub struct MetadataOptions { /// The maximum size limit in bytes that a tag may occupy in memory once decoded. Tags exceeding /// this limit will be skipped by the demuxer. Take note that tags in-memory are stored as UTF-8 /// and therefore may occupy more than one byte per character. pub limit_metadata_bytes: Limit, /// The maximum size limit in bytes that a visual (picture) may occupy. pub limit_visual_bytes: Limit, } /// `StandardVisualKey` is an enumeration providing standardized keys for common visual dispositions. /// A demuxer may assign a `StandardVisualKey` to a `Visual` if the disposition of the attached /// visual is known and can be mapped to a standard key. /// /// The visual types listed here are derived from, though do not entirely cover, the ID3v2 APIC /// frame specification. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum StandardVisualKey { FileIcon, OtherIcon, FrontCover, BackCover, Leaflet, Media, LeadArtistPerformerSoloist, ArtistPerformer, Conductor, BandOrchestra, Composer, Lyricist, RecordingLocation, RecordingSession, Performance, ScreenCapture, Illustration, BandArtistLogo, PublisherStudioLogo, } /// `StandardTagKey` is an enumeration providing standardized keys for common tag types. /// A tag reader may assign a `StandardTagKey` to a `Tag` if the tag's key is generally /// accepted to map to a specific usage. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum StandardTagKey { AcoustidFingerprint, AcoustidId, Album, AlbumArtist, Arranger, Artist, Bpm, Comment, Compilation, Composer, Conductor, ContentGroup, Copyright, Date, Description, DiscNumber, DiscSubtitle, DiscTotal, EncodedBy, Encoder, EncoderSettings, EncodingDate, Engineer, Ensemble, Genre, IdentAsin, IdentBarcode, IdentCatalogNumber, IdentEanUpn, IdentIsrc, IdentPn, IdentPodcast, IdentUpc, Label, Language, License, Lyricist, Lyrics, MediaFormat, MixDj, MixEngineer, Mood, MovementName, MovementNumber, MusicBrainzAlbumArtistId, MusicBrainzAlbumId, MusicBrainzArtistId, MusicBrainzDiscId, MusicBrainzGenreId, MusicBrainzLabelId, MusicBrainzOriginalAlbumId, MusicBrainzOriginalArtistId, MusicBrainzRecordingId, MusicBrainzReleaseGroupId, MusicBrainzReleaseStatus, MusicBrainzReleaseTrackId, MusicBrainzReleaseType, MusicBrainzTrackId, MusicBrainzWorkId, Opus, OriginalAlbum, OriginalArtist, OriginalDate, OriginalFile, OriginalWriter, Owner, Part, PartTotal, Performer, Podcast, PodcastCategory, PodcastDescription, PodcastKeywords, Producer, PurchaseDate, Rating, ReleaseCountry, ReleaseDate, Remixer, ReplayGainAlbumGain, ReplayGainAlbumPeak, ReplayGainTrackGain, ReplayGainTrackPeak, Script, SortAlbum, SortAlbumArtist, SortArtist, SortComposer, SortTrackTitle, TaggingDate, TrackNumber, TrackSubtitle, TrackTitle, TrackTotal, TvEpisode, TvEpisodeTitle, TvNetwork, TvSeason, TvShowTitle, Url, UrlArtist, UrlCopyright, UrlInternetRadio, UrlLabel, UrlOfficial, UrlPayment, UrlPodcast, UrlPurchase, UrlSource, Version, Writer, } /// A `Tag` value. /// /// Note: The data types in this enumeration are a generalization. Depending on the particular tag /// format, the actual data type a specific tag may have a lesser width or encoding than the data /// type in this enumeration. #[derive(Clone, Debug)] pub enum Value { /// A binary buffer. Binary(Box<[u8]>), /// A boolean value. Boolean(bool), /// A flag or indicator. A flag carries no data, but the presence of the tag has an implicit /// meaning. Flag, /// A floating point number. Float(f64), /// A signed integer. SignedInt(i64), /// A string. This is also the catch-all type for tags with unconventional data types. String(String), /// An unsigned integer. UnsignedInt(u64), } macro_rules! impl_from_for_value { ($value:ident, $from:ty, $conv:expr) => { impl From<$from> for Value { fn from($value: $from) -> Self { $conv } } }; } impl_from_for_value!(v, &[u8], Value::Binary(Box::from(v))); impl_from_for_value!(v, bool, Value::Boolean(v)); impl_from_for_value!(v, f32, Value::Float(f64::from(v))); impl_from_for_value!(v, f64, Value::Float(v)); impl_from_for_value!(v, i8, Value::SignedInt(i64::from(v))); impl_from_for_value!(v, i16, Value::SignedInt(i64::from(v))); impl_from_for_value!(v, i32, Value::SignedInt(i64::from(v))); impl_from_for_value!(v, i64, Value::SignedInt(v)); impl_from_for_value!(v, u8, Value::UnsignedInt(u64::from(v))); impl_from_for_value!(v, u16, Value::UnsignedInt(u64::from(v))); impl_from_for_value!(v, u32, Value::UnsignedInt(u64::from(v))); impl_from_for_value!(v, u64, Value::UnsignedInt(v)); impl_from_for_value!(v, &str, Value::String(String::from(v))); impl_from_for_value!(v, String, Value::String(v)); impl_from_for_value!(v, Cow<'_, str>, Value::String(String::from(v))); fn buffer_to_hex_string(buf: &[u8]) -> String { let mut output = String::with_capacity(5 * buf.len()); for ch in buf { let u = (ch & 0xf0) >> 4; let l = ch & 0x0f; output.push_str("\\0x"); output.push(if u < 10 { (b'0' + u) as char } else { (b'a' + u - 10) as char }); output.push(if l < 10 { (b'0' + l) as char } else { (b'a' + l - 10) as char }); } output } impl fmt::Display for Value { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Implement default formatters for each type. match self { Value::Binary(ref buf) => f.write_str(&buffer_to_hex_string(buf)), Value::Boolean(boolean) => fmt::Display::fmt(boolean, f), Value::Flag => write!(f, ""), Value::Float(float) => fmt::Display::fmt(float, f), Value::SignedInt(int) => fmt::Display::fmt(int, f), Value::String(ref string) => fmt::Display::fmt(string, f), Value::UnsignedInt(uint) => fmt::Display::fmt(uint, f), } } } /// A `Tag` encapsulates a key-value pair of metadata. #[derive(Clone, Debug)] pub struct Tag { /// If the `Tag`'s key string is commonly associated with a typical type, meaning, or purpose, /// then if recognized a `StandardTagKey` will be assigned to this `Tag`. /// /// This is a best effort guess since not all metadata formats have a well defined or specified /// tag mapping. However, it is recommended that consumers prefer `std_key` over `key`, if /// provided. pub std_key: Option, /// A key string indicating the type, meaning, or purpose of the `Tag`s value. /// /// Note: The meaning of `key` is dependant on the underlying metadata format. pub key: String, /// The value of the `Tag`. pub value: Value, } impl Tag { /// Create a new `Tag`. pub fn new(std_key: Option, key: &str, value: Value) -> Tag { Tag { std_key, key: key.to_string(), value } } /// Returns true if the `Tag`'s key string was recognized and a `StandardTagKey` was assigned, /// otherwise false is returned. pub fn is_known(&self) -> bool { self.std_key.is_some() } } impl fmt::Display for Tag { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.std_key { Some(ref std_key) => { write!(f, "{{ std_key={:?}, key=\"{}\", value={} }}", std_key, self.key, self.value) } None => write!(f, "{{ key=\"{}\", value={} }}", self.key, self.value), } } } /// A 2 dimensional (width and height) size type. #[derive(Copy, Clone, Debug, Default)] pub struct Size { /// The width in pixels. pub width: u32, /// The height in pixels. pub height: u32, } /// `ColorMode` indicates how the color of a pixel is encoded in a `Visual`. #[derive(Copy, Clone, Debug)] pub enum ColorMode { /// Each pixel in the `Visual` stores its own color information. Discrete, /// Each pixel in the `Visual` stores an index into a color palette containing the color /// information. The value stored by this variant indicates the number of colors in the color /// palette. Indexed(NonZeroU32), } /// A `Visual` is any 2 dimensional graphic. #[derive(Clone, Debug)] pub struct Visual { /// The Media Type (MIME Type) used to encode the `Visual`. pub media_type: String, /// The dimensions of the `Visual`. /// /// Note: This value may not be accurate as it comes from metadata, not the embedded graphic /// itself. Consider it only a hint. pub dimensions: Option, /// The number of bits-per-pixel (aka bit-depth) of the unencoded image. /// /// Note: This value may not be accurate as it comes from metadata, not the embedded graphic /// itself. Consider it only a hint. pub bits_per_pixel: Option, /// The color mode of the `Visual`. /// /// Note: This value may not be accurate as it comes from metadata, not the embedded graphic /// itself. Consider it only a hint. pub color_mode: Option, /// The usage and/or content of the `Visual`. pub usage: Option, /// Any tags associated with the `Visual`. pub tags: Vec, /// The data of the `Visual`, encoded as per `media_type`. pub data: Box<[u8]>, } /// `VendorData` is any binary metadata that is proprietary to a certain application or vendor. #[derive(Clone, Debug)] pub struct VendorData { /// A text representation of the vendor's application identifier. pub ident: String, /// The vendor data. pub data: Box<[u8]>, } /// `Metadata` is a container for a single discrete revision of metadata information. #[derive(Clone, Debug, Default)] pub struct MetadataRevision { tags: Vec, visuals: Vec, vendor_data: Vec, } impl MetadataRevision { /// Gets an immutable slice to the `Tag`s in this revision. /// /// If a tag read from the source contained multiple values, then there will be one `Tag` item /// per value, with each item having the same key and standard key. pub fn tags(&self) -> &[Tag] { &self.tags } /// Gets an immutable slice to the `Visual`s in this revision. pub fn visuals(&self) -> &[Visual] { &self.visuals } /// Gets an immutable slice to the `VendorData` in this revision. pub fn vendor_data(&self) -> &[VendorData] { &self.vendor_data } } /// `MetadataBuilder` is the builder for `Metadata` revisions. #[derive(Clone, Debug, Default)] pub struct MetadataBuilder { metadata: MetadataRevision, } impl MetadataBuilder { /// Instantiate a new `MetadataBuilder`. pub fn new() -> Self { MetadataBuilder { metadata: Default::default() } } /// Add a `Tag` to the metadata. pub fn add_tag(&mut self, tag: Tag) -> &mut Self { self.metadata.tags.push(tag); self } /// Add a `Visual` to the metadata. pub fn add_visual(&mut self, visual: Visual) -> &mut Self { self.metadata.visuals.push(visual); self } /// Add `VendorData` to the metadata. pub fn add_vendor_data(&mut self, vendor_data: VendorData) -> &mut Self { self.metadata.vendor_data.push(vendor_data); self } /// Yield the constructed `Metadata` revision. pub fn metadata(self) -> MetadataRevision { self.metadata } } /// A reference to the metadata inside of a [MetadataLog]. #[derive(Debug)] pub struct Metadata<'a> { revisions: &'a mut VecDeque, } impl<'a> Metadata<'a> { /// Returns `true` if the current metadata revision is the newest, `false` otherwise. pub fn is_latest(&self) -> bool { self.revisions.len() <= 1 } /// Gets an immutable reference to the current, and therefore oldest, revision of the metadata. pub fn current(&self) -> Option<&MetadataRevision> { self.revisions.front() } /// Skips to, and gets an immutable reference to the latest, and therefore newest, revision of /// the metadata. pub fn skip_to_latest(&mut self) -> Option<&MetadataRevision> { loop { if self.pop().is_none() { break; } } self.current() } /// If there are newer `Metadata` revisions, advances the `MetadataLog` by discarding the /// current revision and replacing it with the next revision, returning the discarded /// `Metadata`. When there are no newer revisions, `None` is returned. As such, `pop` will never /// completely empty the log. pub fn pop(&mut self) -> Option { if self.revisions.len() > 1 { self.revisions.pop_front() } else { None } } } /// `MetadataLog` is a container for time-ordered `Metadata` revisions. #[derive(Clone, Debug, Default)] pub struct MetadataLog { revisions: VecDeque, } impl MetadataLog { /// Returns a reducable reference to the metadata inside the log. pub fn metadata(&mut self) -> Metadata<'_> { Metadata { revisions: &mut self.revisions } } /// Pushes a new `Metadata` revision onto the log. pub fn push(&mut self, rev: MetadataRevision) { self.revisions.push_back(rev); } } pub trait MetadataReader: Send + Sync { /// Instantiates the `MetadataReader` with the provided `MetadataOptions`. fn new(options: &MetadataOptions) -> Self where Self: Sized; /// Read all metadata and return it if successful. fn read_all(&mut self, reader: &mut MediaSourceStream) -> Result; } symphonia-core-0.5.4/src/probe.rs000064400000000000000000000327111046102023000150370ustar 00000000000000// Symphonia // Copyright (c) 2019-2022 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/. //! The `probe` module provides methods and traits to support auto-detection of media formats from //! arbitrary media streams. use crate::errors::{unsupported_error, Result}; use crate::formats::{FormatOptions, FormatReader}; use crate::io::{MediaSourceStream, ReadBytes, SeekBuffered}; use crate::meta::{Metadata, MetadataLog, MetadataOptions, MetadataReader}; use log::{debug, error, info}; mod bloom { fn fnv1a32(value: &[u8; 2]) -> u32 { const INIT: u32 = 0x811c_9dc5; const PRIME: u32 = 0x0100_0193; let mut state = INIT; for byte in value.iter() { state = (state ^ u32::from(*byte)).wrapping_mul(PRIME); } state } pub struct BloomFilter { filter: Box<[u64]>, } impl Default for BloomFilter { fn default() -> Self { BloomFilter { filter: vec![0; BloomFilter::M >> 6].into_boxed_slice() } } } impl BloomFilter { /// The number of bits, m, used by the bloom filter. Use 16384 bits (2KiB) by default. const M: usize = 2 * 1024 * 8; pub fn insert(&mut self, key: &[u8; 2]) { let hash = fnv1a32(key); let h0 = (hash >> 16) as u16; let h1 = (hash >> 0) as u16; let i0 = h0 as usize & (BloomFilter::M - 1); let i1 = h0.wrapping_add(h1.wrapping_mul(1)) as usize & (BloomFilter::M - 1); let i2 = h0.wrapping_add(h1.wrapping_mul(2)) as usize & (BloomFilter::M - 1); self.filter[i0 >> 6] |= 1 << (i0 & 63); self.filter[i1 >> 6] |= 1 << (i1 & 63); self.filter[i2 >> 6] |= 1 << (i2 & 63); } pub fn may_contain(&self, key: &[u8; 2]) -> bool { let hash = fnv1a32(key); let h0 = (hash >> 16) as u16; let h1 = (hash >> 0) as u16; let i0 = h0 as usize & (BloomFilter::M - 1); let i1 = h0.wrapping_add(h1.wrapping_mul(1)) as usize & (BloomFilter::M - 1); let i2 = h0.wrapping_add(h1.wrapping_mul(2)) as usize & (BloomFilter::M - 1); if (self.filter[i0 >> 6] & (1 << (i0 & 63))) == 0 { return false; } if (self.filter[i1 >> 6] & (1 << (i1 & 63))) == 0 { return false; } if (self.filter[i2 >> 6] & (1 << (i2 & 63))) == 0 { return false; } true } } } /// `Instantiate` is an enumeration of instantiation functions used by `Descriptor` and `Probe` to /// instantiate metadata and container format readers. #[derive(Copy, Clone)] pub enum Instantiate { /// Instantiation function for a `FormatReader`. Format(fn(MediaSourceStream, &FormatOptions) -> Result>), /// Instantiation function for a `MetadataReader`. Metadata(fn(&MetadataOptions) -> Box), } /// `Descriptor` provides declarative information about container and metadata formats. /// `Descriptor`s are used by `Probe` and related machinery to scan a `MediaSourceStream` for media. #[derive(Copy, Clone)] pub struct Descriptor { /// A short ASCII-only string identifying the codec. pub short_name: &'static str, /// A longer, more descriptive, string identifying the codec. pub long_name: &'static str, /// A list of case-insensitive file extensions that are generally used by the format. pub extensions: &'static [&'static str], /// A list of case-insensitive MIME types that are generally used by the format. pub mime_types: &'static [&'static str], /// A byte-string start-of-stream marker that will be searched for within the stream. pub markers: &'static [&'static [u8]], /// A function to score a context buffer. pub score: fn(&[u8]) -> u8, /// An instantiation function. pub inst: Instantiate, } /// The `QueryDescriptor` trait indicates that the implementer may be registered and capable of /// probing. pub trait QueryDescriptor { /// Returns a list of descriptors. fn query() -> &'static [Descriptor]; /// Using the provided context buffer, score calculate and returns a value between 0 and 255 /// indicating the confidence of the reader in decoding or parsing the source stream. fn score(context: &[u8]) -> u8; } /// A `Hint` provides additional information and context when probing a media source stream. /// /// For example, the `Probe` cannot examine the extension or mime-type of the media because /// `MediaSourceStream` abstracts away such details. However, the embedder may have this information /// from a file path, HTTP header, email attachment metadata, etc. `Hint`s are optional, and won't /// lead the probe astray if they're wrong, but they may provide an informed initial guess and /// optimize the guessing process siginificantly especially as more formats are registered. #[derive(Clone, Debug, Default)] pub struct Hint { extension: Option, mime_type: Option, } impl Hint { /// Instantiate an empty `Hint`. pub fn new() -> Self { Hint { extension: None, mime_type: None } } /// Add a file extension `Hint`. pub fn with_extension(&mut self, extension: &str) -> &mut Self { self.extension = Some(extension.to_owned()); self } /// Add a MIME/Media-type `Hint`. pub fn mime_type(&mut self, mime_type: &str) -> &mut Self { self.mime_type = Some(mime_type.to_owned()); self } } /// Metadata that came from the `metadata` field of [`ProbeResult`]. pub struct ProbedMetadata { metadata: Option, } impl ProbedMetadata { /// Returns the metadata that was found during probing. /// /// If any additional metadata was present outside of the container, this is /// `Some` and the log will have at least one item in it. pub fn get(&mut self) -> Option> { self.metadata.as_mut().map(|m| m.metadata()) } /// Returns the inner metadata log, if it was present. pub fn into_inner(self) -> Option { self.metadata } } /// `ProbeResult` contains the result of a format probe operation. pub struct ProbeResult { /// An instance of a `FormatReader` for the probed format pub format: Box, /// A log of `Metadata` revisions read during the probe operation before the instantiation of /// the `FormatReader`. /// /// Metadata that was part of the container format itself can be read by calling `.metadata()` /// on `format`. pub metadata: ProbedMetadata, } /// `Probe` scans a `MediaSourceStream` for metadata and container formats, and provides an /// iterator-like interface to instantiate readers for the formats encountered. #[derive(Default)] pub struct Probe { filter: bloom::BloomFilter, registered: Vec, } impl Probe { const PROBE_SEARCH_LIMIT: u64 = 1 * 1024 * 1024; /// Register all `Descriptor`s supported by the parameterized type. pub fn register_all(&mut self) { for descriptor in Q::query() { self.register(descriptor); } } /// Register a single `Descriptor`. pub fn register(&mut self, descriptor: &Descriptor) { // Insert 2-byte prefixes for each marker into the bloom filter. for marker in descriptor.markers { let mut prefix = [0u8; 2]; match marker.len() { 2..=16 => prefix.copy_from_slice(&marker[0..2]), _ => panic!("invalid marker length (only 2-16 bytes supported)."), } self.filter.insert(&prefix); } self.registered.push(*descriptor); } /// Searches the provided `MediaSourceStream` for metadata or a container format. pub fn next(&self, mss: &mut MediaSourceStream) -> Result { let mut win = 0u16; let init_pos = mss.pos(); let mut count = 0; // Scan the stream byte-by-byte. Shifting each byte through a 2-byte window. while let Ok(byte) = mss.read_byte() { win = (win << 8) | u16::from(byte); count += 1; if count > Probe::PROBE_SEARCH_LIMIT { break; } if count % 4096 == 0 { debug!( "searching for format marker... {}+{} / {} bytes.", init_pos, count, Probe::PROBE_SEARCH_LIMIT ); } // Use the bloom filter to check if the the window may be a prefix of a registered // marker. if self.filter.may_contain(&win.to_be_bytes()) { // Using the 2-byte window, and a further 14 bytes, create a larger 16-byte window. let mut context = [0u8; 16]; context[0..2].copy_from_slice(&win.to_be_bytes()[0..2]); mss.read_buf_exact(&mut context[2..])?; debug!( "found a possible format marker within {:x?} @ {}+{} bytes.", context, init_pos, count, ); // Search for registered markers in the 16-byte window. for registered in &self.registered { for marker in registered.markers { let len = marker.len(); // If a match is found, return the instantiate. if context[0..len] == **marker { // Re-align the stream to the start of the marker. mss.seek_buffered_rev(16); // TODO: Implement scoring. info!( "found the format marker {:x?} @ {}+{} bytes.", &context[0..len], init_pos, count, ); return Ok(registered.inst); } } } // If no registered markers were matched, then the bloom filter returned a false // positive. Re-align the stream to the end of the 2-byte window and continue the // search. mss.seek_buffered_rev(16 - 2); } } if count < Probe::PROBE_SEARCH_LIMIT { error!("probe reach EOF at {} bytes.", count); } else { // Could not find any marker within the probe limit. error!("reached probe limit of {} bytes.", Probe::PROBE_SEARCH_LIMIT); } unsupported_error("core (probe): no suitable format reader found") } /// Searches the provided `MediaSourceStream` for a container format. Any metadata that is read /// during the search will be queued and attached to the `FormatReader` instance once a /// container format is found. pub fn format( &self, _hint: &Hint, mut mss: MediaSourceStream, format_opts: &FormatOptions, metadata_opts: &MetadataOptions, ) -> Result { let mut metadata: MetadataLog = Default::default(); // Loop over all elements in the stream until a container format is found. loop { match self.next(&mut mss)? { // If a container format is found, return an instance to it's reader. Instantiate::Format(fmt) => { let format = fmt(mss, format_opts)?; let metadata = if metadata.metadata().current().is_some() { Some(metadata) } else { None }; return Ok(ProbeResult { format, metadata: ProbedMetadata { metadata } }); } // If metadata was found, instantiate the metadata reader, read the metadata, and // push it onto the metadata log. Instantiate::Metadata(meta) => { let mut reader = meta(metadata_opts); metadata.push(reader.read_all(&mut mss)?); debug!("chaining a metadata element."); } } } // This function returns when either the end-of-stream is reached, an error occurs, or a // container format is found. } } /// Convenience macro for declaring a probe `Descriptor` for a `FormatReader`. #[macro_export] macro_rules! support_format { ($short_name:expr, $long_name:expr, $exts:expr, $mimes:expr, $markers:expr) => { Descriptor { short_name: $short_name, long_name: $long_name, extensions: $exts, mime_types: $mimes, markers: $markers, score: Self::score, inst: Instantiate::Format(|source, opt| Ok(Box::new(Self::try_new(source, &opt)?))), } }; } /// Convenience macro for declaring a probe `Descriptor` for a `MetadataReader`. #[macro_export] macro_rules! support_metadata { ($short_name:expr, $long_name:expr, $exts:expr, $mimes:expr, $markers:expr) => { Descriptor { short_name: $short_name, long_name: $long_name, extensions: $exts, mime_types: $mimes, markers: $markers, score: Self::score, inst: Instantiate::Metadata(|opt| Box::new(Self::new(&opt))), } }; } symphonia-core-0.5.4/src/sample.rs000064400000000000000000000305251046102023000152120ustar 00000000000000// Symphonia // Copyright (c) 2019-2022 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/. //! The `sample` module defines the core audio sample trait and any non-primitive sample data types. use std::fmt; use crate::util::clamp::{clamp_f32, clamp_f64, clamp_i24, clamp_u24}; /// SampleFormat describes the data encoding for an audio sample. #[derive(Copy, Clone, Debug)] pub enum SampleFormat { /// Unsigned 8-bit integer. U8, /// Unsigned 16-bit integer. U16, /// Unsigned 24-bit integer. U24, /// Unsigned 32-bit integer. U32, /// Signed 8-bit integer. S8, /// Signed 16-bit integer. S16, /// Signed 24-bit integer. S24, /// Signed 32-bit integer. S32, /// Single precision (32-bit) floating point. F32, /// Double precision (64-bit) floating point. F64, } /// `Sample` provides a common interface for manipulating sample's regardless of the /// underlying data type. Additionally, `Sample` provides information regarding the /// format of underlying data types representing the sample when in memory, but also /// when exported. pub trait Sample: Copy + Clone + core::ops::Add + core::ops::Sub + Default + PartialOrd + PartialEq + Sized { /// A unique enum value representing the sample format. This constant may be used to dynamically /// choose how to process the sample at runtime. const FORMAT: SampleFormat; /// The effective number of bits of the valid (clamped) sample range. Quantifies the dynamic /// range of the sample format in bits. const EFF_BITS: u32; /// The mid-point value between the maximum and minimum sample value. If a sample is set to this /// value it is silent. const MID: Self; /// If the sample format does not use the full range of the underlying data type, returns the /// sample clamped to the valid range. Otherwise, returns the sample unchanged. fn clamped(self) -> Self; } /// An unsigned 24-bit integer sample with an internal unsigned 32-bit integer representation. /// /// There are **no** guarantees the sample is within the valid range 24-bit range. Use the /// [`Sample::clamped`] function to clamp the sample to the valid range. #[allow(non_camel_case_types)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Default)] pub struct u24(pub u32); /// A signed 24-bit integer sample with an internal signed 32-bit integer representation. /// /// There are **no** guarantees the sample is within the valid range 24-bit range. Use the /// [`Sample::clamped`] function to clamp the sample to the valid range. #[allow(non_camel_case_types)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Default)] pub struct i24(pub i32); impl Sample for u8 { const FORMAT: SampleFormat = SampleFormat::U8; const EFF_BITS: u32 = 8; const MID: u8 = 128; #[inline(always)] fn clamped(self) -> Self { self } } impl Sample for i8 { const FORMAT: SampleFormat = SampleFormat::S8; const EFF_BITS: u32 = 8; const MID: i8 = 0; #[inline(always)] fn clamped(self) -> Self { self } } impl Sample for u16 { const FORMAT: SampleFormat = SampleFormat::U16; const EFF_BITS: u32 = 16; const MID: u16 = 32_768; #[inline(always)] fn clamped(self) -> Self { self } } impl Sample for i16 { const FORMAT: SampleFormat = SampleFormat::S16; const EFF_BITS: u32 = 16; const MID: i16 = 0; #[inline(always)] fn clamped(self) -> Self { self } } impl Sample for u24 { const FORMAT: SampleFormat = SampleFormat::U24; const EFF_BITS: u32 = 24; const MID: u24 = u24(8_388_608); #[inline(always)] fn clamped(self) -> Self { u24(clamp_u24(self.0)) } } impl Sample for i24 { const FORMAT: SampleFormat = SampleFormat::S24; const EFF_BITS: u32 = 24; const MID: i24 = i24(0); #[inline(always)] fn clamped(self) -> Self { i24(clamp_i24(self.0)) } } impl Sample for u32 { const FORMAT: SampleFormat = SampleFormat::U32; const EFF_BITS: u32 = 32; const MID: u32 = 2_147_483_648; #[inline(always)] fn clamped(self) -> Self { self } } impl Sample for i32 { const FORMAT: SampleFormat = SampleFormat::S32; const EFF_BITS: u32 = 32; const MID: i32 = 0; #[inline(always)] fn clamped(self) -> Self { self } } impl Sample for f32 { const FORMAT: SampleFormat = SampleFormat::F32; const EFF_BITS: u32 = 24; const MID: f32 = 0.0; #[inline(always)] fn clamped(self) -> Self { clamp_f32(self) } } impl Sample for f64 { const FORMAT: SampleFormat = SampleFormat::F64; const EFF_BITS: u32 = 53; const MID: f64 = 0.0; #[inline(always)] fn clamped(self) -> Self { clamp_f64(self) } } // Helper macros macro_rules! shl_impl { ($t:ident, $f:ty) => { impl core::ops::Shl<$f> for $t { type Output = $t; #[inline] fn shl(self, other: $f) -> $t { $t(self.0 << other) } } }; } macro_rules! shr_impl { ($t:ident, $f:ty) => { impl core::ops::Shr<$f> for $t { type Output = $t; #[inline] fn shr(self, other: $f) -> $t { $t(self.0 >> other) } } }; } macro_rules! impl_shifts { ($t:ident, $f:ty) => { shl_impl! { $t, $f } shr_impl! { $t, $f } }; } // Implementation for i24 impl i24 { /// The largest value that can be represented by this integer type. pub const MAX: i24 = i24(8_388_607); /// The smallest value that can be represented by this integer type.. pub const MIN: i24 = i24(-8_388_608); /// Get the underlying `i32` backing this `i24`. #[inline(always)] #[deprecated = "Superseded by `inner`."] pub fn into_i32(self) -> i32 { self.0 } /// Get the underlying `i32` backing this `i24`. #[inline(always)] pub fn inner(self) -> i32 { self.0 } /// Return the memory representation of this `i24` as a byte array in native byte order. #[inline] pub fn to_ne_bytes(self) -> [u8; 3] { let b = self.0.to_ne_bytes(); if cfg!(target_endian = "little") { // In little-endian the MSB is the last byte. Drop it. [b[0], b[1], b[2]] } else { // In big-endian the MSB is the first byte. Drop it. [b[1], b[2], b[3]] } } } impl fmt::Display for i24 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.0) } } impl From for i24 { fn from(val: i32) -> Self { i24(clamp_i24(val)) } } impl From for i24 { fn from(val: i16) -> Self { i24(i32::from(val)) } } impl From for i24 { fn from(val: i8) -> Self { i24(i32::from(val)) } } impl core::ops::Add for i24 { type Output = i24; #[inline] fn add(self, other: Self) -> Self { i24(self.0 + other.0) } } impl core::ops::Sub for i24 { type Output = i24; #[inline] fn sub(self, other: Self) -> Self { i24(self.0 - other.0) } } impl core::ops::Mul for i24 { type Output = i24; #[inline] fn mul(self, other: Self) -> Self { i24(self.0 * other.0) } } impl core::ops::Div for i24 { type Output = i24; #[inline] fn div(self, other: Self) -> Self { i24(self.0 / other.0) } } impl core::ops::Not for i24 { type Output = i24; #[inline] fn not(self) -> Self { i24(!self.0) } } impl core::ops::Rem for i24 { type Output = i24; #[inline] fn rem(self, other: Self) -> Self { i24(self.0 % other.0) } } impl core::ops::Shl for i24 { type Output = i24; #[inline] fn shl(self, other: Self) -> Self { i24(self.0 << other.0) } } impl core::ops::Shr for i24 { type Output = i24; #[inline] fn shr(self, other: Self) -> Self { i24(self.0 >> other.0) } } impl_shifts! { i24, u8 } impl_shifts! { i24, u16 } impl_shifts! { i24, u32 } impl_shifts! { i24, u64 } impl_shifts! { i24, u128 } impl_shifts! { i24, usize } impl_shifts! { i24, i8 } impl_shifts! { i24, i16 } impl_shifts! { i24, i32 } impl_shifts! { i24, i64 } impl_shifts! { i24, i128 } impl_shifts! { i24, isize } impl core::ops::BitAnd for i24 { type Output = i24; #[inline] fn bitand(self, other: Self) -> Self { i24(self.0 & other.0) } } impl core::ops::BitOr for i24 { type Output = i24; #[inline] fn bitor(self, other: Self) -> Self { i24(self.0 | other.0) } } impl core::ops::BitXor for i24 { type Output = i24; #[inline] fn bitxor(self, other: Self) -> Self { i24(self.0 ^ other.0) } } // Implementation for u24 impl u24 { /// The largest value that can be represented by this integer type. pub const MAX: u24 = u24(16_777_215); /// The smallest value that can be represented by this integer type. pub const MIN: u24 = u24(0); /// Get the underlying `u32` backing this `u24`. #[inline(always)] #[deprecated = "Superseded by `inner`."] pub fn into_u32(self) -> u32 { self.0 } /// Get the underlying `u32` backing this `u24`. #[inline(always)] pub fn inner(self) -> u32 { self.0 } /// Return the memory representation of this `u24` as a byte array in native byte order. #[inline] pub fn to_ne_bytes(self) -> [u8; 3] { let b = self.0.to_ne_bytes(); if cfg!(target_endian = "little") { // In little-endian the MSB is the last byte. Drop it. [b[0], b[1], b[2]] } else { // In big-endian the MSB is the first byte. Drop it. [b[1], b[2], b[3]] } } } impl fmt::Display for u24 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.0) } } impl From for u24 { fn from(val: u32) -> Self { u24(clamp_u24(val)) } } impl From for u24 { fn from(val: u16) -> Self { u24(u32::from(val)) } } impl From for u24 { fn from(val: u8) -> Self { u24(u32::from(val)) } } impl core::ops::Add for u24 { type Output = u24; #[inline] fn add(self, other: Self) -> Self { u24(self.0 + other.0) } } impl core::ops::Sub for u24 { type Output = u24; #[inline] fn sub(self, other: Self) -> Self { u24(self.0 - other.0) } } impl core::ops::Mul for u24 { type Output = u24; #[inline] fn mul(self, other: Self) -> Self { u24(self.0 * other.0) } } impl core::ops::Div for u24 { type Output = u24; #[inline] fn div(self, other: Self) -> Self { u24(self.0 / other.0) } } impl core::ops::Not for u24 { type Output = u24; #[inline] fn not(self) -> Self { u24(!self.0) } } impl core::ops::Rem for u24 { type Output = u24; #[inline] fn rem(self, other: Self) -> Self { u24(self.0 % other.0) } } impl core::ops::Shl for u24 { type Output = u24; #[inline] fn shl(self, other: Self) -> Self { u24(self.0 << other.0) } } impl core::ops::Shr for u24 { type Output = u24; #[inline] fn shr(self, other: Self) -> Self { u24(self.0 >> other.0) } } impl_shifts! { u24, u8 } impl_shifts! { u24, u16 } impl_shifts! { u24, u32 } impl_shifts! { u24, u64 } impl_shifts! { u24, u128 } impl_shifts! { u24, usize } impl_shifts! { u24, i8 } impl_shifts! { u24, i16 } impl_shifts! { u24, i32 } impl_shifts! { u24, i64 } impl_shifts! { u24, i128 } impl_shifts! { u24, isize } impl core::ops::BitAnd for u24 { type Output = u24; #[inline] fn bitand(self, other: Self) -> Self { u24(self.0 & other.0) } } impl core::ops::BitOr for u24 { type Output = u24; #[inline] fn bitor(self, other: Self) -> Self { u24(self.0 | other.0) } } impl core::ops::BitXor for u24 { type Output = u24; #[inline] fn bitxor(self, other: Self) -> Self { u24(self.0 ^ other.0) } } symphonia-core-0.5.4/src/units.rs000064400000000000000000000241551046102023000150750ustar 00000000000000// Symphonia // Copyright (c) 2019-2022 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/. //! The `units` module provides definitions for common units. use std::fmt; /// A `TimeStamp` represents an instantenous instant in time since the start of a stream. One /// `TimeStamp` "tick" is equivalent to the stream's `TimeBase` in seconds. pub type TimeStamp = u64; /// A `Duration` indicates a positive span of time. pub type Duration = u64; /// `Time` represents a duration of time in seconds, or the number of seconds since an arbitrary /// epoch. `Time` is stored as an integer number of seconds plus any remaining fraction of a second /// as a floating point value. #[derive(Copy, Clone, Debug, Default, PartialEq, PartialOrd)] pub struct Time { pub seconds: u64, pub frac: f64, } impl Time { const SECONDS_PER_MINUTE: u64 = 60; const SECONDS_PER_HOUR: u64 = 60 * 60; const NANOSECONDS_PER_SECOND: u32 = 1_000_000_000; const NANOSECONDS_PER_SECOND_INV: f64 = 1.0 / 1_000_000_000.0; pub fn new(seconds: u64, frac: f64) -> Self { Time { seconds, frac } } pub fn from_ss(s: u8, ns: u32) -> Option