Skip to content

Commit df6e102

Browse files
committed
Initial avc3 support
1 parent 16ef4e6 commit df6e102

File tree

4 files changed

+166
-1
lines changed

4 files changed

+166
-1
lines changed

src/any.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ any! {
268268
Minf,
269269
Stbl,
270270
Stsd,
271-
Avc1,
271+
Avc1, Avc3,
272272
Avcc,
273273
Btrt,
274274
Ccst,
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
use crate::*;
2+
3+
#[derive(Debug, Clone, PartialEq, Eq, Default)]
4+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
5+
pub struct Avc3 {
6+
pub visual: Visual,
7+
pub avcc: Avcc,
8+
pub btrt: Option<Btrt>,
9+
pub colr: Option<Colr>,
10+
pub pasp: Option<Pasp>,
11+
pub taic: Option<Taic>,
12+
}
13+
14+
impl Atom for Avc3 {
15+
const KIND: FourCC = FourCC::new(b"avc3");
16+
17+
fn decode_body<B: Buf>(buf: &mut B) -> Result<Self> {
18+
let visual = Visual::decode(buf)?;
19+
20+
let mut avcc = None;
21+
let mut btrt = None;
22+
let mut colr = None;
23+
let mut pasp = None;
24+
let mut taic = None;
25+
while let Some(atom) = Any::decode_maybe(buf)? {
26+
match atom {
27+
Any::Avcc(atom) => avcc = atom.into(),
28+
Any::Btrt(atom) => btrt = atom.into(),
29+
Any::Colr(atom) => colr = atom.into(),
30+
Any::Pasp(atom) => pasp = atom.into(),
31+
Any::Taic(atom) => taic = atom.into(),
32+
_ => tracing::warn!("unknown atom: {:?}", atom),
33+
}
34+
}
35+
36+
Ok(Avc3 {
37+
visual,
38+
avcc: avcc.ok_or(Error::MissingBox(Avcc::KIND))?,
39+
btrt,
40+
colr,
41+
pasp,
42+
taic,
43+
})
44+
}
45+
46+
fn encode_body<B: BufMut>(&self, buf: &mut B) -> Result<()> {
47+
self.visual.encode(buf)?;
48+
self.avcc.encode(buf)?;
49+
if self.btrt.is_some() {
50+
self.btrt.encode(buf)?;
51+
}
52+
if self.colr.is_some() {
53+
self.colr.encode(buf)?;
54+
}
55+
if self.pasp.is_some() {
56+
self.pasp.encode(buf)?;
57+
}
58+
if self.taic.is_some() {
59+
self.taic.encode(buf)?
60+
}
61+
Ok(())
62+
}
63+
}
64+
65+
#[cfg(test)]
66+
mod tests {
67+
use super::*;
68+
69+
#[test]
70+
fn test_avc3() {
71+
let expected = Avc3 {
72+
visual: Visual {
73+
data_reference_index: 1,
74+
width: 320,
75+
height: 240,
76+
horizresolution: 0x48.into(),
77+
vertresolution: 0x48.into(),
78+
frame_count: 1,
79+
compressor: "ya boy".into(),
80+
depth: 24,
81+
},
82+
avcc: Avcc {
83+
configuration_version: 1,
84+
avc_profile_indication: 100,
85+
profile_compatibility: 0,
86+
avc_level_indication: 13,
87+
length_size: 4,
88+
sequence_parameter_sets: vec![vec![
89+
0x67, 0x64, 0x00, 0x0D, 0xAC, 0xD9, 0x41, 0x41, 0xFA, 0x10, 0x00, 0x00, 0x03,
90+
0x00, 0x10, 0x00, 0x00, 0x03, 0x03, 0x20, 0xF1, 0x42, 0x99, 0x60,
91+
]],
92+
picture_parameter_sets: vec![vec![0x68, 0xEB, 0xE3, 0xCB, 0x22, 0xC0]],
93+
..Default::default()
94+
},
95+
btrt: None,
96+
colr: None,
97+
pasp: None,
98+
taic: None,
99+
};
100+
let mut buf = Vec::new();
101+
expected.encode(&mut buf).unwrap();
102+
103+
let mut buf = buf.as_ref();
104+
let decoded = Avc3::decode(&mut buf).unwrap();
105+
assert_eq!(decoded, expected);
106+
}
107+
108+
#[test]
109+
fn test_avc3_with_extras() {
110+
let expected = Avc3 {
111+
visual: Visual {
112+
data_reference_index: 1,
113+
width: 320,
114+
height: 240,
115+
horizresolution: 0x48.into(),
116+
vertresolution: 0x48.into(),
117+
frame_count: 1,
118+
compressor: "they".into(),
119+
depth: 24,
120+
},
121+
avcc: Avcc {
122+
configuration_version: 1,
123+
avc_profile_indication: 100,
124+
profile_compatibility: 0,
125+
avc_level_indication: 13,
126+
length_size: 4,
127+
sequence_parameter_sets: vec![vec![
128+
0x67, 0x64, 0x00, 0x0D, 0xAC, 0xD9, 0x41, 0x41, 0xFA, 0x10, 0x00, 0x00, 0x03,
129+
0x00, 0x10, 0x00, 0x00, 0x03, 0x03, 0x20, 0xF1, 0x42, 0x99, 0x60,
130+
]],
131+
picture_parameter_sets: vec![vec![0x68, 0xEB, 0xE3, 0xCB, 0x22, 0xC0]],
132+
..Default::default()
133+
},
134+
btrt: Some(Btrt {
135+
buffer_size_db: 14075,
136+
max_bitrate: 374288,
137+
avg_bitrate: 240976,
138+
}),
139+
colr: Some(Colr::default()),
140+
pasp: Some(Pasp {
141+
h_spacing: 4,
142+
v_spacing: 3,
143+
}),
144+
taic: Some(Taic {
145+
time_uncertainty: u64::MAX,
146+
clock_resolution: 1000,
147+
clock_drift_rate: i32::MAX,
148+
clock_type: ClockType::CanSync,
149+
}),
150+
};
151+
let mut buf = Vec::new();
152+
expected.encode(&mut buf).unwrap();
153+
154+
let mut buf = buf.as_ref();
155+
let decoded = Avc3::decode(&mut buf).unwrap();
156+
assert_eq!(decoded, expected);
157+
}
158+
}

src/moov/trak/mdia/minf/stbl/stsd/h264/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
mod avc1;
22
mod avcc;
3+
mod avc3;
34

45
// Incomplete H264 decoder, saved for possible future use
56
//mod golomb;
@@ -8,3 +9,4 @@ mod avcc;
89

910
pub use avc1::*;
1011
pub use avcc::*;
12+
pub use avc3::*;

src/moov/trak/mdia/minf/stbl/stsd/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ pub enum Codec {
5252
// H264
5353
Avc1(Avc1),
5454

55+
// H264: SPS/PPS/VPS is inline
56+
Avc3(Avc3),
57+
5558
// HEVC: SPS/PPS/VPS is inline
5659
Hev1(Hev1),
5760

@@ -97,6 +100,7 @@ impl Decode for Codec {
97100
let atom = Any::decode(buf)?;
98101
Ok(match atom {
99102
Any::Avc1(atom) => atom.into(),
103+
Any::Avc3(atom) => atom.into(),
100104
Any::Hev1(atom) => atom.into(),
101105
Any::Hvc1(atom) => atom.into(),
102106
Any::Vp08(atom) => atom.into(),
@@ -120,6 +124,7 @@ impl Encode for Codec {
120124
match self {
121125
Self::Unknown(kind) => kind.encode(buf),
122126
Self::Avc1(atom) => atom.encode(buf),
127+
Self::Avc3(atom) => atom.encode(buf),
123128
Self::Hev1(atom) => atom.encode(buf),
124129
Self::Hvc1(atom) => atom.encode(buf),
125130
Self::Vp08(atom) => atom.encode(buf),

0 commit comments

Comments
 (0)