Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ any! {
Minf,
Stbl,
Stsd,
Avc1,
Avc1, Avc3,
Avcc,
Btrt,
Ccst,
Expand Down
158 changes: 158 additions & 0 deletions src/moov/trak/mdia/minf/stbl/stsd/h264/avc3.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
use crate::*;

#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Avc3 {
pub visual: Visual,
pub avcc: Avcc,
pub btrt: Option<Btrt>,
pub colr: Option<Colr>,
pub pasp: Option<Pasp>,
pub taic: Option<Taic>,
}

impl Atom for Avc3 {
const KIND: FourCC = FourCC::new(b"avc3");

fn decode_body<B: Buf>(buf: &mut B) -> Result<Self> {
let visual = Visual::decode(buf)?;

let mut avcc = None;
let mut btrt = None;
let mut colr = None;
let mut pasp = None;
let mut taic = None;
while let Some(atom) = Any::decode_maybe(buf)? {
match atom {
Any::Avcc(atom) => avcc = atom.into(),
Any::Btrt(atom) => btrt = atom.into(),
Any::Colr(atom) => colr = atom.into(),
Any::Pasp(atom) => pasp = atom.into(),
Any::Taic(atom) => taic = atom.into(),
_ => tracing::warn!("unknown atom: {:?}", atom),
}
}

Ok(Avc3 {
visual,
avcc: avcc.ok_or(Error::MissingBox(Avcc::KIND))?,
btrt,
colr,
pasp,
taic,
})
}

fn encode_body<B: BufMut>(&self, buf: &mut B) -> Result<()> {
self.visual.encode(buf)?;
self.avcc.encode(buf)?;
if self.btrt.is_some() {
self.btrt.encode(buf)?;
}
if self.colr.is_some() {
self.colr.encode(buf)?;
}
if self.pasp.is_some() {
self.pasp.encode(buf)?;
}
if self.taic.is_some() {
self.taic.encode(buf)?
}
Ok(())
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_avc3() {
let expected = Avc3 {
visual: Visual {
data_reference_index: 1,
width: 320,
height: 240,
horizresolution: 0x48.into(),
vertresolution: 0x48.into(),
frame_count: 1,
compressor: "ya boy".into(),
depth: 24,
},
avcc: Avcc {
configuration_version: 1,
avc_profile_indication: 100,
profile_compatibility: 0,
avc_level_indication: 13,
length_size: 4,
sequence_parameter_sets: vec![vec![
0x67, 0x64, 0x00, 0x0D, 0xAC, 0xD9, 0x41, 0x41, 0xFA, 0x10, 0x00, 0x00, 0x03,
0x00, 0x10, 0x00, 0x00, 0x03, 0x03, 0x20, 0xF1, 0x42, 0x99, 0x60,
]],
picture_parameter_sets: vec![vec![0x68, 0xEB, 0xE3, 0xCB, 0x22, 0xC0]],
..Default::default()
},
btrt: None,
colr: None,
pasp: None,
taic: None,
};
let mut buf = Vec::new();
expected.encode(&mut buf).unwrap();

let mut buf = buf.as_ref();
let decoded = Avc3::decode(&mut buf).unwrap();
assert_eq!(decoded, expected);
}

#[test]
fn test_avc3_with_extras() {
let expected = Avc3 {
visual: Visual {
data_reference_index: 1,
width: 320,
height: 240,
horizresolution: 0x48.into(),
vertresolution: 0x48.into(),
frame_count: 1,
compressor: "they".into(),
depth: 24,
},
avcc: Avcc {
configuration_version: 1,
avc_profile_indication: 100,
profile_compatibility: 0,
avc_level_indication: 13,
length_size: 4,
sequence_parameter_sets: vec![vec![
0x67, 0x64, 0x00, 0x0D, 0xAC, 0xD9, 0x41, 0x41, 0xFA, 0x10, 0x00, 0x00, 0x03,
0x00, 0x10, 0x00, 0x00, 0x03, 0x03, 0x20, 0xF1, 0x42, 0x99, 0x60,
]],
picture_parameter_sets: vec![vec![0x68, 0xEB, 0xE3, 0xCB, 0x22, 0xC0]],
..Default::default()
},
btrt: Some(Btrt {
buffer_size_db: 14075,
max_bitrate: 374288,
avg_bitrate: 240976,
}),
colr: Some(Colr::default()),
pasp: Some(Pasp {
h_spacing: 4,
v_spacing: 3,
}),
taic: Some(Taic {
time_uncertainty: u64::MAX,
clock_resolution: 1000,
clock_drift_rate: i32::MAX,
clock_type: ClockType::CanSync,
}),
};
let mut buf = Vec::new();
expected.encode(&mut buf).unwrap();

let mut buf = buf.as_ref();
let decoded = Avc3::decode(&mut buf).unwrap();
assert_eq!(decoded, expected);
}
}
2 changes: 2 additions & 0 deletions src/moov/trak/mdia/minf/stbl/stsd/h264/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
mod avc1;

Check warning on line 1 in src/moov/trak/mdia/minf/stbl/stsd/h264/mod.rs

View workflow job for this annotation

GitHub Actions / build

Diff in /home/runner/work/mp4-atom/mp4-atom/src/moov/trak/mdia/minf/stbl/stsd/h264/mod.rs
mod avcc;
mod avc3;

// Incomplete H264 decoder, saved for possible future use
//mod golomb;
//mod pps;
//mod sps;

Check warning on line 8 in src/moov/trak/mdia/minf/stbl/stsd/h264/mod.rs

View workflow job for this annotation

GitHub Actions / build

Diff in /home/runner/work/mp4-atom/mp4-atom/src/moov/trak/mdia/minf/stbl/stsd/h264/mod.rs

pub use avc1::*;
pub use avcc::*;
pub use avc3::*;
5 changes: 5 additions & 0 deletions src/moov/trak/mdia/minf/stbl/stsd/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ pub enum Codec {
// H264
Avc1(Avc1),

// H264: SPS/PPS/VPS is inline
Avc3(Avc3),

// HEVC: SPS/PPS/VPS is inline
Hev1(Hev1),

Expand Down Expand Up @@ -97,6 +100,7 @@ impl Decode for Codec {
let atom = Any::decode(buf)?;
Ok(match atom {
Any::Avc1(atom) => atom.into(),
Any::Avc3(atom) => atom.into(),
Any::Hev1(atom) => atom.into(),
Any::Hvc1(atom) => atom.into(),
Any::Vp08(atom) => atom.into(),
Expand All @@ -120,6 +124,7 @@ impl Encode for Codec {
match self {
Self::Unknown(kind) => kind.encode(buf),
Self::Avc1(atom) => atom.encode(buf),
Self::Avc3(atom) => atom.encode(buf),
Self::Hev1(atom) => atom.encode(buf),
Self::Hvc1(atom) => atom.encode(buf),
Self::Vp08(atom) => atom.encode(buf),
Expand Down
Loading