use crate::*;
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Subs {
pub flags: [u8; 3], pub entries: Vec<SubsEntry>,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SubsEntry {
pub sample_delta: u32,
pub subsamples: Vec<SubsSubsample>,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SubsSubsample {
pub size: SubsSubsampleSize,
pub priority: u8,
pub discardable: bool,
pub codec_specific_parameters: Vec<u8>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum SubsSubsampleSize {
U16(u16),
U32(u32),
}
impl Default for SubsSubsampleSize {
fn default() -> Self {
Self::U16(0)
}
}
impl SubsSubsampleSize {
pub fn value(&self) -> u32 {
match self {
Self::U16(n) => u32::from(*n),
Self::U32(n) => *n,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub(crate) enum SubsVersion {
#[default]
V0 = 0,
V1 = 1,
}
impl TryFrom<u8> for SubsVersion {
type Error = Error;
fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
match value {
0 => Ok(Self::V0),
1 => Ok(Self::V1),
_ => Err(Error::UnknownVersion(value)),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub(crate) struct SubsExt {
pub version: SubsVersion,
pub flags: [u8; 3],
}
impl Ext for SubsExt {
fn encode(&self) -> Result<u32> {
Ok((self.version as u32) << 24
| (self.flags[0] as u32) << 16
| (self.flags[1] as u32) << 8
| (self.flags[2] as u32))
}
fn decode(v: u32) -> Result<Self> {
let bytes = v.to_be_bytes();
let version = SubsVersion::try_from(bytes[0])?;
let flags = [bytes[1], bytes[2], bytes[3]];
Ok(Self { version, flags })
}
}
impl AtomExt for Subs {
type Ext = SubsExt;
const KIND_EXT: FourCC = FourCC::new(b"subs");
fn decode_body_ext<B: Buf>(buf: &mut B, ext: Self::Ext) -> Result<Self> {
let flags = ext.flags;
let entry_count = u32::decode(buf)?;
let mut entries = Vec::with_capacity((entry_count as usize).min(1024));
for _ in 0..entry_count {
let sample_delta = u32::decode(buf)?;
let subsample_count = u16::decode(buf)?;
let mut subsamples = Vec::with_capacity(usize::from(subsample_count).min(1024));
for _ in 0..subsample_count {
let size = if ext.version == SubsVersion::V1 {
SubsSubsampleSize::U32(u32::decode(buf)?)
} else {
SubsSubsampleSize::U16(u16::decode(buf)?)
};
let priority = u8::decode(buf)?;
let discardable = u8::decode(buf)? == 1;
let codec_specific_parameters = buf.slice(4).to_vec();
buf.advance(4);
subsamples.push(SubsSubsample {
size,
priority,
discardable,
codec_specific_parameters,
});
}
entries.push(SubsEntry {
sample_delta,
subsamples,
});
}
Ok(Self { flags, entries })
}
fn encode_body_ext<B: BufMut>(&self, buf: &mut B) -> Result<Self::Ext> {
let ext = match &self
.entries
.first()
.and_then(|e| e.subsamples.first())
.map(|s| &s.size)
{
Some(SubsSubsampleSize::U16(_)) => SubsExt {
version: SubsVersion::V0,
flags: self.flags,
},
Some(SubsSubsampleSize::U32(_)) => SubsExt {
version: SubsVersion::V1,
flags: self.flags,
},
None => SubsExt {
version: SubsVersion::default(),
flags: self.flags,
},
};
(self.entries.len() as u32).encode(buf)?;
for entry in &self.entries {
entry.sample_delta.encode(buf)?;
(entry.subsamples.len() as u16).encode(buf)?;
for subsample in &entry.subsamples {
match subsample.size {
SubsSubsampleSize::U16(n) => n.encode(buf)?,
SubsSubsampleSize::U32(n) => n.encode(buf)?,
}
subsample.priority.encode(buf)?;
if subsample.discardable {
1u8.encode(buf)?;
} else {
0u8.encode(buf)?;
}
subsample.codec_specific_parameters.encode(buf)?;
}
}
Ok(ext)
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Cursor;
const SUBS: &[u8] = &[
0x00, 0x00, 0x00, 0x16, 0x73, 0x75, 0x62, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
];
#[test]
fn subs_decodes_from_bytes_correctly() {
let mut buf = Cursor::new(SUBS);
let subs = Subs::decode(&mut buf).expect("subs should decode successfully");
assert_eq!(
subs,
Subs {
flags: [0, 0, 0],
entries: vec![SubsEntry {
sample_delta: 1,
subsamples: vec![],
}],
}
)
}
const SUBS_COMPLEX: &[u8] = &[
0x00, 0x00, 0x00, 0x9C, 0x73, 0x75, 0x62, 0x73, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0F, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x05, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xA3, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0B, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xA3, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x05, 0xF5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x4A, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x05, 0x6A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x00, 0x08, 0x00, 0xC2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAB, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x02, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xDE, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x05, 0xBE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x4A, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xF6,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
#[test]
fn subs_decodes_from_bytes_and_encodes_to_bytes_correctly_with_more_complex_example() {
let mut buf = Cursor::new(SUBS_COMPLEX);
let subs = Subs {
flags: [0, 0, 2],
entries: vec![
SubsEntry {
sample_delta: 0,
subsamples: vec![
SubsSubsample {
size: SubsSubsampleSize::U16(3991),
priority: 0,
discardable: false,
codec_specific_parameters: 0u32.to_be_bytes().to_vec(),
},
SubsSubsample {
size: SubsSubsampleSize::U16(1362),
priority: 0,
discardable: false,
codec_specific_parameters: 0u32.to_be_bytes().to_vec(),
},
SubsSubsample {
size: SubsSubsampleSize::U16(1443),
priority: 0,
discardable: false,
codec_specific_parameters: 0u32.to_be_bytes().to_vec(),
},
SubsSubsample {
size: SubsSubsampleSize::U16(2952),
priority: 0,
discardable: false,
codec_specific_parameters: 0u32.to_be_bytes().to_vec(),
},
SubsSubsample {
size: SubsSubsampleSize::U16(1955),
priority: 0,
discardable: false,
codec_specific_parameters: 0u32.to_be_bytes().to_vec(),
},
SubsSubsample {
size: SubsSubsampleSize::U16(1525),
priority: 0,
discardable: false,
codec_specific_parameters: 0u32.to_be_bytes().to_vec(),
},
SubsSubsample {
size: SubsSubsampleSize::U16(842),
priority: 0,
discardable: false,
codec_specific_parameters: 0u32.to_be_bytes().to_vec(),
},
SubsSubsample {
size: SubsSubsampleSize::U16(1386),
priority: 0,
discardable: false,
codec_specific_parameters: 0u32.to_be_bytes().to_vec(),
},
],
},
SubsEntry {
sample_delta: 1,
subsamples: vec![
SubsSubsample {
size: SubsSubsampleSize::U16(194),
priority: 0,
discardable: false,
codec_specific_parameters: 0u32.to_be_bytes().to_vec(),
},
SubsSubsample {
size: SubsSubsampleSize::U16(171),
priority: 0,
discardable: false,
codec_specific_parameters: 0u32.to_be_bytes().to_vec(),
},
SubsSubsample {
size: SubsSubsampleSize::U16(736),
priority: 0,
discardable: false,
codec_specific_parameters: 0u32.to_be_bytes().to_vec(),
},
SubsSubsample {
size: SubsSubsampleSize::U16(734),
priority: 0,
discardable: false,
codec_specific_parameters: 0u32.to_be_bytes().to_vec(),
},
SubsSubsample {
size: SubsSubsampleSize::U16(1470),
priority: 0,
discardable: false,
codec_specific_parameters: 0u32.to_be_bytes().to_vec(),
},
SubsSubsample {
size: SubsSubsampleSize::U16(330),
priority: 0,
discardable: false,
codec_specific_parameters: 0u32.to_be_bytes().to_vec(),
},
SubsSubsample {
size: SubsSubsampleSize::U16(150),
priority: 0,
discardable: false,
codec_specific_parameters: 0u32.to_be_bytes().to_vec(),
},
SubsSubsample {
size: SubsSubsampleSize::U16(1014),
priority: 0,
discardable: false,
codec_specific_parameters: 0u32.to_be_bytes().to_vec(),
},
],
},
],
};
let decoded = Subs::decode(&mut buf).expect("subs should decode successfully");
assert_eq!(subs, decoded);
let mut encoded = Vec::new();
subs.encode(&mut encoded)
.expect("encode should be successful");
assert_eq!(SUBS_COMPLEX, &encoded);
}
}