symphonia-core-0.5.2/.cargo_vcs_info.json0000644000000001540000000000100137750ustar { "git": { "sha1": "412f44daab39920beeb81d78b0e4271b263d33e9" }, "path_in_vcs": "symphonia-core" }symphonia-core-0.5.2/Cargo.toml0000644000000023030000000000100117710ustar # 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.2" 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" symphonia-core-0.5.2/Cargo.toml.orig000064400000000000000000000011421046102023000154520ustar 00000000000000[package] name = "symphonia-core" version = "0.5.2" 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" [dependencies] arrayvec = "0.7.1" bitflags = "1.2.1" bytemuck = "1.7" lazy_static = "1.4.0" log = "0.4" symphonia-core-0.5.2/README.md000064400000000000000000000014451046102023000140500ustar 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 an open-source project and contributions are very welcome! If you would like to make a large contribution, please raise an issue ahead of time to make sure your efforts fit into the project goals, and that no duplication of efforts occurs. All contributors will be credited within the CONTRIBUTORS file. symphonia-core-0.5.2/src/audio.rs000064400000000000000000001306211046102023000150260ustar 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.2/src/checksum/crc16.rs000064400000000000000000000613731046102023000164540ustar 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.2/src/checksum/crc32.rs000064400000000000000000000763171046102023000164560ustar 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.2/src/checksum/crc8.rs000064400000000000000000000053661046102023000163750ustar 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.2/src/checksum/md5.rs000064400000000000000000000305711046102023000162170ustar 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.2/src/checksum/mod.rs000064400000000000000000000010351046102023000163020ustar 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.2/src/codecs.rs000064400000000000000000000530071046102023000151670ustar 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.2/src/conv.rs000075500000000000000000001213431046102023000146760ustar 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.2/src/dsp/complex.rs000064400000000000000000000104641046102023000161640ustar 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.2/src/dsp/fft.rs000064400000000000000000000462321046102023000152760ustar 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.2/src/dsp/mdct.rs000064400000000000000000000173121046102023000154430ustar 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. use super::complex::Complex; use super::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 (((&even, &odd), &w), t) in spec .iter() .step_by(2) .zip(spec.iter().rev().step_by(2)) .zip(self.twiddle.iter()) .zip(self.fft_in.iter_mut()) { 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. } } #[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.2/src/dsp/mod.rs000064400000000000000000000006461046102023000152750ustar 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.2/src/errors.rs000064400000000000000000000101501046102023000152330ustar 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.2/src/formats.rs000064400000000000000000000515561046102023000154110ustar 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.2/src/io/bit.rs000075500000000000000000002160621046102023000151210ustar 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, } 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(); // 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 mut 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 mut 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); } } // Generate Codebook's lookup table. let table = CodebookBuilder::generate_lut(self.bit_order, self.is_sparse, &blocks)?; Ok(Codebook { table }) } } } 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)> { debug_assert!(!codebook.is_empty()); let mut code_len = 0; let mut jmp_read_len = 0; let mut entry = codebook.table[0]; while entry.is_jump() { // Consume bits from the last jump. self.consume_bits(jmp_read_len); // Update decoded code length. code_len += jmp_read_len; // The length of the next run of bits to read. jmp_read_len = entry.jump_len(); let addr = self.get_bits() >> (u64::BITS - jmp_read_len); // Jump! let jmp_offset = entry.jump_offset(); entry = codebook.table[jmp_offset + addr as usize]; // The bit cache cannot fully service next lookup. Try to use the remaining bits (addr) // as a prefix. If it points to a value entry that has a code length that's <= the // remaining number of bits, then no further reads are necessary. if self.num_bits_left() < jmp_read_len { if entry.is_value() && entry.value_len() <= self.num_bits_left() { break; } // Fetch more bits without discarding the unconsumed bits. self.fetch_bits_partial()?; let addr = self.get_bits() >> (u64::BITS - jmp_read_len); entry = codebook.table[jmp_offset + addr as usize]; } } // Consume the bits from the value entry. let entry_code_len = entry.value_len(); self.consume_bits(entry_code_len); Ok((entry.value(), code_len + entry_code_len)) } } /// `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<()> { self.bits |= u64::from(self.reader.read_u8()?) << (u64::BITS - self.n_bits_left); self.n_bits_left += u8::BITS; 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> { 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); 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; 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) } /// 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)> { debug_assert!(!codebook.is_empty()); let mut code_len = 0; let mut jmp_read_len = 0; let mut entry = codebook.table[0]; while entry.is_jump() { // Consume bits from the last jump. self.consume_bits(jmp_read_len); // Update decoded code length. code_len += jmp_read_len; // The length of the next run of bits to read. jmp_read_len = entry.jump_len(); let addr = self.get_bits() & ((1 << jmp_read_len) - 1); // Jump! let jmp_offset = entry.jump_offset(); entry = codebook.table[jmp_offset + addr as usize]; // The bit cache cannot fully service next lookup. Try to use the remaining bits (addr) // as a prefix. If it points to a value entry that has a code length that's <= the // remaining number of bits, then no further reads are necessary. if self.num_bits_left() < jmp_read_len { if entry.is_value() && entry.value_len() <= self.num_bits_left() { break; } // Fetch more bits without discarding the unconsumed bits. self.fetch_bits_partial()?; let addr = self.get_bits() & ((1 << jmp_read_len) - 1); entry = codebook.table[jmp_offset + addr as usize]; } } // Consume the bits from the value entry. let entry_code_len = entry.value_len(); self.consume_bits(entry_code_len); Ok((entry.value(), code_len + entry_code_len)) } } /// `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<()> { self.bits |= u64::from(self.reader.read_u8()?) << self.n_bits_left; self.n_bits_left += u8::BITS; 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> { 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); 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; 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.2/src/io/buf_reader.rs000064400000000000000000000137511046102023000164360ustar 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.2/src/io/media_source_stream.rs000064400000000000000000000500721046102023000203470ustar 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.2/src/io/mod.rs000064400000000000000000000426711046102023000151220ustar 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.2/src/io/monitor_stream.rs000064400000000000000000000070221046102023000173740ustar 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.2/src/io/scoped_stream.rs000064400000000000000000000125701046102023000171660ustar 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.2/src/lib.rs000064400000000000000000000013661046102023000144760ustar 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.2/src/meta.rs000064400000000000000000000367451046102023000146670ustar 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)] 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)] 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. 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.2/src/probe.rs000064400000000000000000000323331046102023000150350ustar 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 % 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); } } // 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.2/src/sample.rs000064400000000000000000000305251046102023000152100ustar 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 prevision (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.2/src/units.rs000064400000000000000000000222141046102023000150650ustar 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