1use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
2use serde::Serialize;
3use std::io::{Read, Seek, Write};
4use std::mem::size_of;
5
6use crate::mp4box::*;
7
8#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
9pub struct ElstBox {
10 pub version: u8,
11 pub flags: u32,
12
13 #[serde(skip_serializing)]
14 pub entries: Vec<ElstEntry>,
15}
16
17#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
18pub struct ElstEntry {
19 pub segment_duration: u64,
20 pub media_time: u64,
21 pub media_rate: u16,
22 pub media_rate_fraction: u16,
23}
24
25impl ElstBox {
26 pub fn get_type(&self) -> BoxType {
27 BoxType::ElstBox
28 }
29
30 pub fn get_size(&self) -> u64 {
31 let mut size = HEADER_SIZE + HEADER_EXT_SIZE + 4;
32 if self.version == 1 {
33 size += self.entries.len() as u64 * 20;
34 } else if self.version == 0 {
35 size += self.entries.len() as u64 * 12;
36 }
37 size
38 }
39}
40
41impl Mp4Box for ElstBox {
42 fn box_type(&self) -> BoxType {
43 self.get_type()
44 }
45
46 fn box_size(&self) -> u64 {
47 self.get_size()
48 }
49
50 fn to_json(&self) -> Result<String> {
51 Ok(serde_json::to_string(&self).unwrap())
52 }
53
54 fn summary(&self) -> Result<String> {
55 let s = format!("elst_entries={}", self.entries.len());
56 Ok(s)
57 }
58}
59
60impl<R: Read + Seek> ReadBox<&mut R> for ElstBox {
61 fn read_box(reader: &mut R, size: u64) -> Result<Self> {
62 let start = box_start(reader)?;
63
64 let (version, flags) = read_box_header_ext(reader)?;
65
66 let header_size = HEADER_SIZE + HEADER_EXT_SIZE;
67 let entry_count = reader.read_u32::<BigEndian>()?;
68 let other_size = size_of::<i32>(); let entry_size = {
70 let mut entry_size = 0;
71 entry_size += if version == 1 {
72 size_of::<u64>() + size_of::<i64>() } else {
74 size_of::<u32>() + size_of::<i32>() };
76 entry_size += size_of::<i16>() + size_of::<i16>(); entry_size
78 };
79 if u64::from(entry_count)
80 > size
81 .saturating_sub(header_size)
82 .saturating_sub(other_size as u64)
83 / entry_size as u64
84 {
85 return Err(Error::InvalidData(
86 "elst entry_count indicates more entries than could fit in the box",
87 ));
88 }
89 let mut entries = Vec::with_capacity(entry_count as usize);
90 for _ in 0..entry_count {
91 let (segment_duration, media_time) = if version == 1 {
92 (
93 reader.read_u64::<BigEndian>()?,
94 reader.read_u64::<BigEndian>()?,
95 )
96 } else {
97 (
98 reader.read_u32::<BigEndian>()? as u64,
99 reader.read_u32::<BigEndian>()? as u64,
100 )
101 };
102
103 let entry = ElstEntry {
104 segment_duration,
105 media_time,
106 media_rate: reader.read_u16::<BigEndian>()?,
107 media_rate_fraction: reader.read_u16::<BigEndian>()?,
108 };
109 entries.push(entry);
110 }
111
112 skip_bytes_to(reader, start + size)?;
113
114 Ok(ElstBox {
115 version,
116 flags,
117 entries,
118 })
119 }
120}
121
122impl<W: Write> WriteBox<&mut W> for ElstBox {
123 fn write_box(&self, writer: &mut W) -> Result<u64> {
124 let size = self.box_size();
125 BoxHeader::new(self.box_type(), size).write(writer)?;
126
127 write_box_header_ext(writer, self.version, self.flags)?;
128
129 writer.write_u32::<BigEndian>(self.entries.len() as u32)?;
130 for entry in self.entries.iter() {
131 if self.version == 1 {
132 writer.write_u64::<BigEndian>(entry.segment_duration)?;
133 writer.write_u64::<BigEndian>(entry.media_time)?;
134 } else {
135 writer.write_u32::<BigEndian>(entry.segment_duration as u32)?;
136 writer.write_u32::<BigEndian>(entry.media_time as u32)?;
137 }
138 writer.write_u16::<BigEndian>(entry.media_rate)?;
139 writer.write_u16::<BigEndian>(entry.media_rate_fraction)?;
140 }
141
142 Ok(size)
143 }
144}
145
146#[cfg(test)]
147mod tests {
148 use super::*;
149 use crate::mp4box::BoxHeader;
150 use std::io::Cursor;
151
152 #[test]
153 fn test_elst32() {
154 let src_box = ElstBox {
155 version: 0,
156 flags: 0,
157 entries: vec![ElstEntry {
158 segment_duration: 634634,
159 media_time: 0,
160 media_rate: 1,
161 media_rate_fraction: 0,
162 }],
163 };
164 let mut buf = Vec::new();
165 src_box.write_box(&mut buf).unwrap();
166 assert_eq!(buf.len(), src_box.box_size() as usize);
167
168 let mut reader = Cursor::new(&buf);
169 let header = BoxHeader::read(&mut reader).unwrap();
170 assert_eq!(header.name, BoxType::ElstBox);
171 assert_eq!(src_box.box_size(), header.size);
172
173 let dst_box = ElstBox::read_box(&mut reader, header.size).unwrap();
174 assert_eq!(src_box, dst_box);
175 }
176
177 #[test]
178 fn test_elst64() {
179 let src_box = ElstBox {
180 version: 1,
181 flags: 0,
182 entries: vec![ElstEntry {
183 segment_duration: 634634,
184 media_time: 0,
185 media_rate: 1,
186 media_rate_fraction: 0,
187 }],
188 };
189 let mut buf = Vec::new();
190 src_box.write_box(&mut buf).unwrap();
191 assert_eq!(buf.len(), src_box.box_size() as usize);
192
193 let mut reader = Cursor::new(&buf);
194 let header = BoxHeader::read(&mut reader).unwrap();
195 assert_eq!(header.name, BoxType::ElstBox);
196 assert_eq!(src_box.box_size(), header.size);
197
198 let dst_box = ElstBox::read_box(&mut reader, header.size).unwrap();
199 assert_eq!(src_box, dst_box);
200 }
201}