av-data-0.4.4/.cargo_vcs_info.json0000644000000001420000000000100123530ustar { "git": { "sha1": "5e5ec8d281d10ff6b6b7139ef798b21e1fff32ff" }, "path_in_vcs": "data" }av-data-0.4.4/CHANGELOG.md000064400000000000000000000010211046102023000127510ustar 00000000000000## Version 0.4.4 - Remove `thiserror` dependency ## Version 0.4.3 - Add Hash trait to some structs - Include LICENSE file in published crate ## Version 0.4.2 - Update num-derive from 0.3 to 0.4. ## Version 0.4.1 - Use initialized data for a frame. ## Version 0.4.0 - Upgrade to Rust edition 2021. - Improve documentation. - Pre-allocate planes. - Update `num-rational` crate requirement. - Update `bytes` crates. - Refactor `Frame`. - Add trait for copying to/from a buffer. - Fix colorspace error. - Fix an API misuse. av-data-0.4.4/Cargo.toml0000644000000021020000000000100103470ustar # 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 = "2021" name = "av-data" version = "0.4.4" authors = ["Luca Barbato "] build = false autobins = false autoexamples = false autotests = false autobenches = false description = "Multimedia data structures" homepage = "https://github.com/rust-av/rust-av" readme = "README.md" keywords = ["multimedia"] license = "MIT" [lib] name = "av_data" path = "src/lib.rs" [dependencies.byte-slice-cast] version = "1.2.1" [dependencies.bytes] version = "1.2.1" [dependencies.num-derive] version = "0.4" [dependencies.num-rational] version = "0.4.0" [dependencies.num-traits] version = "0.2.8" av-data-0.4.4/Cargo.toml.orig000064400000000000000000000006011046102023000140320ustar 00000000000000[package] name = "av-data" description = "Multimedia data structures" version = "0.4.4" authors = ["Luca Barbato "] license = "MIT" homepage = "https://github.com/rust-av/rust-av" keywords = ["multimedia"] readme = "README.md" edition = "2021" [dependencies] byte-slice-cast = "1.2.1" bytes = "1.2.1" num-rational = "0.4.0" num-traits = "0.2.8" num-derive = "0.4" av-data-0.4.4/LICENSE000064400000000000000000000020551046102023000121550ustar 00000000000000MIT License Copyright (c) 2017 Luca Barbato Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. av-data-0.4.4/README.md000064400000000000000000000017041046102023000124270ustar 00000000000000# Rust-AV datatypes [![LICENSE](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) [![Build Status](https://travis-ci.org/rust-av/rust-av.svg?branch=master)](https://travis-ci.org/rust-av/rust-av) [![Coverage Status](https://coveralls.io/repos/rust-av/rust-av/badge.svg?branch=master)](https://coveralls.io/r/rust-av/rust-av?branch=master) [![dependency status](https://deps.rs/repo/github/rust-av/rust-av/status.svg)](https://deps.rs/repo/github/rust-av/rust-av) [![IRC](https://img.shields.io/badge/irc-%23rust--av-blue.svg)](http://webchat.freenode.net?channels=%23rust-av&uio=d4) Pure-rust implementation of multimedia data primitives ## Status - [x] Basic types - [x] Pixel definition - [x] Audio Sample definition - [x] Timing Information - [x] Audio/Video Frame - [x] Data Packet - [x] Stream definition - [x] Plain Default allocator - [x] Self-describing Value abstraction - [ ] Documentation ## License MIT as per `LICENSE`. av-data-0.4.4/src/audiosample.rs000064400000000000000000000240261046102023000146120ustar 00000000000000//! Audio sample format definitions. use std::fmt; use std::string::*; /// Audio format definition. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct Soniton { /// Bits per sample. pub bits: u8, /// Tells if audio format is big-endian. pub be: bool, /// Audio samples are packed (e.g. 20-bit audio samples) and not padded. pub packed: bool, /// Audio data is stored in planar format /// (channels in sequence i.e. C1 C1 C1... C2 C2 C2) instead of interleaving /// samples (i.e. C1 C2 C1 C2) for different channels. pub planar: bool, /// Audio data is in floating point format. pub float: bool, /// Audio data is signed (usually only 8-bit audio is unsigned). pub signed: bool, } // TODO: make it a trait for usize? /// Aligns a value to a specific number of bytes. fn align(v: usize, a: usize) -> usize { (v + a - 1) & !(a - 1) } /// Returns the number of bytes necessary to represent the number of bits /// passed as input. fn round_to_byte(v: usize) -> usize { (v + 7) >> 3 } impl Soniton { /// Constructs a new audio format definition. pub fn new(bits: u8, be: bool, packed: bool, planar: bool, float: bool, signed: bool) -> Self { Soniton { bits, be, packed, planar, float, signed, } } /// Returns the amount of bytes needed to store /// the audio of requested length (in samples). pub fn get_audio_size(self, length: usize, alignment: usize) -> usize { let s = if self.packed { round_to_byte(length * (self.bits as usize)) } else { length * round_to_byte(self.bits as usize) }; align(s, alignment) } } impl fmt::Display for Soniton { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let fmt = if self.float { "float" } else if self.signed { "int" } else { "uint" }; let end = if self.be { "BE" } else { "LE" }; write!( f, "({} bps, {} planar: {} packed: {} {})", self.bits, end, self.packed, self.planar, fmt ) } } /// Known audio channel types. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[allow(clippy::upper_case_acronyms)] pub enum ChannelType { /// Center front. C, /// Left front. L, /// Right front. R, /// Center surround. Cs, /// Left surround. Ls, /// Right surround. Rs, /// Left surround side. Lss, /// Right surround side. Rss, /// Low Frequency Effect. LFE, /// Left center. Lc, /// Right center. Rc, /// Left height. Lh, /// Right height. Rh, /// Center height. Ch, /// Second Low Frequency Effect. LFE2, /// Left wide. Lw, /// Right wide. Rw, /// Overhead. /// /// Known also as: /// - Over the listener head (Oh) in DTS specification (ETSI TS 102.114) /// - Top Center Surround (Ts) in SMPTE 428-3-2006 specification Ov, /// Left height side. Lhs, /// Right height side. Rhs, /// Center height side. Chs, /// Left in the plane lower then listener's ears /// (DTS specification ETSI TS 102.114). Ll, /// Right in the plane lower then listener's ears /// (DTS specification ETSI TS 102.114). Rl, /// Center in the plane lower then listener's ears /// (DTS specification ETSI TS 102.114). Cl, /// Left total (SMPTE 428-3-2006 specification). Lt, /// Right total (SMPTE 428-3-2006 specification). Rt, /// Left-only downmix mode (Dolby ETSI TS 102.366 specification). Lo, /// Right-only downmix mode (Dolby ETSI TS 102.366 specification). Ro, } impl ChannelType { /// Tells whether the channel is some center channel. pub fn is_center(self) -> bool { matches!( self, ChannelType::C | ChannelType::Ch | ChannelType::Cl | ChannelType::Ov | ChannelType::LFE | ChannelType::LFE2 | ChannelType::Cs | ChannelType::Chs ) } /// Tells whether the channel is some left channel. pub fn is_left(self) -> bool { matches!( self, ChannelType::L | ChannelType::Ls | ChannelType::Lss | ChannelType::Lc | ChannelType::Lh | ChannelType::Lw | ChannelType::Lhs | ChannelType::Ll | ChannelType::Lt | ChannelType::Lo ) } /// Tells whether the channel is some right channel. pub fn is_right(self) -> bool { matches!( self, ChannelType::R | ChannelType::Rs | ChannelType::Rss | ChannelType::Rc | ChannelType::Rh | ChannelType::Rw | ChannelType::Rhs | ChannelType::Rl | ChannelType::Rt | ChannelType::Ro ) } } impl fmt::Display for ChannelType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let name = match *self { ChannelType::C => "C".to_string(), ChannelType::L => "L".to_string(), ChannelType::R => "R".to_string(), ChannelType::Cs => "Cs".to_string(), ChannelType::Ls => "Ls".to_string(), ChannelType::Rs => "Rs".to_string(), ChannelType::Lss => "Lss".to_string(), ChannelType::Rss => "Rss".to_string(), ChannelType::LFE => "LFE".to_string(), ChannelType::Lc => "Lc".to_string(), ChannelType::Rc => "Rc".to_string(), ChannelType::Lh => "Lh".to_string(), ChannelType::Rh => "Rh".to_string(), ChannelType::Ch => "Ch".to_string(), ChannelType::LFE2 => "LFE2".to_string(), ChannelType::Lw => "Lw".to_string(), ChannelType::Rw => "Rw".to_string(), ChannelType::Ov => "Ov".to_string(), ChannelType::Lhs => "Lhs".to_string(), ChannelType::Rhs => "Rhs".to_string(), ChannelType::Chs => "Chs".to_string(), ChannelType::Ll => "Ll".to_string(), ChannelType::Rl => "Rl".to_string(), ChannelType::Cl => "Cl".to_string(), ChannelType::Lt => "Lt".to_string(), ChannelType::Rt => "Rt".to_string(), ChannelType::Lo => "Lo".to_string(), ChannelType::Ro => "Ro".to_string(), }; write!(f, "{}", name) } } /// An ordered sequence of channels. #[derive(Clone, Debug, PartialEq, Eq, Default)] pub struct ChannelMap { ids: Vec, } impl ChannelMap { /// Creates a new sequence of channels. pub fn new() -> Self { ChannelMap { ids: Vec::new() } } /// Adds a single channel to the map. pub fn add_channel(&mut self, ch: ChannelType) { self.ids.push(ch); } /// Adds several channels to the map in order of occurrence. pub fn add_channels(&mut self, chs: &[ChannelType]) { for ch in chs { self.ids.push(*ch); } } /// Returns the total number of channels of the map. pub fn len(&self) -> usize { self.ids.len() } /// Tells if the channel map is empty. pub fn is_empty(&self) -> bool { self.ids.is_empty() } /// Gets the channel type for a requested index. pub fn get_channel(&self, idx: usize) -> ChannelType { self.ids[idx] } /// Tries to find the position of a determined type of channel in the map. pub fn find_channel_id(&self, t: ChannelType) -> Option { for i in 0..self.ids.len() { if self.ids[i] as i32 == t as i32 { return Some(i as u8); } } None } /// Creates a default channel map. /// /// Depending on the `count` value, the channel map is defined differently. /// /// When `count` is 1 --> the channel map is composed by a single centered /// channel. /// /// When `count` is 2 --> the channel map is composed by a right and a left /// channel respectively. /// /// For other `count` values, no other implementations are given for now. pub fn default_map(count: usize) -> Self { use self::ChannelType::*; let ids = match count { 1 => vec![C], 2 => vec![R, L], _ => unimplemented!(), }; ChannelMap { ids } } } /// A set of default constant channels for general use. pub mod formats { use super::*; /// Predefined format for interleaved 8-bit unsigned audio. pub const U8: Soniton = Soniton { bits: 8, be: false, packed: false, planar: false, float: false, signed: false, }; /// Predefined format for interleaved 16-bit signed audio. pub const S16: Soniton = Soniton { bits: 16, be: false, packed: false, planar: false, float: false, signed: true, }; /// Predefined format for interleaved 32-bit signed audio. pub const S32: Soniton = Soniton { bits: 32, be: false, packed: false, planar: false, float: false, signed: true, }; /// Predefined format for interleaved floating points 32-bit signed audio. pub const F32: Soniton = Soniton { bits: 32, be: false, packed: false, planar: false, float: true, signed: true, }; /// Predefined format for interleaved floating points 64-bit signed audio. pub const F64: Soniton = Soniton { bits: 64, be: false, packed: false, planar: false, float: true, signed: true, }; } #[cfg(test)] mod test { use super::*; #[test] fn fmt() { println!("{}", formats::S16); println!("{}", formats::U8); println!("{}", formats::F32); } } av-data-0.4.4/src/frame.rs000064400000000000000000000445701046102023000134070ustar 00000000000000//! Packets and decoded frames functionality. #![allow(dead_code, unused_variables)] use std::convert::From; use std::fmt; use std::ptr::copy_nonoverlapping; use std::sync::Arc; use byte_slice_cast::*; use bytes::BytesMut; use crate::audiosample::*; use crate::pixel::*; use crate::timeinfo::*; use self::FrameError::*; /// Frame errors. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum FrameError { /// Invalid frame index. InvalidIndex, /// Invalid frame conversion. InvalidConversion, } impl std::error::Error for FrameError {} impl fmt::Display for FrameError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { InvalidIndex => write!(f, "Invalid Index"), InvalidConversion => write!(f, "Invalid Conversion"), } } } // TODO: Change it to provide Droppable/Seekable information or use a separate enum? /// A list of recognized frame types. #[derive(Clone, Debug, PartialEq, Eq, Hash)] #[allow(clippy::upper_case_acronyms)] pub enum FrameType { /// Intra frame type. I, /// Inter frame type. P, /// Bidirectionally predicted frame. B, /// Skip frame. /// /// When such frame is encountered, then last frame should be used again /// if it is needed. SKIP, /// Some other frame type. OTHER, } impl fmt::Display for FrameType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { FrameType::I => write!(f, "I"), FrameType::P => write!(f, "P"), FrameType::B => write!(f, "B"), FrameType::SKIP => write!(f, "Skip"), FrameType::OTHER => write!(f, "x"), } } } /// Video stream information. #[derive(Clone, Debug)] pub struct VideoInfo { /// Frame width. pub width: usize, /// Frame height. pub height: usize, /// Frame is stored downside up. pub flipped: bool, /// Frame type. pub frame_type: FrameType, /// Frame pixel format. pub format: Arc, /// Declared bits per sample. pub bits: u8, } impl VideoInfo { /// Constructs a new `VideoInfo` instance. pub fn new( width: usize, height: usize, flipped: bool, frame_type: FrameType, format: Arc, ) -> Self { let bits = format.get_total_depth(); VideoInfo { width, height, flipped, frame_type, format, bits, } } /// Returns frame width. pub fn get_width(&self) -> usize { self.width } /// Returns frame height. pub fn get_height(&self) -> usize { self.height } /// Returns frame orientation. pub fn is_flipped(&self) -> bool { self.flipped } /// Returns frame type. pub fn get_frame_type(&self) -> &FrameType { &self.frame_type } /// Returns frame pixel format. pub fn get_format(&self) -> Formaton { *self.format } /// Sets new frame width. pub fn set_width(&mut self, width: usize) { self.width = width; } /// Sets new frame height. pub fn set_height(&mut self, height: usize) { self.height = height; } /// Returns video stream size with the specified alignment. pub fn size(&self, align: usize) -> usize { let mut size = 0; for &component in self.format.into_iter() { if let Some(c) = component { size += c.get_data_size(self.width, self.height, align); } } size } } impl fmt::Display for VideoInfo { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}x{}", self.width, self.height) } } impl PartialEq for VideoInfo { fn eq(&self, info2: &VideoInfo) -> bool { self.width == info2.width && self.height == info2.height && self.format == info2.format } } /// Audio stream information contained in a frame. #[derive(Clone, Debug)] pub struct AudioInfo { /// Number of samples. pub samples: usize, /// Sample rate. pub sample_rate: usize, /// Sequence of stream channels. pub map: ChannelMap, /// Audio sample format. pub format: Arc, /// Length of one audio block in samples. /// /// None if not present. pub block_len: Option, } impl AudioInfo { /// Constructs a new `AudioInfo` instance. pub fn new( samples: usize, sample_rate: usize, map: ChannelMap, format: Arc, block_len: Option, ) -> Self { AudioInfo { samples, sample_rate, map, format, block_len, } } /// Returns audio sample rate. pub fn get_sample_rate(&self) -> usize { self.sample_rate } /// Returns the number of channels. pub fn get_channels_number(&self) -> usize { self.map.len() } /// Returns sample format. pub fn get_format(&self) -> Soniton { *self.format } /// Returns number of samples. pub fn get_samples(&self) -> usize { self.samples } /// Returns one audio block duration in samples. pub fn get_block_len(&self) -> Option { self.block_len } /// Returns audio stream size with the specified alignment. pub fn size(&self, align: usize) -> usize { self.format.get_audio_size(self.samples, align) * self.map.len() } } impl fmt::Display for AudioInfo { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, "{} Hz, {} ch", self.sample_rate, self.get_channels_number() ) } } impl PartialEq for AudioInfo { fn eq(&self, info2: &AudioInfo) -> bool { self.sample_rate == info2.sample_rate && self.map == info2.map && self.format == info2.format } } /// A list of possible stream information types. #[derive(Clone, Debug, PartialEq)] pub enum MediaKind { /// Video codec information. Video(VideoInfo), /// Audio codec information. Audio(AudioInfo), } impl MediaKind { /// Returns video stream information. pub fn get_video_info(&self) -> Option { if let MediaKind::Video(vinfo) = self { Some(vinfo.clone()) } else { None } } /// Returns audio stream information. pub fn get_audio_info(&self) -> Option { if let MediaKind::Audio(ainfo) = self { Some(ainfo.clone()) } else { None } } /// Reports whether the current stream is a video stream. pub fn is_video(&self) -> bool { matches!(self, MediaKind::Video(_)) } /// Reports whether the current stream is an audio stream. pub fn is_audio(&self) -> bool { matches!(self, MediaKind::Audio(_)) } } impl fmt::Display for MediaKind { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let ret = match self { MediaKind::Audio(fmt) => format!("{}", fmt), MediaKind::Video(fmt) => format!("{}", fmt), }; write!(f, "{}", ret) } } impl From for MediaKind { fn from(v: VideoInfo) -> Self { MediaKind::Video(v) } } impl From for MediaKind { fn from(a: AudioInfo) -> Self { MediaKind::Audio(a) } } /// A series of methods to interact with the planes of frame. pub trait FrameBuffer: Send + Sync { /// Returns the linesize (stride) of the idx-th frame plane. fn linesize(&self, idx: usize) -> Result; /// Counts the number of frame planes. fn count(&self) -> usize; /// Returns an immutable buffer with the data associated to the idx-th /// frame plane. fn as_slice_inner(&self, idx: usize) -> Result<&[u8], FrameError>; /// Returns a mutable buffer with the data associated to the idx-th /// frame plane. fn as_mut_slice_inner(&mut self, idx: usize) -> Result<&mut [u8], FrameError>; } mod private { use byte_slice_cast::*; pub trait Supported: FromByteSlice {} impl Supported for u8 {} impl Supported for i16 {} impl Supported for f32 {} } /// A series of methods to get mutable and immutable slices of datatype `T` /// from frame planes. pub trait FrameBufferConv: FrameBuffer { /// Returns an immutable slice of datatype `T` with the data associated to /// the idx-th frame plane. fn as_slice(&self, idx: usize) -> Result<&[T], FrameError> { self.as_slice_inner(idx)? .as_slice_of::() .map_err(|e| InvalidConversion) } /// Returns a mutable slice of datatype `T` with the data associated to /// the idx-th frame plane. fn as_mut_slice(&mut self, idx: usize) -> Result<&mut [T], FrameError> { self.as_mut_slice_inner(idx)? .as_mut_slice_of::() .map_err(|e| InvalidConversion) } } impl FrameBufferConv for dyn FrameBuffer {} impl FrameBufferConv for dyn FrameBuffer {} impl FrameBufferConv for dyn FrameBuffer {} /// A series of methods to copy the content of a frame from or to a buffer. pub trait FrameBufferCopy { /// Copies a determined plane to an output buffer. fn copy_plane_to_buffer(&self, plane_index: usize, dst: &mut [u8], dst_linesize: usize); /// Copies a frame to an output buffer. fn copy_frame_to_buffer<'a, IM: Iterator, IU: Iterator>( &self, dst: IM, dst_linesizes: IU, ); /// Copies from a slice into a frame. fn copy_from_slice<'a, I: Iterator, IU: Iterator>( &mut self, src: I, src_linesize: IU, ); } impl fmt::Debug for dyn FrameBuffer { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "FrameBuffer") } } const ALIGNMENT: usize = 32; struct Plane { buf: BytesMut, linesize: usize, } struct DefaultFrameBuffer { buf: BytesMut, planes: Vec, } impl FrameBuffer for DefaultFrameBuffer { fn linesize(&self, idx: usize) -> Result { match self.planes.get(idx) { None => Err(FrameError::InvalidIndex), Some(plane) => Ok(plane.linesize), } } fn count(&self) -> usize { self.planes.len() } fn as_slice_inner(&self, idx: usize) -> Result<&[u8], FrameError> { match self.planes.get(idx) { None => Err(FrameError::InvalidIndex), Some(plane) => Ok(&plane.buf), } } fn as_mut_slice_inner(&mut self, idx: usize) -> Result<&mut [u8], FrameError> { match self.planes.get_mut(idx) { None => Err(FrameError::InvalidIndex), Some(plane) => Ok(&mut plane.buf), } } } impl DefaultFrameBuffer { pub fn new(kind: &MediaKind) -> DefaultFrameBuffer { match *kind { MediaKind::Video(ref video) => { let size = video.size(ALIGNMENT); let buf = BytesMut::zeroed(size); let mut buffer = DefaultFrameBuffer { buf, planes: Vec::with_capacity(video.format.get_num_comp()), }; for &component in video.format.iter() { if let Some(c) = component { let planesize = c.get_data_size(video.width, video.height, ALIGNMENT); let linesize = c.get_linesize(video.width, ALIGNMENT); buffer.planes.push(Plane { buf: buffer.buf.split_to(planesize), linesize, }); } } buffer } MediaKind::Audio(ref audio) => { let size = audio.size(ALIGNMENT); let buf = BytesMut::zeroed(size); let mut buffer = DefaultFrameBuffer { buf, planes: if audio.format.planar { Vec::with_capacity(audio.map.len()) } else { Vec::with_capacity(1) }, }; if audio.format.planar { for _ in 0..audio.map.len() { let size = audio.format.get_audio_size(audio.samples, ALIGNMENT); buffer.planes.push(Plane { buf: buffer.buf.split_to(size), linesize: size, }); } } else { buffer.planes.push(Plane { buf: buffer.buf.split_to(size), linesize: size, }); } buffer } } } } /// Decoded frame information. #[derive(Debug)] pub struct Frame { /// The kind of frame (audio or video). pub kind: MediaKind, /// Frame buffer containing the data associated to each plane. pub buf: Box, /// Timestamp information associated to a frame. pub t: TimeInfo, } impl Frame { /// Creates a new frame. pub fn new_default_frame(kind: T, t: Option) -> Self where T: Into + Clone, { let k = kind.into(); let buf = DefaultFrameBuffer::new(&k); Self { kind: k, buf: Box::new(buf), t: t.unwrap_or_default(), } } } impl FrameBufferCopy for Frame { fn copy_plane_to_buffer(&self, plane_index: usize, dst: &mut [u8], dst_linesize: usize) { if let MediaKind::Video(ref fmt) = self.kind { let width = fmt.width; let height = fmt.height; let src = self.buf.as_slice_inner(plane_index).unwrap(); let src_linesize = self.buf.linesize(plane_index).unwrap(); copy_plane(dst, dst_linesize, src, src_linesize, width, height); } else { unimplemented!(); } } fn copy_frame_to_buffer<'a, IM, IU>(&self, dst: IM, dst_linesizes: IU) where IM: Iterator, IU: Iterator, { if let MediaKind::Video(ref fmt) = self.kind { let width = fmt.width; let height = fmt.height; let dst_iter = dst.zip(dst_linesizes); let iter = dst_iter.zip(0..self.buf.count()).zip(fmt.format.iter()); for (((d, d_linesize), plane_index), c) in iter { copy_plane( d, d_linesize, self.buf.as_slice_inner(plane_index).unwrap(), self.buf.linesize(plane_index).unwrap(), c.unwrap().get_width(width), c.unwrap().get_height(height), ); } } else { unimplemented!() } } // TODO: Add proper tests /// Copies from a slice into a frame. fn copy_from_slice<'a, I, IU>(&mut self, mut src: I, mut src_linesize: IU) where I: Iterator, IU: Iterator, { if let MediaKind::Video(ref fmt) = self.kind { let mut f_iter = fmt.format.iter(); let width = fmt.width; let height = fmt.height; for i in 0..self.buf.count() { let d_linesize = self.buf.linesize(i).unwrap(); let s_linesize = src_linesize.next().unwrap(); let data = self.buf.as_mut_slice(i).unwrap(); let ss = src.next().unwrap(); let cc = f_iter.next().unwrap(); copy_plane( data, d_linesize, ss, s_linesize, cc.unwrap().get_width(width), cc.unwrap().get_height(height), ); } } else { unimplemented!(); } } } fn copy_plane( dst: &mut [u8], dst_linesize: usize, src: &[u8], src_linesize: usize, width: usize, height: usize, ) { let dst_chunks = dst.chunks_mut(dst_linesize); let src_chunks = src.chunks(src_linesize); for (d, s) in dst_chunks.zip(src_chunks).take(height) { // SAFETY: // dst and src slices are initialized. unsafe { copy_nonoverlapping(s.as_ptr(), d.as_mut_ptr(), width); } } } /// A specialized type for reference-counted `Frame` pub type ArcFrame = Arc; #[cfg(test)] mod test { use super::*; use crate::audiosample::formats; #[test] fn test_format_cmp() { let mut map = ChannelMap::new(); map.add_channel(ChannelType::C); let sn = Arc::new(formats::S16); let info1 = AudioInfo::new(42, 48000, map.clone(), sn, None); let sn = Arc::new(formats::S16); let info2 = AudioInfo::new(4242, 48000, map.clone(), sn, None); assert!(info1 == info2); let mut map = ChannelMap::new(); map.add_channel(ChannelType::C); let sn = Arc::new(formats::S16); let info1 = AudioInfo::new(42, 48000, map.clone(), sn, None); let sn = Arc::new(formats::S32); let info2 = AudioInfo::new(42, 48000, map.clone(), sn, None); assert!(!(info1 == info2)); } use crate::pixel::formats::{RGB565, YUV420}; #[test] fn test_video_format_cmp() { let yuv420: Formaton = *YUV420; let fm = Arc::new(yuv420); let info1 = VideoInfo::new(42, 42, false, FrameType::I, fm); let yuv420: Formaton = *YUV420; let fm = Arc::new(yuv420); let info2 = VideoInfo::new(42, 42, false, FrameType::P, fm); assert!(info1 == info2); let yuv420: Formaton = *YUV420; let fm = Arc::new(yuv420); let info1 = VideoInfo::new(42, 42, false, FrameType::I, fm); let rgb565: Formaton = *RGB565; let fm = Arc::new(rgb565); let info2 = VideoInfo::new(42, 42, false, FrameType::I, fm); assert!(!(info1 == info2)); } #[test] #[should_panic] fn test_frame_copy_from_slice() { let yuv420: Formaton = *YUV420; let fm = Arc::new(yuv420); let video_info = VideoInfo::new(42, 42, false, FrameType::I, fm); let mut frame = Frame::new_default_frame(MediaKind::Video(video_info), None); frame.copy_from_slice( vec![vec![0].as_slice(); 2].into_iter(), vec![40; 2].into_iter(), ); } } av-data-0.4.4/src/lib.rs000064400000000000000000000005331046102023000130520ustar 00000000000000//! Structs and traits to interact with multimedia data. #![deny(missing_docs, clippy::undocumented_unsafe_blocks)] /// A module to represent and interact with rational numbers. pub mod rational { pub use num_rational::*; } pub mod audiosample; pub mod frame; pub mod packet; pub mod params; pub mod pixel; pub mod timeinfo; pub mod value; av-data-0.4.4/src/packet.rs000064400000000000000000000060751046102023000135620ustar 00000000000000//! Packets definitions. #![allow(dead_code)] use crate::timeinfo::TimeInfo; use std::io::{Read, Result, Write}; /// Packet with compressed data. #[derive(Default, Debug, Clone)] pub struct Packet { /// Packet data. pub data: Vec, /// Packet position in the stream. /// /// If `None`, the packet is not associated to a stream. pub pos: Option, /// Type of stream the packet is associated to. pub stream_index: isize, /// Packet timestamp information. pub t: TimeInfo, /// Tells whether a packet contains a keyframe. pub is_key: bool, /// Tells whether a packet is corrupted. pub is_corrupted: bool, } impl Packet { /// Creates a new empty `Packet` of a determined capacity. pub fn with_capacity(capacity: usize) -> Self { Packet { data: Vec::with_capacity(capacity), t: TimeInfo::default(), pos: None, stream_index: -1, is_key: false, is_corrupted: false, } } /// Creates a zero-initalized `Packet` of a determined capacity. pub fn zeroed(size: usize) -> Self { Packet { data: vec![0; size], t: TimeInfo::default(), pos: None, stream_index: -1, is_key: false, is_corrupted: false, } } /// Creates a new empty `Packet`. pub fn new() -> Self { Self::with_capacity(0) } } /// Used to read a packet from a source. pub trait ReadPacket: Read { /// Reads a packet from a source. fn get_packet(&mut self, len: usize) -> Result { let mut pkt = Packet::zeroed(len); self.read_exact(pkt.data.as_mut_slice())?; Ok(pkt) } } /// Used to write a packet into a source. pub trait WritePacket: Write { /// Writes a packet into a source. fn put_packet(&mut self, pkt: Packet) -> Result<()> { self.write_all(pkt.data.as_slice()) } } impl ReadPacket for R {} impl WritePacket for W {} use std::sync::Arc; /// A specialized type for a thread-safe reference-counting pointer `Packet`. pub type ArcPacket = Arc; #[cfg(test)] mod test { use super::*; use std::io::Cursor; #[test] fn read_packet() { let data: Vec = (0..128).collect(); let mut buf = Cursor::new(data.clone()); match buf.get_packet(64) { Ok(pkt) => assert_eq!(pkt.data, &data[..64]), _ => unreachable!(), } } /*#[test] fn test_new(){ let pkt = Packet::new(); assert_eq!(0, pkt.data.len()); }*/ #[test] fn write_packet() { let size = 1024; let mut buf = Cursor::new(Vec::with_capacity(size)); let mut pkt = Packet::with_capacity(size); for i in 0..size { pkt.data.push(i as u8); } buf.put_packet(pkt).unwrap(); let vec = buf.into_inner(); for (i, elem) in vec.iter().enumerate().take(size) { println!("{}", elem); assert!(*elem == i as u8); } } } av-data-0.4.4/src/params.rs000064400000000000000000000026361046102023000135750ustar 00000000000000//! Video and audio definitions. use crate::audiosample::{ChannelMap, Soniton}; use crate::pixel::Formaton; use std::sync::Arc; /// Video stream information. #[derive(Clone, Debug, PartialEq, Eq)] pub struct VideoInfo { /// Picture width. pub width: usize, /// Picture height. pub height: usize, /// Picture pixel format. pub format: Option>, } /// Audio stream information. #[derive(Clone, Debug, PartialEq, Eq)] pub struct AudioInfo { /// Audio sample rate. pub rate: usize, /// Audio sequence of channels. pub map: Option, /// Audio sample format. pub format: Option>, } /// Possible stream information types. #[derive(Clone, Debug, PartialEq, Eq)] pub enum MediaKind { /// Video codec information. Video(VideoInfo), /// Audio codec information. Audio(AudioInfo), } /// Possible codec parameters. #[derive(Clone, Debug, PartialEq, Eq)] pub struct CodecParams { /// Stream information type. pub kind: Option, /// Codec id. pub codec_id: Option, /// Codec additional data. pub extradata: Option>, /// Codec bit-rate. pub bit_rate: usize, /// Number of samples the decoder must process /// before outputting valid data. pub convergence_window: usize, /// Number of samples the codec needs to process /// before returning data. pub delay: usize, } av-data-0.4.4/src/pixel.rs000064400000000000000000001167111046102023000134330ustar 00000000000000//! Expose all necessary data structures to represent pixels. //! //! Re-exports num_traits::FromPrimitive and num_traits::cast::ToPrimitive //! in order to make easy to cast a parsed value into correct enum structures. use num_derive::{FromPrimitive, ToPrimitive}; pub use num_traits::cast::ToPrimitive; pub use num_traits::FromPrimitive; use std::fmt; use std::ops::Index; use std::slice; /// YUV color range. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[allow(clippy::upper_case_acronyms)] pub enum YUVRange { /// Pixels in the range [16, 235]. Limited, /// Pixels in the range [0, 255]. Full, } impl fmt::Display for YUVRange { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { YUVRange::Limited => write!(f, "Limited range"), YUVRange::Full => write!(f, "Full range"), } } } /// Describes the matrix coefficients used in deriving /// luma and chroma signals from the green, blue and red or X, Y and Z primaries. /// /// Values adopted from Table 4 of ISO/IEC 23001-8:2013/DCOR1. #[allow(clippy::upper_case_acronyms)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, FromPrimitive, ToPrimitive)] pub enum MatrixCoefficients { /// The identity matrix. /// Typically used for: /// /// - GBR (often referred to as RGB) /// - YZX (often referred to as XYZ) /// - IEC 61966-2-1 sRGB /// - SMPTE ST 428-1 (2019) Identity = 0, /// - Rec. ITU-R BT.709-6 /// - Rec. ITU-R BT.1361-0 conventional colour gamut system and extended colour /// gamut system (historical) /// - IEC 61966-2-4 xvYCC709 /// - SMPTE RP 177 (1993) Annex B BT709 = 1, /// Image characteristics are unknown or are determined by the application. Unspecified = 2, /// For future use by ITU-T | ISO/IEC. Reserved = 3, /// United States Federal Communications Commission (2003) Title 47 Code of /// Federal Regulations 73.682 (a) (20) BT470M = 4, /// - Rec. ITU-R BT.470-6 System B, G (historical) /// - Rec. ITU-R BT.601-7 625 /// - Rec. ITU-R BT.1358-0 625 (historical) /// - Rec. ITU-R BT.1700-0 625 PAL and 625 SECAM /// - IEC 61966-2-1 sYCC /// - IEC 61966-2-4 xvYCC601 /// /// (functionally the same as the value 6) BT470BG = 5, /// - Rec. ITU-R BT.601-7 525 /// - Rec. ITU-R BT.1358-1 525 or 625 (historical) /// - Rec. ITU-R BT.1700-0 NTSC /// - SMPTE ST 170 (2004) /// /// (functionally the same as the value 5) ST170M = 6, /// SMPTE ST 240 (1999) ST240M = 7, /// The YCoCg color model, also known as the YCgCo color model, /// is the color space formed from a simple transformation of /// an associated RGB color space into a luma value and /// two chroma values called chrominance green and chrominance orange. YCgCo = 8, /// - Rec. ITU-R BT.2020-2 (non-constant luminance) /// - Rec. ITU-R BT.2100-2 Y′CbCr BT2020NonConstantLuminance = 9, /// Rec. ITU-R BT.2020-2 (constant luminance) BT2020ConstantLuminance = 10, /// SMPTE ST 2085 (2015) ST2085 = 11, /// Chromaticity-derived non-constant luminance system. ChromaticityDerivedNonConstantLuminance = 12, /// Chromaticity-derived constant luminance system. ChromaticityDerivedConstantLuminance = 13, /// Rec. ITU-R BT.2100-2 ICTCP ICtCp = 14, } impl fmt::Display for MatrixCoefficients { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { MatrixCoefficients::Identity => write!(f, "Identity"), MatrixCoefficients::BT709 => write!(f, "ITU BT.709"), MatrixCoefficients::Unspecified => write!(f, "Unspecified"), MatrixCoefficients::Reserved => write!(f, "Reserved"), MatrixCoefficients::BT470M => write!(f, "ITU BT.470M"), MatrixCoefficients::BT470BG => write!(f, "ITU BT.470BG"), MatrixCoefficients::ST170M => write!(f, "SMPTE ST-170M"), MatrixCoefficients::ST240M => write!(f, "SMPTE ST-240M"), MatrixCoefficients::YCgCo => write!(f, "YCgCo"), MatrixCoefficients::BT2020NonConstantLuminance => { write!(f, "ITU BT.2020 (Non Constant Luminance)") } MatrixCoefficients::BT2020ConstantLuminance => { write!(f, "ITU BT.2020 (Constant Luminance)") } MatrixCoefficients::ST2085 => write!(f, "SMPTE ST-2085"), MatrixCoefficients::ChromaticityDerivedNonConstantLuminance => { write!(f, "Chromaticity Derived (Non ConstantLuminance)") } MatrixCoefficients::ChromaticityDerivedConstantLuminance => { write!(f, "Chromaticity Derived (Constant Luminance)") } MatrixCoefficients::ICtCp => write!(f, "ICtCp"), } } } /// Indicates the chromaticity coordinates of the source colour primaries as specified in Table 2 in terms /// of the CIE 1931 definition of x and y as specified by ISO 11664-1. /// /// Values adopted from Table 4 of ISO/IEC 23001-8:2013/DCOR1. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, FromPrimitive, ToPrimitive)] #[allow(clippy::upper_case_acronyms)] pub enum ColorPrimaries { /// For future use by ITU-T | ISO/IEC. Reserved0 = 0, /// - Rec. ITU-R BT.709-6 /// - Rec. ITU-R BT.1361-0 conventional colour gamut /// system and extended colour gamut system (historical) /// - IEC 61966-2-1 sRGB or sYCC /// - IEC 61966-2-4 /// - Society of Motion Picture and Television Engineers /// (SMPTE) RP 177 (1993) Annex B BT709 = 1, /// Image characteristics are unknown or are determined by /// the application. Unspecified = 2, /// For future use by ITU-T | ISO/IEC. Reserved = 3, /// - Rec. ITU-R BT.470-6 System M (historical) /// - United States National Television System Committee /// 1953 Recommendation for transmission standards for /// color television /// - United States Federal Communications Commission /// (2003) Title 47 Code of Federal Regulations 73.682 (a) (20) BT470M = 4, /// - Rec. ITU-R BT.470-6 System B, G (historical) /// - Rec. ITU-R BT.601-7 625 /// - Rec. ITU-R BT.1358-0 625 (historical) /// - Rec. ITU-R BT.1700-0 625 PAL and 625 SECAM BT470BG = 5, /// - Rec. ITU-R BT.601-7 525 /// - Rec. ITU-R BT.1358-1 525 or 625 (historical) /// - Rec. ITU-R BT.1700-0 NTSC /// - SMPTE ST 170 (2004) /// /// (functionally the same as the value 7) ST170M = 6, /// - SMPTE ST 240 (1999) /// /// (functionally the same as the value 6) ST240M = 7, /// Generic film (colour filters using Illuminant C) Film = 8, /// - Rec. ITU-R BT.2020-2 /// - Rec. ITU-R BT.2100-2 BT2020 = 9, /// - SMPTE ST 428-1 (2019) /// - (CIE 1931 XYZ as in ISO 11664-1) ST428 = 10, /// SMPTE RP 431-2 (2011) P3DCI = 11, /// SMPTE EG 432-1 (2010) P3Display = 12, /// No corresponding industry specification identified. Tech3213 = 22, } impl fmt::Display for ColorPrimaries { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { ColorPrimaries::Reserved0 => write!(f, "Identity"), ColorPrimaries::BT709 => write!(f, "ITU BT.709"), ColorPrimaries::Unspecified => write!(f, "Unspecified"), ColorPrimaries::Reserved => write!(f, "Reserved"), ColorPrimaries::BT470M => write!(f, "ITU BT.470M"), ColorPrimaries::BT470BG => write!(f, "ITU BT.470BG"), ColorPrimaries::ST170M => write!(f, "SMPTE ST-170M"), ColorPrimaries::ST240M => write!(f, "SMPTE ST-240M"), ColorPrimaries::Film => write!(f, "Film"), ColorPrimaries::BT2020 => write!(f, "ITU BT.2020"), ColorPrimaries::ST428 => write!(f, "SMPTE ST-428"), ColorPrimaries::P3DCI => write!(f, "DCI P3"), ColorPrimaries::P3Display => write!(f, "Display P3"), ColorPrimaries::Tech3213 => write!(f, "EBU Tech3213"), } } } /// Either indicates the reference opto-electronic transfer characteristic /// function of the source picture as a function of a source input linear optical intensity /// input Lc with a nominal real-valued range of 0 to 1 or indicates the inverse of the /// reference electro-optical transfer characteristic function as a function of an /// output linear optical intensity Lo with a nominal real-valued range of 0 to 1. /// /// Values adopted from Table 4 of ISO/IEC 23001-8:2013/DCOR1. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, FromPrimitive, ToPrimitive)] #[allow(clippy::upper_case_acronyms)] pub enum TransferCharacteristic { /// For future use by ITU-T | ISO/IEC. Reserved0 = 0, /// - Rec. ITU-R BT.709-6 /// - Rec. ITU-R BT.1361-0 conventional /// colour gamut system (historical) /// /// (functionally the same as the values 6, 14 and 15) BT1886 = 1, /// Image characteristics are unknown or /// are determined by the application. Unspecified = 2, /// For future use by ITU-T | ISO/IEC. Reserved = 3, /// Assumed display gamma 2.2. /// /// - Rec. ITU-R BT.470-6 System M /// (historical) /// - United States National Television /// System Committee 1953 /// Recommendation for transmission /// standards for color television /// - United States Federal Communications /// Commission (2003) Title 47 Code of /// Federal Regulations 73.682 (a) (20) /// - Rec. ITU-R BT.1700-0 625 PAL and /// 625 SECAM BT470M = 4, /// Assumed display gamma 2.8. /// /// Rec. ITU-R BT.470-6 System B, G (historical) BT470BG = 5, /// - Rec. ITU-R BT.601-7 525 or 625 /// - Rec. ITU-R BT.1358-1 525 or 625 /// (historical) /// - Rec. ITU-R BT.1700-0 NTSC /// - SMPTE ST 170 (2004) /// /// (functionally the same as the values 1, 14 and 15) ST170M = 6, /// SMPTE ST 240 (1999) ST240M = 7, /// Linear transfer characteristics Linear = 8, /// Logarithmic transfer characteristic /// (100:1 range) Logarithmic100 = 9, /// Logarithmic transfer characteristic /// (100 * Sqrt( 10 ) : 1 range) Logarithmic316 = 10, /// IEC 61966-2-4 XVYCC = 11, /// Rec. ITU-R BT.1361-0 extended /// colour gamut system (historical) BT1361E = 12, /// - IEC 61966-2-1 sRGB (with /// MatrixCoefficients equal to 0) /// - IEC 61966-2-1 sYCC (with /// MatrixCoefficients equal to 5) SRGB = 13, /// Rec. ITU-R BT.2020-2 (10-bit system) /// /// (functionally the same as the values 1, 6 and 15) BT2020Ten = 14, /// Rec. ITU-R BT.2020-2 (12-bit system) /// /// (functionally the same as the values 1, 6 and 14) BT2020Twelve = 15, /// - SMPTE ST 2084 (2014) for 10-, 12-, /// 14- and 16-bit systems /// - Rec. ITU-R BT.2100-2 perceptual /// quantization (PQ) system PerceptualQuantizer = 16, /// SMPTE ST 428-1 (2019) ST428 = 17, /// - ARIB STD-B67 (2015) /// - Rec. ITU-R BT.2100-2 hybrid log- /// gamma (HLG) system HybridLogGamma = 18, } impl fmt::Display for TransferCharacteristic { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { TransferCharacteristic::Reserved0 => write!(f, "Identity"), TransferCharacteristic::BT1886 => write!(f, "ITU BT.1886"), TransferCharacteristic::Unspecified => write!(f, "Unspecified"), TransferCharacteristic::Reserved => write!(f, "Reserved"), TransferCharacteristic::BT470M => write!(f, "ITU BT.470M"), TransferCharacteristic::BT470BG => write!(f, "ITU BT.470BG"), TransferCharacteristic::ST170M => write!(f, "SMPTE ST-170M"), TransferCharacteristic::ST240M => write!(f, "SMPTE ST-240M"), TransferCharacteristic::Linear => write!(f, "Linear"), TransferCharacteristic::Logarithmic100 => write!(f, "Logarithmic 100:1 range"), TransferCharacteristic::Logarithmic316 => write!(f, "Logarithmic 316:1 range"), TransferCharacteristic::XVYCC => write!(f, "XVYCC"), TransferCharacteristic::BT1361E => write!(f, "ITU BT.1361 Extended Color Gamut"), TransferCharacteristic::SRGB => write!(f, "sRGB"), TransferCharacteristic::BT2020Ten => write!(f, "ITU BT.2020 for 10bit systems"), TransferCharacteristic::BT2020Twelve => write!(f, "ITU BT.2020 for 12bit systems"), TransferCharacteristic::PerceptualQuantizer => write!(f, "Perceptual Quantizer"), TransferCharacteristic::ST428 => write!(f, "SMPTE ST-428"), TransferCharacteristic::HybridLogGamma => write!(f, "Hybrid Log-Gamma"), } } } /// Indicates the chroma sampling grid alignment for video fields or frames using the 4:2:0 /// colour format (in which the two chroma arrays have half the width /// and half the height of the associated luma array) /// /// Values adopted from Table 4 of ISO/IEC 23001-8:2013/DCOR1. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[allow(missing_docs)] pub enum ChromaLocation { Unspecified = 0, Left, Center, TopLeft, Top, BottomLeft, Bottom, } impl fmt::Display for ChromaLocation { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use self::ChromaLocation::*; match *self { Unspecified => write!(f, "Unspecified"), Left => write!(f, "Left"), Center => write!(f, "Center"), TopLeft => write!(f, "TopLeft"), Top => write!(f, "Top"), BottomLeft => write!(f, "BottomLeft"), Bottom => write!(f, "Bottom"), } } } /// All YUV color representations. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[allow(clippy::upper_case_acronyms)] pub enum YUVSystem { /// YCbCr is a family of color spaces used as a part of the color image pipeline /// in video and digital photography systems. Y′ is the luma component and CB and CR /// are the blue-difference and red-difference chroma components. YCbCr(YUVRange), /// The YCoCg color model, also known as the YCgCo color model, /// is the color space formed from a simple transformation of /// an associated RGB color space into a luma value and /// two chroma values called chrominance green and chrominance orange. YCoCg, /// ICtCp is a color representation format specified in the Rec. ITU-R BT.2100 standard /// that is used as a part of the color image pipeline in video and digital photography /// systems for high dynamic range (HDR) and wide color gamut (WCG) imagery. ICtCp, } impl fmt::Display for YUVSystem { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use self::YUVSystem::*; match *self { YCbCr(range) => write!(f, "YCbCr ({})", range), YCoCg => write!(f, "YCbCg"), ICtCp => write!(f, "ICtCp"), } } } /// Trichromatic color encoding system. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[allow(clippy::upper_case_acronyms)] pub enum TrichromaticEncodingSystem { /// Image represented by three color channels: Red, Green, and Blue. RGB, /// Image represented by a luminance (luma) channel and two chroma channels. YUV(YUVSystem), /// In the CIE 1931 model, Y is the luminance, Z is quasi-equal to blue (of CIE RGB), /// and X is a mix of the three CIE RGB curves chosen to be nonnegative. /// Setting Y as luminance has the useful result that for any given Y value, /// the XZ plane will contain all possible chromaticities at that luminance. XYZ, } impl fmt::Display for TrichromaticEncodingSystem { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use self::TrichromaticEncodingSystem::*; match *self { YUV(system) => write!(f, "{}", system), RGB => write!(f, "RGB"), XYZ => write!(f, "XYZ"), } } } /// All supported color models. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[allow(clippy::upper_case_acronyms)] pub enum ColorModel { /// An image represented by three channels or planes: Includes RGB, YUV, and XYZ. Trichromatic(TrichromaticEncodingSystem), /// The CMYK color model is a subtractive color model, based on the CMY color model, /// used in color printing, and is also used to describe the printing process itself. /// CMYK refers to the four ink plates used in some color printing: cyan, magenta, yellow, and key. CMYK, /// HSL and HSV are alternative representations of the RGB color model, /// designed in the 1970s by computer graphics researchers to more closely align /// with the way human vision perceives color-making attributes. HSV, /// The CIELAB color space expresses color as three values: /// L* for perceptual lightness, and a* and b* for the four unique colors of human vision: /// red, green, blue, and yellow. LAB, } impl fmt::Display for ColorModel { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { ColorModel::Trichromatic(system) => write!(f, "{}", system), ColorModel::CMYK => write!(f, "CMYK"), ColorModel::HSV => write!(f, "HSV"), ColorModel::LAB => write!(f, "LAB"), } } } impl ColorModel { /// Returns the number of components of a color model. pub fn get_default_components(self) -> usize { match self { ColorModel::CMYK => 4, _ => 3, } } } /// Single colorspace component definition. /// /// Defines how the components of a colorspace are subsampled and /// where and how they are stored. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct Chromaton { /// Horizontal subsampling in power of two /// (e.g. `0` = no subsampling, `1` = only every second value is stored). pub h_ss: u8, /// Vertical subsampling in power of two /// (e.g. `0` = no subsampling, `1` = only every second value is stored). pub v_ss: u8, /// Tells if a component is packed. pub packed: bool, /// Bit depth of a component. pub depth: u8, /// Shift for packed components. pub shift: u8, /// Component offset for byte-packed components. pub comp_offs: u8, /// The distance to the next packed element in bytes. pub next_elem: u8, } fn align(v: usize, a: usize) -> usize { (v + a - 1) & !(a - 1) } impl Chromaton { /// Constructs a new `Chromaton` instance. pub const fn new( h_ss: u8, v_ss: u8, packed: bool, depth: u8, shift: u8, comp_offs: u8, next_elem: u8, ) -> Self { Chromaton { h_ss, v_ss, packed, depth, shift, comp_offs, next_elem, } } /// Constructs a specific `Chromaton` instance for `yuv8`. pub const fn yuv8(h_ss: u8, v_ss: u8, comp_offs: u8) -> Chromaton { Chromaton::new(h_ss, v_ss, false, 8, 0, comp_offs, 1) } /// Constructs a specific `Chromaton` instance for `yuvhb`. pub const fn yuvhb(h_ss: u8, v_ss: u8, depth: u8, comp_offs: u8) -> Chromaton { Chromaton::new(h_ss, v_ss, false, depth, 0, comp_offs, 1) } /// Constructs a specific `Chromaton` instance for `packrgb`. pub const fn packrgb(depth: u8, shift: u8, comp_offs: u8, next_elem: u8) -> Chromaton { Chromaton::new(0, 0, true, depth, shift, comp_offs, next_elem) } /// Constructs a specific `Chromaton` instance for `pal8`. pub const fn pal8(comp_offs: u8) -> Chromaton { Chromaton::new(0, 0, true, 8, 0, comp_offs, 3) } /// Returns the subsampling of a component. pub fn get_subsampling(self) -> (u8, u8) { (self.h_ss, self.v_ss) } /// Tells whether a component is packed. pub fn is_packed(self) -> bool { self.packed } /// Returns the bit depth of a component. pub fn get_depth(self) -> u8 { self.depth } /// Returns the bit shift of a packed component. pub fn get_shift(self) -> u8 { self.shift } /// Returns the byte offset of a packed component. pub fn get_offset(self) -> u8 { self.comp_offs } /// Returns the byte offset to the next element of a packed component. pub fn get_step(self) -> u8 { self.next_elem } /// Calculates the width for a component from general image width. pub fn get_width(self, width: usize) -> usize { (width + ((1 << self.h_ss) - 1)) >> self.h_ss } /// Calculates the height for a component from general image height. pub fn get_height(self, height: usize) -> usize { (height + ((1 << self.v_ss) - 1)) >> self.v_ss } /// Calculates the minimal stride for a component from general image width. pub fn get_linesize(self, width: usize, alignment: usize) -> usize { let d = self.depth as usize; align((self.get_width(width) * d + d - 1) >> 3, alignment) } /// Calculates the required image size in pixels for a component /// from general image width. pub fn get_data_size(self, width: usize, height: usize, align: usize) -> usize { let nh = (height + ((1 << self.v_ss) - 1)) >> self.v_ss; self.get_linesize(width, align) * nh } } impl fmt::Display for Chromaton { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let pfmt = if self.packed { let mask = ((1 << self.depth) - 1) << self.shift; format!( "packed(+{},{:X}, step {})", self.comp_offs, mask, self.next_elem ) } else { format!("planar({},{})", self.comp_offs, self.next_elem) }; write!(f, "({}x{}, {})", self.h_ss, self.v_ss, pfmt) } } /// Image colorspace representation. /// /// Includes both definitions for each component and some common definitions. /// /// For example, the format can be paletted, so the components describe /// the palette storage format, while the actual data is 8-bit palette indices. #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] pub struct Formaton { /// Image color model. pub model: ColorModel, /// Image color primaries. pub primaries: ColorPrimaries, /// Image transfer characteristic. pub xfer: TransferCharacteristic, /// Image matrix coefficients. pub matrix: MatrixCoefficients, /// Image chroma location. pub chroma_location: ChromaLocation, /// Actual number of components present. pub components: u8, /// Format definition for each component. pub comp_info: [Option; 5], /// Single pixel size for packed formats. pub elem_size: u8, /// Tells if data is stored as big-endian. pub be: bool, /// Tells if image has alpha component. pub alpha: bool, /// Tells if data is paletted. pub palette: bool, } impl Formaton { /// Constructs a new instance of `Formaton`. pub fn new( model: ColorModel, components: &[Chromaton], elem_size: u8, be: bool, alpha: bool, palette: bool, ) -> Self { let mut c: [Option; 5] = [None; 5]; if components.len() > 5 { panic!("too many components"); } for (i, v) in components.iter().enumerate() { c[i] = Some(*v); } Formaton { model, primaries: ColorPrimaries::Unspecified, xfer: TransferCharacteristic::Unspecified, matrix: MatrixCoefficients::Unspecified, chroma_location: ChromaLocation::Unspecified, components: components.len() as u8, comp_info: c, elem_size, be, alpha, palette, } } /// Returns current color model. pub fn get_model(&self) -> ColorModel { self.model } /// Returns current image primaries. pub fn get_primaries(&self) -> ColorPrimaries { self.primaries } /// Returns the total amount of bits needed for components. pub fn get_total_depth(&self) -> u8 { let mut depth = 0; for chromaton in self.comp_info.iter().flatten() { depth += chromaton.depth; } depth } /// Sets current image primaries. pub fn set_primaries(mut self, pc: ColorPrimaries) { self.primaries = pc; } /// Sets current image primaries from `u32`. pub fn set_primaries_from_u32(mut self, pc: u32) -> Option { let parsed_pc = ColorPrimaries::from_u32(pc); if let Some(pc) = parsed_pc { self.primaries = pc } parsed_pc } /// Returns current image transfer characteristic. pub fn get_xfer(&self) -> TransferCharacteristic { self.xfer } /// Sets current image transfer characteristic. pub fn set_xfer(mut self, pc: TransferCharacteristic) { self.xfer = pc; } /// Sets current image transfer characteristic from `u32`. pub fn set_xfer_from_u32(mut self, tc: u32) -> Option { let parsed_tc = TransferCharacteristic::from_u32(tc); if let Some(tc) = parsed_tc { self.xfer = tc } parsed_tc } /// Returns current image matrix coefficients. pub fn get_matrix(&self) -> MatrixCoefficients { self.matrix } /// Sets current image matrix coefficients. pub fn set_matrix(mut self, mc: MatrixCoefficients) { self.matrix = mc; } /// Sets current image matrix coefficients from `u32`. pub fn set_matrix_from_u32(mut self, mc: u32) -> Option { let parsed_mc = MatrixCoefficients::from_u32(mc); if let Some(mc) = parsed_mc { self.matrix = mc } parsed_mc } /// Returns the number of components. pub fn get_num_comp(&self) -> usize { self.components as usize } /// Returns selected component information. pub fn get_chromaton(&self, idx: usize) -> Option { if idx < self.comp_info.len() { return self.comp_info[idx]; } None } /// Reports whether the packing format is big-endian. pub fn is_be(&self) -> bool { self.be } /// Reports whether a colorspace has an alpha component. pub fn has_alpha(&self) -> bool { self.alpha } /// Reports whether this is a paletted format. pub fn is_paletted(&self) -> bool { self.palette } /// Returns single packed pixel size. pub fn get_elem_size(&self) -> u8 { self.elem_size } /// Returns an iterator over the format definition of each component. pub fn iter(&self) -> slice::Iter> { self.comp_info.iter() } } impl<'a> Index for &'a Formaton { type Output = Option; fn index(&self, index: usize) -> &Self::Output { self.comp_info.index(index) } } impl<'a> IntoIterator for &'a Formaton { type Item = &'a Option; type IntoIter = slice::Iter<'a, Option>; fn into_iter(self) -> Self::IntoIter { self.comp_info.iter() } } impl fmt::Display for Formaton { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let end = if self.be { "BE" } else { "LE" }; let palstr = if self.palette { "palette " } else { "" }; let astr = if self.alpha { "alpha " } else { "" }; let mut str = format!( "Formaton for {} ({}{}elem {} size {}): ", self.model, palstr, astr, end, self.elem_size ); for &i in self.into_iter() { if let Some(chr) = i { str = format!("{} {}", str, chr); } } write!(f, "[{}]", str) } } pub mod formats { //! //! Ready-to-use formaton //! use self::ColorModel::*; use self::TrichromaticEncodingSystem::*; use self::YUVRange::*; use self::YUVSystem::*; use crate::pixel::*; /// Predefined format for planar 8-bit YUV with 4:4:4 subsampling. pub const YUV444: &Formaton = &Formaton { model: Trichromatic(YUV(YCbCr(Limited))), primaries: ColorPrimaries::Unspecified, xfer: TransferCharacteristic::Unspecified, matrix: MatrixCoefficients::Unspecified, chroma_location: ChromaLocation::Unspecified, components: 3, comp_info: [ Some(Chromaton::new(0, 0, false, 8, 0, 0, 1)), Some(Chromaton::yuv8(0, 0, 1)), Some(Chromaton::yuv8(0, 0, 2)), None, None, ], elem_size: 0, be: false, alpha: false, palette: false, }; /// Predefined format for planar 8-bit YUV with 4:2:2 subsampling. pub const YUV422: &Formaton = &Formaton { model: Trichromatic(YUV(YCbCr(Limited))), primaries: ColorPrimaries::Unspecified, xfer: TransferCharacteristic::Unspecified, matrix: MatrixCoefficients::Unspecified, chroma_location: ChromaLocation::Unspecified, components: 3, comp_info: [ Some(Chromaton::new(0, 0, false, 8, 0, 0, 1)), Some(Chromaton::yuv8(0, 1, 1)), Some(Chromaton::yuv8(0, 1, 2)), None, None, ], elem_size: 0, be: false, alpha: false, palette: false, }; /// Predefined format for planar 8-bit YUV with 4:2:0 subsampling. pub const YUV420: &Formaton = &Formaton { model: Trichromatic(YUV(YCbCr(Limited))), primaries: ColorPrimaries::Unspecified, xfer: TransferCharacteristic::Unspecified, matrix: MatrixCoefficients::Unspecified, chroma_location: ChromaLocation::Unspecified, components: 3, comp_info: [ Some(Chromaton::new(0, 0, false, 8, 0, 0, 1)), Some(Chromaton::yuv8(1, 1, 1)), Some(Chromaton::yuv8(1, 1, 2)), None, None, ], elem_size: 0, be: false, alpha: false, palette: false, }; /// Predefined format for planar 8-bit YUV with 4:1:1 subsampling. pub const YUV411: &Formaton = &Formaton { model: Trichromatic(YUV(YCbCr(Limited))), primaries: ColorPrimaries::Unspecified, xfer: TransferCharacteristic::Unspecified, matrix: MatrixCoefficients::Unspecified, chroma_location: ChromaLocation::Unspecified, components: 3, comp_info: [ Some(Chromaton::new(0, 0, false, 8, 0, 0, 1)), Some(Chromaton::yuv8(2, 0, 1)), Some(Chromaton::yuv8(2, 0, 2)), None, None, ], elem_size: 0, be: false, alpha: false, palette: false, }; /// Predefined format for planar 8-bit YUV with 4:1:0 subsampling. pub const YUV410: &Formaton = &Formaton { model: Trichromatic(YUV(YCbCr(Limited))), primaries: ColorPrimaries::Unspecified, xfer: TransferCharacteristic::Unspecified, matrix: MatrixCoefficients::Unspecified, chroma_location: ChromaLocation::Unspecified, components: 3, comp_info: [ Some(Chromaton::new(0, 0, false, 8, 0, 0, 1)), Some(Chromaton::yuv8(2, 1, 1)), Some(Chromaton::yuv8(2, 1, 2)), None, None, ], elem_size: 0, be: false, alpha: false, palette: false, }; /// Predefined format for planar 10-bit YUV with 4:4:4 subsampling. pub const YUV444_10: &Formaton = &Formaton { model: Trichromatic(YUV(YCbCr(Limited))), primaries: ColorPrimaries::Unspecified, xfer: TransferCharacteristic::Unspecified, matrix: MatrixCoefficients::Unspecified, chroma_location: ChromaLocation::Unspecified, components: 3, comp_info: [ Some(Chromaton::new(0, 0, false, 10, 0, 0, 1)), Some(Chromaton::yuvhb(0, 0, 1, 10)), Some(Chromaton::yuvhb(0, 0, 2, 10)), None, None, ], elem_size: 0, be: false, alpha: false, palette: false, }; /// Predefined format for planar 10-bit YUV with 4:2:2 subsampling. pub const YUV422_10: &Formaton = &Formaton { model: Trichromatic(YUV(YCbCr(Limited))), primaries: ColorPrimaries::Unspecified, xfer: TransferCharacteristic::Unspecified, matrix: MatrixCoefficients::Unspecified, chroma_location: ChromaLocation::Unspecified, components: 3, comp_info: [ Some(Chromaton::new(0, 0, false, 10, 0, 0, 1)), Some(Chromaton::yuvhb(0, 1, 1, 10)), Some(Chromaton::yuvhb(0, 1, 2, 10)), None, None, ], elem_size: 0, be: false, alpha: false, palette: false, }; /// Predefined format for planar 10-bit YUV with 4:2:0 subsampling. pub const YUV420_10: &Formaton = &Formaton { model: Trichromatic(YUV(YCbCr(Limited))), primaries: ColorPrimaries::Unspecified, xfer: TransferCharacteristic::Unspecified, matrix: MatrixCoefficients::Unspecified, chroma_location: ChromaLocation::Unspecified, components: 3, comp_info: [ Some(Chromaton::new(0, 0, false, 10, 0, 0, 1)), Some(Chromaton::yuvhb(1, 1, 1, 10)), Some(Chromaton::yuvhb(1, 1, 2, 10)), None, None, ], elem_size: 0, be: false, alpha: false, palette: false, }; /// Predefined format for planar 10-bit YUV with 4:1:1 subsampling. pub const YUV411_10: &Formaton = &Formaton { model: Trichromatic(YUV(YCbCr(Limited))), primaries: ColorPrimaries::Unspecified, xfer: TransferCharacteristic::Unspecified, matrix: MatrixCoefficients::Unspecified, chroma_location: ChromaLocation::Unspecified, components: 3, comp_info: [ Some(Chromaton::new(0, 0, false, 10, 0, 0, 1)), Some(Chromaton::yuvhb(2, 0, 1, 10)), Some(Chromaton::yuvhb(2, 0, 2, 10)), None, None, ], elem_size: 0, be: false, alpha: false, palette: false, }; /// Predefined format for planar 10-bit YUV with 4:1:0 subsampling. pub const YUV410_10: &Formaton = &Formaton { model: Trichromatic(YUV(YCbCr(Limited))), primaries: ColorPrimaries::Unspecified, xfer: TransferCharacteristic::Unspecified, matrix: MatrixCoefficients::Unspecified, chroma_location: ChromaLocation::Unspecified, components: 3, comp_info: [ Some(Chromaton::new(0, 0, false, 10, 0, 0, 1)), Some(Chromaton::yuvhb(2, 1, 1, 10)), Some(Chromaton::yuvhb(2, 1, 2, 10)), None, None, ], elem_size: 0, be: false, alpha: false, palette: false, }; /// Predefined format with RGB24 palette. pub const PAL8: &Formaton = &Formaton { model: Trichromatic(RGB), primaries: ColorPrimaries::Unspecified, xfer: TransferCharacteristic::Unspecified, matrix: MatrixCoefficients::Unspecified, chroma_location: ChromaLocation::Unspecified, components: 3, comp_info: [ Some(Chromaton::pal8(0)), Some(Chromaton::pal8(1)), Some(Chromaton::pal8(2)), None, None, ], elem_size: 3, be: false, alpha: false, palette: true, }; /// Predefined format for RGB565 packed video. pub const RGB565: &Formaton = &Formaton { model: Trichromatic(RGB), primaries: ColorPrimaries::Unspecified, xfer: TransferCharacteristic::Unspecified, matrix: MatrixCoefficients::Unspecified, chroma_location: ChromaLocation::Unspecified, components: 3, comp_info: [ Some(Chromaton::packrgb(5, 11, 0, 2)), Some(Chromaton::packrgb(6, 5, 0, 2)), Some(Chromaton::packrgb(5, 0, 0, 2)), None, None, ], elem_size: 2, be: false, alpha: false, palette: false, }; /// Predefined format for RGB24. pub const RGB24: &Formaton = &Formaton { model: Trichromatic(RGB), primaries: ColorPrimaries::Unspecified, xfer: TransferCharacteristic::Unspecified, matrix: MatrixCoefficients::Unspecified, chroma_location: ChromaLocation::Unspecified, components: 3, comp_info: [ Some(Chromaton::packrgb(8, 0, 2, 3)), Some(Chromaton::packrgb(8, 0, 1, 3)), Some(Chromaton::packrgb(8, 0, 0, 3)), None, None, ], elem_size: 3, be: false, alpha: false, palette: false, }; /// Predefined format for RGBA. pub const RGBA: &Formaton = &Formaton { model: Trichromatic(RGB), primaries: ColorPrimaries::Unspecified, xfer: TransferCharacteristic::Unspecified, matrix: MatrixCoefficients::Unspecified, chroma_location: ChromaLocation::Unspecified, components: 4, comp_info: [ Some(Chromaton::packrgb(8, 0, 3, 4)), Some(Chromaton::packrgb(8, 0, 2, 4)), Some(Chromaton::packrgb(8, 0, 1, 4)), Some(Chromaton::packrgb(8, 0, 0, 4)), None, ], elem_size: 4, be: false, alpha: true, palette: false, }; /// Predefined format for RGB48. pub const RGB48: &Formaton = &Formaton { model: Trichromatic(RGB), primaries: ColorPrimaries::Unspecified, xfer: TransferCharacteristic::Unspecified, matrix: MatrixCoefficients::Unspecified, chroma_location: ChromaLocation::Unspecified, components: 3, comp_info: [ Some(Chromaton::packrgb(16, 0, 2, 6)), Some(Chromaton::packrgb(16, 0, 1, 6)), Some(Chromaton::packrgb(16, 0, 0, 6)), None, None, ], elem_size: 6, be: false, alpha: false, palette: false, }; /// Predefined format for RGBA64. pub const RGBA64: &Formaton = &Formaton { model: Trichromatic(RGB), primaries: ColorPrimaries::Unspecified, xfer: TransferCharacteristic::Unspecified, matrix: MatrixCoefficients::Unspecified, chroma_location: ChromaLocation::Unspecified, components: 4, comp_info: [ Some(Chromaton::packrgb(16, 0, 3, 8)), Some(Chromaton::packrgb(16, 0, 2, 8)), Some(Chromaton::packrgb(16, 0, 1, 8)), Some(Chromaton::packrgb(16, 0, 0, 8)), None, ], elem_size: 8, be: false, alpha: true, palette: false, }; } #[cfg(test)] mod test { mod formats { use super::super::*; #[test] fn fmt() { println!("formaton yuv- {}", formats::YUV420); println!("formaton pal- {}", formats::PAL8); println!("formaton rgb565- {}", formats::RGB565); println!("formaton rgba- {}", formats::RGBA); println!("formaton rgb48- {}", formats::RGB48); println!("formaton rgba64- {}", formats::RGBA64); } #[test] fn comparison() { use std::sync::Arc; let rcf = Arc::new(*formats::YUV420); let cf = &formats::YUV420.clone(); if cf != formats::YUV420 { panic!("cf"); } if *rcf != *formats::YUV420 { panic!("rcf"); } } } } av-data-0.4.4/src/timeinfo.rs000064400000000000000000000013271046102023000141200ustar 00000000000000//! Time info definitions for frames and packets. use crate::rational::Rational64; use std::any::Any; use std::sync::Arc; /// Timestamp information for frames and packets. #[derive(Debug, Clone, Default)] pub struct TimeInfo { /// Presentation timestamp. pub pts: Option, /// Decode timestamp. pub dts: Option, /// Duration (in timebase units). pub duration: Option, /// Timebase numerator/denominator (i.e 1/75th of a second). /// /// Its value does not vary among frames/packets, since it is /// computed and defined at stream level. pub timebase: Option, /// Timebase user private data. pub user_private: Option>, } av-data-0.4.4/src/value.rs000064400000000000000000000030561046102023000134230ustar 00000000000000//! Option values definitions. use crate::audiosample::Soniton; use crate::pixel::Formaton; use std::convert::From; use std::sync::Arc; /// Accepted option values. #[derive(Debug)] pub enum Value<'a> { /// Signed integer value. I64(i64), /// Unsigned integer value. U64(u64), /// Unicode string slice value. Str(&'a str), /// Boolean value. Bool(bool), /// Pair of signed integer values. Pair(i64, i64), /// Image colorspace representation value. Formaton(Arc), /// Audio format definition value. Soniton(Arc), } impl<'a> From for Value<'a> { fn from(v: i64) -> Self { Value::I64(v) } } impl<'a> From for Value<'a> { fn from(v: u64) -> Self { Value::U64(v) } } impl<'a> From<&'a str> for Value<'a> { fn from(v: &'a str) -> Self { Value::Str(v) } } impl<'a> From for Value<'a> { fn from(v: bool) -> Self { Value::Bool(v) } } impl<'a> From<(i64, i64)> for Value<'a> { fn from(v: (i64, i64)) -> Self { Value::Pair(v.0, v.1) } } impl<'a> From> for Value<'a> { fn from(v: Arc) -> Self { Value::Formaton(v) } } impl<'a> From> for Value<'a> { fn from(v: Arc) -> Self { Value::Soniton(v) } } #[cfg(test)] mod test { use super::*; use std::fmt::Debug; fn p<'a, T>(v: T) where T: Into> + Debug, { println!("{:?}", v); } #[test] fn value_str() { p("test"); } }