flowly_mp4/mp4box/
stco.rs

1use 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 StcoBox {
10    pub version: u8,
11    pub flags: u32,
12
13    #[serde(skip_serializing)]
14    pub entries: Vec<u32>,
15}
16
17impl<'a> IntoIterator for &'a StcoBox {
18    type Item = u64;
19    type IntoIter = std::iter::Map<std::iter::Copied<std::slice::Iter<'a, u32>>, fn(u32) -> u64>;
20
21    #[inline]
22    fn into_iter(self) -> Self::IntoIter {
23        self.entries.iter().copied().map(Into::<u64>::into)
24    }
25}
26
27impl IntoIterator for StcoBox {
28    type Item = u64;
29    type IntoIter = std::iter::Map<std::vec::IntoIter<u32>, fn(u32) -> u64>;
30
31    #[inline]
32    fn into_iter(self) -> Self::IntoIter {
33        self.entries.into_iter().map(Into::<u64>::into)
34    }
35}
36
37impl StcoBox {
38    pub fn get_type(&self) -> BoxType {
39        BoxType::StcoBox
40    }
41
42    pub fn get_size(&self) -> u64 {
43        HEADER_SIZE + HEADER_EXT_SIZE + 4 + (4 * self.entries.len() as u64)
44    }
45}
46
47impl Mp4Box for StcoBox {
48    const TYPE: BoxType = BoxType::StcoBox;
49
50    fn box_size(&self) -> u64 {
51        self.get_size()
52    }
53
54    fn to_json(&self) -> Result<String, Error> {
55        Ok(serde_json::to_string(&self).unwrap())
56    }
57
58    fn summary(&self) -> Result<String, Error> {
59        let s = format!("entries={}", self.entries.len());
60        Ok(s)
61    }
62}
63
64impl BlockReader for StcoBox {
65    fn read_block<'a>(reader: &mut impl Reader<'a>) -> Result<Self, Error> {
66        let (version, flags) = read_box_header_ext(reader);
67
68        let entry_size = size_of::<u32>(); // chunk_offset
69        let entry_count = reader.get_u32();
70        if entry_count as usize > reader.remaining() / entry_size {
71            return Err(Error::InvalidData(
72                "stco entry_count indicates more entries than could fit in the box",
73            ));
74        }
75
76        let mut entries = Vec::with_capacity(entry_count as usize);
77        for _i in 0..entry_count {
78            let chunk_offset = reader.get_u32();
79            entries.push(chunk_offset);
80        }
81
82        Ok(StcoBox {
83            version,
84            flags,
85            entries,
86        })
87    }
88
89    fn size_hint() -> usize {
90        8
91    }
92}
93
94impl<W: Write> WriteBox<&mut W> for StcoBox {
95    fn write_box(&self, writer: &mut W) -> Result<u64, Error> {
96        let size = self.box_size();
97        BoxHeader::new(Self::TYPE, size).write(writer)?;
98
99        write_box_header_ext(writer, self.version, self.flags)?;
100
101        writer.write_u32::<BigEndian>(self.entries.len() as u32)?;
102        for chunk_offset in self.entries.iter() {
103            writer.write_u32::<BigEndian>(*chunk_offset)?;
104        }
105
106        Ok(size)
107    }
108}
109
110impl std::convert::TryFrom<&co64::Co64Box> for StcoBox {
111    type Error = std::num::TryFromIntError;
112
113    fn try_from(co64: &co64::Co64Box) -> std::result::Result<Self, Self::Error> {
114        let entries = co64
115            .entries
116            .iter()
117            .copied()
118            .map(u32::try_from)
119            .collect::<std::result::Result<Vec<_>, _>>()?;
120        Ok(Self {
121            version: 0,
122            flags: 0,
123            entries,
124        })
125    }
126}
127
128#[cfg(test)]
129mod tests {
130    use super::*;
131    use crate::mp4box::BoxHeader;
132
133    #[tokio::test]
134    async fn test_stco() {
135        let src_box = StcoBox {
136            version: 0,
137            flags: 0,
138            entries: vec![267, 1970, 2535, 2803, 11843, 22223, 33584],
139        };
140        let mut buf = Vec::new();
141        src_box.write_box(&mut buf).unwrap();
142        assert_eq!(buf.len(), src_box.box_size() as usize);
143
144        let mut reader = buf.as_slice();
145        let header = BoxHeader::read(&mut reader, &mut 0).await.unwrap().unwrap();
146        assert_eq!(header.kind, BoxType::StcoBox);
147        assert_eq!(src_box.box_size(), header.size);
148
149        let dst_box = StcoBox::read_block(&mut reader).unwrap();
150        assert_eq!(src_box, dst_box);
151    }
152}