1use crate::*;
2
3ext! {
4 name: Tkhd,
5 versions: [0, 1],
6 flags: {
7 track_enabled = 0,
8 track_in_movie = 1,
9 track_in_preview = 2,
10 track_size_is_aspect_ratio = 3,
11 }
12}
13
14#[derive(Debug, Clone, PartialEq, Eq, Default)]
15#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
16pub struct Tkhd {
17 pub creation_time: u64,
18 pub modification_time: u64,
19 pub track_id: u32,
20 pub duration: u64,
21 pub layer: u16,
22 pub alternate_group: u16,
23 pub enabled: bool,
24 pub in_movie: bool,
25 pub size_is_aspect_ratio: bool,
28
29 pub volume: FixedPoint<u8>,
30 pub matrix: Matrix,
31
32 pub width: FixedPoint<u16>,
33 pub height: FixedPoint<u16>,
34}
35
36impl AtomExt for Tkhd {
37 const KIND_EXT: FourCC = FourCC::new(b"tkhd");
38
39 type Ext = TkhdExt;
40
41 fn decode_body_ext<B: Buf>(buf: &mut B, ext: TkhdExt) -> Result<Self> {
42 let (creation_time, modification_time, track_id, _, duration) = match ext.version {
43 TkhdVersion::V1 => (
44 u64::decode(buf)?,
45 u64::decode(buf)?,
46 u32::decode(buf)?,
47 u32::decode(buf)?,
48 u64::decode(buf)?,
49 ),
50 TkhdVersion::V0 => (
51 u32::decode(buf)? as u64,
52 u32::decode(buf)? as u64,
53 u32::decode(buf)?,
54 u32::decode(buf)?,
55 u32::decode(buf)? as u64,
56 ),
57 };
58
59 u64::decode(buf)?; let layer = u16::decode(buf)?;
61 let alternate_group = u16::decode(buf)?;
62 let volume = FixedPoint::decode(buf)?;
63
64 u16::decode(buf)?; let matrix = Matrix::decode(buf)?;
66 let width = FixedPoint::decode(buf)?;
67 let height = FixedPoint::decode(buf)?;
68
69 Ok(Tkhd {
70 creation_time,
71 modification_time,
72 track_id,
73 duration,
74 layer,
75 alternate_group,
76 volume,
77 matrix,
78 width,
79 height,
80 enabled: ext.track_enabled,
81 in_movie: ext.track_in_movie,
82 size_is_aspect_ratio: ext.track_size_is_aspect_ratio,
83 })
86 }
87
88 fn encode_body_ext<B: BufMut>(&self, buf: &mut B) -> Result<TkhdExt> {
89 self.creation_time.encode(buf)?;
90 self.modification_time.encode(buf)?;
91 self.track_id.encode(buf)?;
92 0u32.encode(buf)?; self.duration.encode(buf)?;
94
95 0u64.encode(buf)?; self.layer.encode(buf)?;
97 self.alternate_group.encode(buf)?;
98 self.volume.encode(buf)?;
99 0u16.encode(buf)?; self.matrix.encode(buf)?;
101
102 self.width.encode(buf)?;
103 self.height.encode(buf)?;
104
105 Ok(TkhdExt {
106 version: TkhdVersion::V1,
107 track_enabled: self.enabled,
108 track_in_movie: self.in_movie,
109 track_in_preview: self.in_movie,
112 track_size_is_aspect_ratio: self.size_is_aspect_ratio,
113 })
114 }
115}
116
117#[derive(Debug, Clone, PartialEq, Eq)]
118#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
119pub struct Matrix {
120 pub a: i32,
121 pub b: i32,
122 pub u: i32,
123 pub c: i32,
124 pub d: i32,
125 pub v: i32,
126 pub x: i32,
127 pub y: i32,
128 pub w: i32,
129}
130
131impl Decode for Matrix {
132 fn decode<B: Buf>(buf: &mut B) -> Result<Self> {
133 Ok(Self {
134 a: i32::decode(buf)?,
135 b: i32::decode(buf)?,
136 u: i32::decode(buf)?,
137 c: i32::decode(buf)?,
138 d: i32::decode(buf)?,
139 v: i32::decode(buf)?,
140 x: i32::decode(buf)?,
141 y: i32::decode(buf)?,
142 w: i32::decode(buf)?,
143 })
144 }
145}
146
147impl Encode for Matrix {
148 fn encode<B: BufMut>(&self, buf: &mut B) -> Result<()> {
149 self.a.encode(buf)?;
150 self.b.encode(buf)?;
151 self.u.encode(buf)?;
152 self.c.encode(buf)?;
153 self.d.encode(buf)?;
154 self.v.encode(buf)?;
155 self.x.encode(buf)?;
156 self.y.encode(buf)?;
157 self.w.encode(buf)
158 }
159}
160
161impl std::fmt::Display for Matrix {
162 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
163 write!(
164 f,
165 "{:#x} {:#x} {:#x} {:#x} {:#x} {:#x} {:#x} {:#x} {:#x}",
166 self.a, self.b, self.u, self.c, self.d, self.v, self.x, self.y, self.w
167 )
168 }
169}
170
171impl Default for Matrix {
172 fn default() -> Self {
173 Self {
174 a: 0x00010000,
176 b: 0,
177 u: 0,
178 c: 0,
179 d: 0x00010000,
180 v: 0,
181 x: 0,
182 y: 0,
183 w: 0x40000000,
184 }
185 }
186}
187
188#[cfg(test)]
189mod tests {
190 use super::*;
191
192 #[test]
193 fn test_tkhd32() {
194 let expected = Tkhd {
195 creation_time: 100,
196 modification_time: 200,
197 track_id: 1,
198 duration: 634634,
199 layer: 0,
200 alternate_group: 0,
201 volume: 1.into(),
202 matrix: Matrix::default(),
203 width: 512.into(),
204 height: 288.into(),
205 enabled: true,
206 in_movie: true,
207 size_is_aspect_ratio: false,
208 };
209 let mut buf = Vec::new();
210 expected.encode(&mut buf).unwrap();
211
212 let mut buf = buf.as_ref();
213 let decoded = Tkhd::decode(&mut buf).unwrap();
214 assert_eq!(decoded, expected);
215 }
216
217 #[test]
218 fn test_tkhd64() {
219 let expected = Tkhd {
220 creation_time: 100,
221 modification_time: 200,
222 track_id: 1,
223 duration: 634634,
224 layer: 0,
225 alternate_group: 0,
226 volume: 1.into(),
227 matrix: Matrix::default(),
228 width: 512.into(),
229 height: 288.into(),
230 enabled: true,
231 in_movie: true,
232 size_is_aspect_ratio: false,
233 };
234 let mut buf = Vec::new();
235 expected.encode(&mut buf).unwrap();
236
237 let mut buf = buf.as_ref();
238 let decoded = Tkhd::decode(&mut buf).unwrap();
239 assert_eq!(decoded, expected);
240 }
241}