scuffle_mp4/boxes/types/
subs.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 Subs {
13 pub header: FullBoxHeader,
14
15 pub entries: Vec<SubsEntry>,
16}
17
18#[derive(Debug, Clone, PartialEq)]
19pub struct SubsEntry {
21 pub sample_delta: u32,
22 pub subsamples: Vec<SubSampleEntry>,
23}
24
25#[derive(Debug, Clone, PartialEq)]
26pub struct SubSampleEntry {
28 pub subsample_size: u32,
29 pub subsample_priority: u8,
30 pub discardable: u8,
31 pub codec_specific_parameters: u32,
32}
33
34impl BoxType for Subs {
35 const NAME: [u8; 4] = *b"subs";
36
37 fn demux(header: BoxHeader, data: Bytes) -> io::Result<Self> {
38 let mut reader = io::Cursor::new(data);
39
40 let header = FullBoxHeader::demux(header, &mut reader)?;
41
42 let entry_count = reader.read_u32::<BigEndian>()?;
43 let mut entries = Vec::with_capacity(entry_count as usize);
44
45 for _ in 0..entry_count {
46 let sample_delta = reader.read_u32::<BigEndian>()?;
47 let subsample_count = reader.read_u16::<BigEndian>()?;
48 let mut subsamples = Vec::with_capacity(subsample_count as usize);
49
50 for _ in 0..subsample_count {
51 let subsample_size = if header.version == 1 {
52 reader.read_u32::<BigEndian>()?
53 } else {
54 reader.read_u16::<BigEndian>()? as u32
55 };
56 let subsample_priority = reader.read_u8()?;
57 let discardable = reader.read_u8()?;
58 let codec_specific_parameters = reader.read_u32::<BigEndian>()?;
59 subsamples.push(SubSampleEntry {
60 subsample_size,
61 subsample_priority,
62 discardable,
63 codec_specific_parameters,
64 });
65 }
66
67 entries.push(SubsEntry {
68 sample_delta,
69 subsamples,
70 });
71 }
72
73 Ok(Self { header, entries })
74 }
75
76 fn primitive_size(&self) -> u64 {
77 let size = self.header.size();
78 let size = size + 4; let size = size
80 + self
81 .entries
82 .iter()
83 .map(|e| {
84 let size = 4; let size = size + 2; size + e.subsamples.len() as u64
88 * if self.header.version == 1 {
89 4 + 1 + 1 + 4
90 } else {
91 2 + 1 + 1 + 4
92 }
93 })
94 .sum::<u64>(); size
96 }
97
98 fn primitive_mux<T: io::Write>(&self, writer: &mut T) -> io::Result<()> {
99 self.header.mux(writer)?;
100
101 writer.write_u32::<BigEndian>(self.entries.len() as u32)?;
102 for entry in &self.entries {
103 writer.write_u32::<BigEndian>(entry.sample_delta)?;
104 writer.write_u16::<BigEndian>(entry.subsamples.len() as u16)?;
105 for subsample in &entry.subsamples {
106 if self.header.version == 1 {
107 writer.write_u32::<BigEndian>(subsample.subsample_size)?;
108 } else {
109 writer.write_u16::<BigEndian>(subsample.subsample_size as u16)?;
110 }
111 writer.write_u8(subsample.subsample_priority)?;
112 writer.write_u8(subsample.discardable)?;
113 writer.write_u32::<BigEndian>(subsample.codec_specific_parameters)?;
114 }
115 }
116
117 Ok(())
118 }
119
120 fn validate(&self) -> io::Result<()> {
121 if self.header.version > 1 {
122 return Err(io::Error::new(io::ErrorKind::InvalidData, "subs version must be 0 or 1"));
123 }
124
125 if self.header.version == 0 {
126 for entry in &self.entries {
127 for subsample in &entry.subsamples {
128 if subsample.subsample_size > u16::MAX as u32 {
129 return Err(io::Error::new(
130 io::ErrorKind::InvalidData,
131 "subs subsample_size must be less than 2^16",
132 ));
133 }
134 }
135 }
136 }
137
138 Ok(())
139 }
140}