scuffle_mp4/boxes/types/
stsz.rs

1use std::io;
2
3use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
4use bytes::Bytes;
5
6use crate::boxes::header::{BoxHeader, FullBoxHeader};
7use crate::boxes::traits::BoxType;
8
9#[derive(Debug, Clone, PartialEq)]
10/// Sample Size Box
11/// ISO/IEC 14496-12:2022(E) - 8.7.3.2
12pub struct Stsz {
13    pub header: FullBoxHeader,
14    pub sample_size: u32,
15    pub samples: Vec<u32>,
16}
17
18impl Stsz {
19    pub fn new(sample_size: u32, samples: Vec<u32>) -> Self {
20        Self {
21            header: FullBoxHeader::new(Self::NAME, 0, 0),
22            sample_size,
23            samples,
24        }
25    }
26}
27
28impl BoxType for Stsz {
29    const NAME: [u8; 4] = *b"stsz";
30
31    fn demux(header: BoxHeader, data: Bytes) -> io::Result<Self> {
32        let mut reader = io::Cursor::new(data);
33
34        let header = FullBoxHeader::demux(header, &mut reader)?;
35
36        let sample_size = reader.read_u32::<BigEndian>()?;
37        let sample_count = reader.read_u32::<BigEndian>()?;
38
39        let mut samples = Vec::with_capacity(sample_count as usize);
40        if sample_size == 0 {
41            for _ in 0..sample_count {
42                let size = reader.read_u32::<BigEndian>()?;
43                samples.push(size);
44            }
45        }
46
47        Ok(Self {
48            header,
49            sample_size,
50            samples,
51        })
52    }
53
54    fn primitive_size(&self) -> u64 {
55        let size = self.header.size();
56        let size = size + 8; // sample_size + sample_count
57
58        if self.sample_size == 0 {
59            size + (self.samples.len() as u64 * 4) // samples
60        } else {
61            size
62        }
63    }
64
65    fn primitive_mux<T: io::Write>(&self, writer: &mut T) -> io::Result<()> {
66        self.header.mux(writer)?;
67
68        writer.write_u32::<BigEndian>(self.sample_size)?;
69        writer.write_u32::<BigEndian>(self.samples.len() as u32)?;
70
71        if self.sample_size == 0 {
72            for size in &self.samples {
73                writer.write_u32::<BigEndian>(*size)?;
74            }
75        }
76
77        Ok(())
78    }
79
80    fn validate(&self) -> io::Result<()> {
81        if self.sample_size != 0 && !self.samples.is_empty() {
82            return Err(io::Error::new(
83                io::ErrorKind::InvalidData,
84                "stsz: sample_size is not 0 but samples are present",
85            ));
86        }
87
88        if self.header.version != 0 {
89            return Err(io::Error::new(io::ErrorKind::InvalidData, "stsz box version must be 0"));
90        }
91
92        if self.header.flags != 0 {
93            return Err(io::Error::new(io::ErrorKind::InvalidData, "stsz box flags must be 0"));
94        }
95
96        Ok(())
97    }
98}