mp4_atom/moov/trak/mdia/minf/stbl/
ctts.rs1use crate::*;
2
3ext! {
4 name: Ctts,
5 versions: [0, 1],
6 flags: {}
7}
8
9#[derive(Debug, Clone, PartialEq, Eq, Default)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11pub struct Ctts {
12 pub entries: Vec<CttsEntry>,
13}
14
15#[derive(Debug, Clone, PartialEq, Eq, Default)]
16#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
17pub struct CttsEntry {
18 pub sample_count: u32,
19 pub sample_offset: i64,
21}
22
23impl AtomExt for Ctts {
24 type Ext = CttsExt;
25
26 const KIND_EXT: FourCC = FourCC::new(b"ctts");
27
28 fn decode_body_ext<B: Buf>(buf: &mut B, ext: CttsExt) -> Result<Self> {
29 let entry_count = u32::decode(buf)?;
30
31 let mut entries = Vec::new();
32 for _ in 0..entry_count {
33 let entry = CttsEntry {
34 sample_count: u32::decode(buf)?,
35 sample_offset: match ext.version {
36 CttsVersion::V0 => u32::decode(buf)?.into(),
37 CttsVersion::V1 => i32::decode(buf)?.into(),
38 },
39 };
40 entries.push(entry);
41 }
42
43 Ok(Ctts { entries })
44 }
45
46 fn encode_body_ext<B: BufMut>(&self, buf: &mut B) -> Result<CttsExt> {
47 let version = if self.entries.iter().any(|entry| entry.sample_offset < 0) {
48 CttsVersion::V1
49 } else {
50 CttsVersion::V0
51 };
52
53 (self.entries.len() as u32).encode(buf)?;
54 for entry in self.entries.iter() {
55 (entry.sample_count).encode(buf)?;
56 match version {
57 CttsVersion::V0 => u32::try_from(entry.sample_offset)
58 .map_err(|_| Error::InvalidSize)?
59 .encode(buf)?,
60 CttsVersion::V1 => i32::try_from(entry.sample_offset)
61 .map_err(|_| Error::InvalidSize)?
62 .encode(buf)?,
63 }
64 }
65
66 Ok(version.into())
67 }
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73
74 #[test]
75 fn test_ctts_v1() {
76 const ENCODED: &[u8] = &[
77 0x00, 0x00, 0x00, 0x20, b'c', b't', b't', b's', 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
78 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x02,
79 0xff, 0xff, 0xff, 0x9c,
80 ];
81
82 let expected = Ctts {
83 entries: vec![
84 CttsEntry {
85 sample_count: 1,
86 sample_offset: 200,
87 },
88 CttsEntry {
89 sample_count: 2,
90 sample_offset: -100,
91 },
92 ],
93 };
94 let mut buf = Vec::new();
95 expected.encode(&mut buf).unwrap();
96 assert_eq!(buf, ENCODED);
97
98 let mut buf = buf.as_ref();
99 let decoded = Ctts::decode(&mut buf).unwrap();
100 assert_eq!(decoded, expected);
101 }
102
103 #[test]
104 fn test_ctts_v0_unsigned_offset() {
105 const ENCODED: &[u8] = &[
106 0x00, 0x00, 0x00, 0x18, b'c', b't', b't', b's', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
107 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x00,
108 ];
109
110 let decoded = Ctts::decode(&mut &ENCODED[..]).unwrap();
111 assert_eq!(
112 decoded,
113 Ctts {
114 entries: vec![CttsEntry {
115 sample_count: 2,
116 sample_offset: 1 << 31,
117 }],
118 }
119 );
120
121 let mut encoded = Vec::new();
122 decoded.encode(&mut encoded).unwrap();
123 assert_eq!(encoded, ENCODED);
124 }
125}