use std::fmt;
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct FourCc(pub [u8; 4]);
impl FourCc {
pub const fn new(bytes: [u8; 4]) -> Self {
Self(bytes)
}
pub const fn into_bytes(self) -> [u8; 4] {
self.0
}
pub fn as_lossy_str(&self) -> String {
String::from_utf8_lossy(&self.0).into_owned()
}
}
impl Default for FourCc {
fn default() -> Self {
Self(*b" ")
}
}
impl From<[u8; 4]> for FourCc {
fn from(value: [u8; 4]) -> Self {
Self(value)
}
}
impl TryFrom<&str> for FourCc {
type Error = &'static str;
fn try_from(value: &str) -> Result<Self, Self::Error> {
let bytes: [u8; 4] = value
.as_bytes()
.try_into()
.map_err(|_| "a fourcc must contain four bytes")?;
Ok(Self(bytes))
}
}
impl fmt::Display for FourCc {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for byte in self.0 {
if byte.is_ascii_graphic() || byte == b' ' {
write!(f, "{}", char::from(byte))?;
} else {
write!(f, "\\x{byte:02x}")?;
}
}
Ok(())
}
}
impl fmt::Debug for FourCc {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "FourCc({self})")
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
pub struct TrackId(pub u32);
#[derive(Clone, Debug, PartialEq, Eq, Default)]
pub struct Brands {
pub major: FourCc,
pub minor_version: u32,
pub compatible: Vec<FourCc>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum TrackKind {
Video,
Audio,
Subtitle,
Other(FourCc),
}
#[derive(Clone, Debug, PartialEq)]
pub enum Codec {
H264 {
entry: FourCc,
config: AvcConfig,
},
H265 {
entry: FourCc,
config: HevcConfig,
},
Aac {
config: AacConfig,
},
Opus {
config: OpusConfig,
},
Other {
entry: FourCc,
raw: Vec<u8>,
},
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SidecarBox {
pub kind: FourCc,
pub payload: Vec<u8>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AvcConfig {
pub raw: Vec<u8>,
pub profile: u8,
pub profile_compat: u8,
pub level: u8,
pub nal_length_size: u8,
pub sps: Vec<Vec<u8>>,
pub pps: Vec<Vec<u8>>,
pub sidecars: Vec<SidecarBox>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct NalArray {
pub nal_type: u8,
pub nals: Vec<Vec<u8>>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct HevcConfig {
pub raw: Vec<u8>,
pub nal_length_size: u8,
pub arrays: Vec<NalArray>,
pub sidecars: Vec<SidecarBox>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AacConfig {
pub raw_esds: Vec<u8>,
pub object_type: u8,
pub audio_specific_config: Vec<u8>,
pub channels: u16,
pub sample_rate: u32,
pub sidecars: Vec<SidecarBox>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct OpusConfig {
pub raw: Vec<u8>,
pub channels: u8,
pub pre_skip: u16,
pub input_sample_rate: u32,
pub output_gain: i16,
pub mapping_family: u8,
pub sidecars: Vec<SidecarBox>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct Edit {
pub segment_duration: u64,
pub media_time: Option<u64>,
pub media_rate: f32,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ChunkOffsetKind {
Stco,
Co64,
None,
}
#[derive(Clone, Debug, PartialEq)]
pub struct Track {
pub id: TrackId,
pub kind: TrackKind,
pub handler_name: String,
pub timescale: u32,
pub duration: u64,
pub language: String,
pub enabled: bool,
pub width: f64,
pub height: f64,
pub codec: Codec,
pub edit_list: Vec<Edit>,
pub sample_count: u32,
pub chunk_offsets: ChunkOffsetKind,
pub sync_sample_count: Option<u32>,
}
impl Track {
pub fn presentation_offset(&self) -> Option<u64> {
let mut non_empty = self
.edit_list
.iter()
.filter(|edit| edit.media_time.is_some());
let first = non_empty.next()?;
if non_empty.next().is_some() {
return None;
}
first.media_time
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct SampleInfo {
pub index: u32,
pub offset: u64,
pub size: u32,
pub dts: u64,
pub cts_offset: i64,
pub pts: i64,
pub duration: u32,
pub is_sync: bool,
pub chunk: u32,
pub description_index: u32,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Sample {
pub info: SampleInfo,
pub data: Vec<u8>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Fragment {
pub sequence_number: u32,
pub moof_offset: u64,
pub runs: Vec<TrackRun>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct TrackRun {
pub track: TrackId,
pub samples: Vec<SampleInfo>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Event {
pub scheme_id_uri: String,
pub value: String,
pub timescale: u32,
pub presentation_time: u64,
pub event_duration: u32,
pub id: u32,
pub message_data: Vec<u8>,
}
#[derive(Clone, Debug, PartialEq, Eq, Default)]
pub struct Metadata {
pub entries: Vec<(MetaKey, MetaValue)>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum MetaKey {
Title,
Artist,
Album,
AlbumArtist,
Composer,
Genre,
Comment,
Date,
Other(FourCc),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum MetaValue {
Text(String),
Binary(Vec<u8>),
Integer(i64),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Warning {
TrailingBytes {
at: u64,
count: u64,
},
UnknownBox {
kind: FourCc,
parent: Option<FourCc>,
},
}
#[non_exhaustive]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Limits {
pub max_moov_bytes: u64,
pub max_moof_bytes: u64,
pub max_sample_bytes: u32,
pub max_fragments: u32,
pub max_sample_count: u32,
pub max_depth: u8,
}
impl Default for Limits {
fn default() -> Self {
Self {
max_moov_bytes: 256 * 1024 * 1024,
max_moof_bytes: 64 * 1024 * 1024,
max_sample_bytes: 64 * 1024 * 1024,
max_fragments: 1_000_000,
max_sample_count: 500_000,
max_depth: 32,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ChunkOffsetChoice {
Auto,
Co64,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct WriterConfig {
pub movie_timescale: u32,
pub major_brand: FourCc,
pub compatible_brands: Vec<FourCc>,
pub chunk_offsets: ChunkOffsetChoice,
}
impl Default for WriterConfig {
fn default() -> Self {
Self {
movie_timescale: 1000,
major_brand: FourCc(*b"isom"),
compatible_brands: vec![FourCc(*b"isom"), FourCc(*b"iso2"), FourCc(*b"mp41")],
chunk_offsets: ChunkOffsetChoice::Auto,
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct TrackConfig {
pub kind: TrackKind,
pub timescale: u32,
pub language: String,
pub handler_name: String,
pub codec: Codec,
pub width: f64,
pub height: f64,
pub edit_list: Vec<Edit>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct SampleInput<'a> {
pub data: &'a [u8],
pub duration: u32,
pub cts_offset: i32,
pub is_sync: bool,
}