scuffle_mp4/boxes/types/
stts.rs1use 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)]
10pub struct Stts {
13 pub header: FullBoxHeader,
14 pub entries: Vec<SttsEntry>,
15}
16
17impl Stts {
18 pub fn new(entries: Vec<SttsEntry>) -> Self {
19 Self {
20 header: FullBoxHeader::new(Self::NAME, 0, 0),
21 entries,
22 }
23 }
24}
25
26#[derive(Debug, Clone, PartialEq)]
27pub struct SttsEntry {
29 pub sample_count: u32,
30 pub sample_delta: u32,
31}
32
33impl BoxType for Stts {
34 const NAME: [u8; 4] = *b"stts";
35
36 fn demux(header: BoxHeader, data: Bytes) -> io::Result<Self> {
37 let mut reader = io::Cursor::new(data);
38
39 let header = FullBoxHeader::demux(header, &mut reader)?;
40
41 let entry_count = reader.read_u32::<BigEndian>()?;
42 let mut entries = Vec::with_capacity(entry_count as usize);
43 for _ in 0..entry_count {
44 let sample_count = reader.read_u32::<BigEndian>()?;
45 let sample_delta = reader.read_u32::<BigEndian>()?;
46 entries.push(SttsEntry {
47 sample_count,
48 sample_delta,
49 });
50 }
51
52 Ok(Self { header, entries })
53 }
54
55 fn primitive_size(&self) -> u64 {
56 let size = self.header.size();
57 let size = size + 4; size + (self.entries.len() as u64 * 8)
60 }
61
62 fn primitive_mux<T: io::Write>(&self, writer: &mut T) -> io::Result<()> {
63 self.header.mux(writer)?;
64
65 writer.write_u32::<BigEndian>(self.entries.len() as u32)?;
66 for entry in &self.entries {
67 writer.write_u32::<BigEndian>(entry.sample_count)?;
68 writer.write_u32::<BigEndian>(entry.sample_delta)?;
69 }
70
71 Ok(())
72 }
73
74 fn validate(&self) -> io::Result<()> {
75 if self.header.version != 0 {
76 return Err(io::Error::new(io::ErrorKind::InvalidData, "stts version must be 0"));
77 }
78
79 if self.header.flags != 0 {
80 return Err(io::Error::new(io::ErrorKind::InvalidData, "stts flags must be 0"));
81 }
82
83 Ok(())
84 }
85}