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 StscBox {
10 pub version: u8,
11 pub flags: u32,
12
13 #[serde(skip_serializing)]
14 pub entries: Vec<StscEntry>,
15}
16
17impl StscBox {
18 pub fn get_type(&self) -> BoxType {
19 BoxType::StscBox
20 }
21
22 pub fn get_size(&self) -> u64 {
23 HEADER_SIZE + HEADER_EXT_SIZE + 4 + (12 * self.entries.len() as u64)
24 }
25}
26
27#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
28pub struct StscEntry {
29 pub first_chunk: u32,
30 pub samples_per_chunk: u32,
31 pub sample_description_index: u32,
32 pub first_sample: u32,
33}
34
35impl Mp4Box for StscBox {
36 fn box_type(&self) -> BoxType {
37 self.get_type()
38 }
39
40 fn box_size(&self) -> u64 {
41 self.get_size()
42 }
43
44 fn to_json(&self) -> Result<String> {
45 Ok(serde_json::to_string(&self).unwrap())
46 }
47
48 fn summary(&self) -> Result<String> {
49 let s = format!("entries={}", self.entries.len());
50 Ok(s)
51 }
52}
53
54impl<R: Read + Seek> ReadBox<&mut R> for StscBox {
55 fn read_box(reader: &mut R, size: u64) -> Result<Self> {
56 let start = box_start(reader)?;
57
58 let (version, flags) = read_box_header_ext(reader)?;
59
60 let header_size = HEADER_SIZE + HEADER_EXT_SIZE;
61 let other_size = size_of::<u32>(); let entry_size = size_of::<u32>() + size_of::<u32>() + size_of::<u32>(); let entry_count = reader.read_u32::<BigEndian>()?;
64 if u64::from(entry_count)
65 > size
66 .saturating_sub(header_size)
67 .saturating_sub(other_size as u64)
68 / entry_size as u64
69 {
70 return Err(Error::InvalidData(
71 "stsc entry_count indicates more entries than could fit in the box",
72 ));
73 }
74 let mut entries = Vec::with_capacity(entry_count as usize);
75 for _ in 0..entry_count {
76 let entry = StscEntry {
77 first_chunk: reader.read_u32::<BigEndian>()?,
78 samples_per_chunk: reader.read_u32::<BigEndian>()?,
79 sample_description_index: reader.read_u32::<BigEndian>()?,
80 first_sample: 0,
81 };
82 entries.push(entry);
83 }
84
85 let mut sample_id = 1;
86 for i in 0..entry_count {
87 let (first_chunk, samples_per_chunk) = {
88 let entry = entries.get_mut(i as usize).unwrap();
89 entry.first_sample = sample_id;
90 (entry.first_chunk, entry.samples_per_chunk)
91 };
92 if i < entry_count - 1 {
93 let next_entry = entries.get(i as usize + 1).unwrap();
94 sample_id = next_entry
95 .first_chunk
96 .checked_sub(first_chunk)
97 .and_then(|n| n.checked_mul(samples_per_chunk))
98 .and_then(|n| n.checked_add(sample_id))
99 .ok_or(Error::InvalidData(
100 "attempt to calculate stsc sample_id with overflow",
101 ))?;
102 }
103 }
104
105 skip_bytes_to(reader, start + size)?;
106
107 Ok(StscBox {
108 version,
109 flags,
110 entries,
111 })
112 }
113}
114
115impl<W: Write> WriteBox<&mut W> for StscBox {
116 fn write_box(&self, writer: &mut W) -> Result<u64> {
117 let size = self.box_size();
118 BoxHeader::new(self.box_type(), size).write(writer)?;
119
120 write_box_header_ext(writer, self.version, self.flags)?;
121
122 writer.write_u32::<BigEndian>(self.entries.len() as u32)?;
123 for entry in self.entries.iter() {
124 writer.write_u32::<BigEndian>(entry.first_chunk)?;
125 writer.write_u32::<BigEndian>(entry.samples_per_chunk)?;
126 writer.write_u32::<BigEndian>(entry.sample_description_index)?;
127 }
128
129 Ok(size)
130 }
131}
132
133#[cfg(test)]
134mod tests {
135 use super::*;
136 use crate::mp4box::BoxHeader;
137 use std::io::Cursor;
138
139 #[test]
140 fn test_stsc() {
141 let src_box = StscBox {
142 version: 0,
143 flags: 0,
144 entries: vec![
145 StscEntry {
146 first_chunk: 1,
147 samples_per_chunk: 1,
148 sample_description_index: 1,
149 first_sample: 1,
150 },
151 StscEntry {
152 first_chunk: 19026,
153 samples_per_chunk: 14,
154 sample_description_index: 1,
155 first_sample: 19026,
156 },
157 ],
158 };
159 let mut buf = Vec::new();
160 src_box.write_box(&mut buf).unwrap();
161 assert_eq!(buf.len(), src_box.box_size() as usize);
162
163 let mut reader = Cursor::new(&buf);
164 let header = BoxHeader::read(&mut reader).unwrap();
165 assert_eq!(header.name, BoxType::StscBox);
166 assert_eq!(src_box.box_size(), header.size);
167
168 let dst_box = StscBox::read_box(&mut reader, header.size).unwrap();
169 assert_eq!(src_box, dst_box);
170 }
171}