flowly_mp4/mp4box/
stts.rs1use byteorder::{BigEndian, WriteBytesExt};
2use serde::Serialize;
3use std::io::Write;
4use std::mem::size_of;
5
6use crate::mp4box::*;
7
8#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
9pub struct SttsBox {
10 pub version: u8,
11 pub flags: u32,
12
13 #[serde(skip_serializing)]
14 pub entries: Vec<SttsEntry>,
15}
16
17impl SttsBox {
18 pub fn get_type(&self) -> BoxType {
19 BoxType::SttsBox
20 }
21
22 pub fn get_size(&self) -> u64 {
23 HEADER_SIZE + HEADER_EXT_SIZE + 4 + (8 * self.entries.len() as u64)
24 }
25}
26
27#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
28pub struct SttsEntry {
29 pub sample_count: u32,
30 pub sample_delta: u32,
31}
32
33impl Mp4Box for SttsBox {
34 const TYPE: BoxType = BoxType::SttsBox;
35
36 fn box_size(&self) -> u64 {
37 self.get_size()
38 }
39
40 fn to_json(&self) -> Result<String, Error> {
41 Ok(serde_json::to_string(&self).unwrap())
42 }
43
44 fn summary(&self) -> Result<String, Error> {
45 let s = format!("entries={}", self.entries.len());
46 Ok(s)
47 }
48}
49
50impl BlockReader for SttsBox {
51 fn read_block<'a>(reader: &mut impl Reader<'a>) -> Result<Self, Error> {
52 let (version, flags) = read_box_header_ext(reader);
53
54 let entry_size = size_of::<u32>() + size_of::<u32>(); let entry_count = reader.get_u32();
56
57 if entry_count as usize > reader.remaining() / entry_size {
58 return Err(Error::InvalidData(
59 "stts entry_count indicates more entries than could fit in the box",
60 ));
61 }
62
63 let mut entries = Vec::with_capacity(entry_count as usize);
64 for _i in 0..entry_count {
65 let entry = SttsEntry {
66 sample_count: reader.get_u32(),
67 sample_delta: reader.get_u32(),
68 };
69 entries.push(entry);
70 }
71
72 Ok(SttsBox {
73 version,
74 flags,
75 entries,
76 })
77 }
78
79 fn size_hint() -> usize {
80 8
81 }
82}
83
84impl<W: Write> WriteBox<&mut W> for SttsBox {
85 fn write_box(&self, writer: &mut W) -> Result<u64, Error> {
86 let size = self.box_size();
87 BoxHeader::new(Self::TYPE, size).write(writer)?;
88
89 write_box_header_ext(writer, self.version, self.flags)?;
90
91 writer.write_u32::<BigEndian>(self.entries.len() as u32)?;
92 for entry in self.entries.iter() {
93 writer.write_u32::<BigEndian>(entry.sample_count)?;
94 writer.write_u32::<BigEndian>(entry.sample_delta)?;
95 }
96
97 Ok(size)
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104 use crate::mp4box::BoxHeader;
105
106 #[tokio::test]
107 async fn test_stts() {
108 let src_box = SttsBox {
109 version: 0,
110 flags: 0,
111 entries: vec![
112 SttsEntry {
113 sample_count: 29726,
114 sample_delta: 1024,
115 },
116 SttsEntry {
117 sample_count: 1,
118 sample_delta: 512,
119 },
120 ],
121 };
122 let mut buf = Vec::new();
123 src_box.write_box(&mut buf).unwrap();
124 assert_eq!(buf.len(), src_box.box_size() as usize);
125
126 let mut reader = buf.as_slice();
127 let header = BoxHeader::read(&mut reader, &mut 0).await.unwrap().unwrap();
128 assert_eq!(header.kind, BoxType::SttsBox);
129 assert_eq!(src_box.box_size(), header.size);
130
131 let dst_box = SttsBox::read_block(&mut reader).unwrap();
132 assert_eq!(src_box, dst_box);
133 }
134}