mp4_atom/moov/udta/
chpl.rs1use crate::*;
2
3#[derive(Debug, Clone, PartialEq, Eq)]
5#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
6pub struct ChplEntry {
7 pub start: u64,
9 pub title: String,
10}
11
12#[derive(Debug, Clone, PartialEq, Eq, Default)]
24#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
25pub struct Chpl {
26 pub entries: Vec<ChplEntry>,
27}
28
29impl Atom for Chpl {
30 const KIND: FourCC = FourCC::new(b"chpl");
31
32 fn decode_body<B: Buf>(buf: &mut B) -> Result<Self> {
33 let version = u8::decode(buf)?;
34 <[u8; 3]>::decode(buf)?; if version != 0 {
36 <[u8; 4]>::decode(buf)?; }
38
39 let count = u8::decode(buf)?;
40 let mut entries = Vec::with_capacity(count as usize);
41 for _ in 0..count {
42 let start = u64::decode(buf)?;
43
44 let title = decode_length_prefixed_utf8_string::<u8>(buf)?;
45
46 entries.push(ChplEntry { start, title });
47 }
48
49 Ok(Self { entries })
50 }
51
52 fn encode_body<B: BufMut>(&self, buf: &mut B) -> Result<()> {
53 1u8.encode(buf)?; [0u8; 3].encode(buf)?; [0u8; 4].encode(buf)?; let count: u8 = self
58 .entries
59 .len()
60 .try_into()
61 .map_err(|_| Error::TooLarge(Self::KIND))?;
62 count.encode(buf)?;
63
64 for entry in &self.entries {
65 entry.start.encode(buf)?;
66
67 encode_length_prefixed_string::<u8>(buf, &entry.title, Self::KIND)?;
68 }
69
70 Ok(())
71 }
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77
78 #[test]
79 fn test_chpl_roundtrip() {
80 let expected = Chpl {
81 entries: vec![
82 ChplEntry {
83 start: 0,
84 title: "Intro".into(),
85 },
86 ChplEntry {
87 start: 30_000_000,
88 title: "Chapter 2".into(),
89 },
90 ],
91 };
92
93 let mut buf = Vec::new();
94 expected.encode(&mut buf).unwrap();
95
96 let decoded = Chpl::decode(&mut buf.as_slice()).expect("failed to decode chpl");
97 assert_eq!(decoded, expected);
98 }
99
100 #[test]
101 fn test_chpl_empty() {
102 let expected = Chpl { entries: vec![] };
103
104 let mut buf = Vec::new();
105 expected.encode(&mut buf).unwrap();
106
107 let decoded = Chpl::decode(&mut buf.as_slice()).expect("failed to decode chpl");
108 assert_eq!(decoded, expected);
109 }
110
111 #[test]
112 fn test_chpl_version0_no_reserved_field() {
113 let expected = Chpl {
116 entries: vec![
117 ChplEntry {
118 start: 0,
119 title: "Intro".into(),
120 },
121 ChplEntry {
122 start: 30_000_000,
123 title: "Chapter 2".into(),
124 },
125 ],
126 };
127
128 let mut buf = Vec::new();
129 0u8.encode(&mut buf).unwrap(); [0u8; 3].encode(&mut buf).unwrap(); let count: u8 = expected.entries.len().try_into().unwrap();
132 count.encode(&mut buf).unwrap();
133 for entry in &expected.entries {
134 entry.start.encode(&mut buf).unwrap();
135 let title_bytes = entry.title.as_bytes();
136 let title_len: u8 = title_bytes.len().try_into().unwrap();
137 title_len.encode(&mut buf).unwrap();
138 buf.extend_from_slice(title_bytes);
139 }
140
141 let decoded = Chpl::decode_body(&mut buf.as_slice()).expect("failed to decode chpl");
142 assert_eq!(decoded, expected);
143 }
144}