mp4_atom/moov/trak/
tkhd.rs

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