1use std::fmt::Debug;
2use std::io::{
3 Read, Write, {self},
4};
5
6use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
7use bytes::Bytes;
8
9use super::clap::Clap;
10use super::colr::Colr;
11use super::pasp::Pasp;
12use crate::boxes::DynBox;
13use crate::boxes::header::{BoxHeader, FullBoxHeader};
14use crate::boxes::traits::BoxType;
15
16#[derive(Debug, Clone, PartialEq)]
17pub struct Stsd {
20 pub header: FullBoxHeader,
21 pub entries: Vec<DynBox>,
22}
23
24impl Stsd {
25 pub fn new(entries: Vec<DynBox>) -> Self {
26 Self {
27 header: FullBoxHeader::new(Self::NAME, 0, 0),
28 entries,
29 }
30 }
31
32 pub fn get_codecs(&self) -> impl Iterator<Item = String> + '_ {
33 self.entries.iter().filter_map(|e| match e {
34 DynBox::Av01(av01) => av01.codec().ok().map(|c| c.to_string()),
35 DynBox::Avc1(avc1) => avc1.codec().ok().map(|c| c.to_string()),
36 DynBox::Hev1(hev1) => hev1.codec().ok().map(|c| c.to_string()),
37 DynBox::Opus(opus) => opus.codec().ok().map(|c| c.to_string()),
38 DynBox::Mp4a(mp4a) => mp4a.codec().ok().map(|c| c.to_string()),
39 _ => None,
40 })
41 }
42
43 pub fn is_audio(&self) -> bool {
44 self.entries.iter().any(|e| matches!(e, DynBox::Mp4a(_) | DynBox::Opus(_)))
45 }
46
47 pub fn is_video(&self) -> bool {
48 self.entries
49 .iter()
50 .any(|e| matches!(e, DynBox::Av01(_) | DynBox::Avc1(_) | DynBox::Hev1(_)))
51 }
52}
53
54#[derive(Debug, Clone, PartialEq)]
55pub struct SampleEntry<T: SampleEntryExtension> {
59 pub reserved: [u8; 6],
60 pub data_reference_index: u16,
61 pub extension: T,
62}
63
64impl<T: SampleEntryExtension> SampleEntry<T> {
65 pub fn new(extension: T) -> Self {
66 Self {
67 reserved: [0; 6],
68 data_reference_index: 1,
69 extension,
70 }
71 }
72}
73
74pub trait SampleEntryExtension: Debug + Clone + PartialEq {
75 fn demux<R: Read>(reader: &mut R) -> io::Result<Self>
76 where
77 Self: Sized;
78
79 fn size(&self) -> u64;
80
81 fn mux<W: Write>(&self, writer: &mut W) -> io::Result<()>;
82
83 fn validate(&self) -> io::Result<()> {
84 Ok(())
85 }
86}
87
88impl<T: SampleEntryExtension> SampleEntry<T> {
89 pub fn demux<R: Read>(reader: &mut R) -> io::Result<Self> {
90 let mut reserved = [0; 6];
91 reader.read_exact(&mut reserved)?;
92
93 let data_reference_index = reader.read_u16::<BigEndian>()?;
94
95 Ok(Self {
96 reserved,
97 data_reference_index,
98 extension: T::demux(reader)?,
99 })
100 }
101
102 pub fn size(&self) -> u64 {
103 6 + 2 + self.extension.size()
106 }
107
108 pub fn mux<W: Write>(&self, writer: &mut W) -> io::Result<()> {
109 self.validate()?;
110
111 writer.write_all(&self.reserved)?;
112 writer.write_u16::<BigEndian>(self.data_reference_index)?;
113 self.extension.mux(writer)?;
114
115 Ok(())
116 }
117
118 pub fn validate(&self) -> io::Result<()> {
119 if self.reserved != [0; 6] {
120 return Err(io::Error::new(
121 io::ErrorKind::InvalidData,
122 "sample entry reserved field must be 0",
123 ));
124 }
125
126 self.extension.validate()?;
127
128 Ok(())
129 }
130}
131
132#[derive(Debug, Clone, PartialEq)]
133pub struct AudioSampleEntry {
136 pub reserved: [u32; 2],
137 pub channel_count: u16,
138 pub sample_size: u16,
139 pub pre_defined: u16,
140 pub reserved2: u16,
141 pub sample_rate: u32,
142}
143
144impl AudioSampleEntry {
145 pub fn new(channel_count: u16, sample_size: u16, sample_rate: u32) -> Self {
146 Self {
147 reserved: [0, 0],
148 channel_count,
149 sample_size,
150 pre_defined: 0,
151 reserved2: 0,
152 sample_rate,
153 }
154 }
155}
156
157impl SampleEntryExtension for AudioSampleEntry {
158 fn demux<T: io::Read>(reader: &mut T) -> io::Result<Self> {
159 let reserved = [reader.read_u32::<BigEndian>()?, reader.read_u32::<BigEndian>()?];
160
161 let channel_count = reader.read_u16::<BigEndian>()?;
162 let sample_size = reader.read_u16::<BigEndian>()?;
163 let pre_defined = reader.read_u16::<BigEndian>()?;
164 let reserved2 = reader.read_u16::<BigEndian>()?;
165 let sample_rate = reader.read_u32::<BigEndian>()? >> 16;
166
167 Ok(Self {
168 reserved,
169 channel_count,
170 sample_size,
171 pre_defined,
172 reserved2,
173 sample_rate,
174 })
175 }
176
177 fn size(&self) -> u64 {
178 4 + 4 + 2 + 2 + 2 + 2 + 4 }
186
187 fn mux<T: io::Write>(&self, writer: &mut T) -> io::Result<()> {
188 writer.write_u32::<BigEndian>(self.reserved[0])?;
189 writer.write_u32::<BigEndian>(self.reserved[1])?;
190 writer.write_u16::<BigEndian>(self.channel_count)?;
191 writer.write_u16::<BigEndian>(self.sample_size)?;
192 writer.write_u16::<BigEndian>(self.pre_defined)?;
193 writer.write_u16::<BigEndian>(self.reserved2)?;
194 writer.write_u32::<BigEndian>(self.sample_rate << 16)?;
195
196 Ok(())
197 }
198
199 fn validate(&self) -> io::Result<()> {
200 if self.reserved != [0, 0] {
201 return Err(io::Error::new(io::ErrorKind::InvalidData, "reserved field must be 0"));
202 }
203
204 if self.pre_defined != 0 {
205 return Err(io::Error::new(io::ErrorKind::InvalidData, "pre_defined field must be 0"));
206 }
207
208 if self.reserved2 != 0 {
209 return Err(io::Error::new(io::ErrorKind::InvalidData, "reserved2 field must be 0"));
210 }
211
212 Ok(())
213 }
214}
215
216#[derive(Debug, Clone, PartialEq)]
217pub struct VisualSampleEntry {
220 pub pre_defined: u16,
221 pub reserved: u16,
222 pub pre_defined2: [u32; 3],
223 pub width: u16,
224 pub height: u16,
225 pub horizresolution: u32,
226 pub vertresolution: u32,
227 pub reserved2: u32,
228 pub frame_count: u16,
229 pub compressorname: [u8; 32],
230 pub depth: u16,
231 pub pre_defined3: i16,
232 pub clap: Option<Clap>,
233 pub colr: Option<Colr>,
234 pub pasp: Option<Pasp>,
235}
236
237impl VisualSampleEntry {
238 pub fn new(width: u16, height: u16, colr: Option<Colr>) -> Self {
239 Self {
240 pre_defined: 0,
241 reserved: 0,
242 pre_defined2: [0, 0, 0],
243 width,
244 height,
245 horizresolution: 0x00480000,
246 vertresolution: 0x00480000,
247 reserved2: 0,
248 frame_count: 1,
249 compressorname: [0; 32],
250 depth: 0x0018,
251 pre_defined3: -1,
252 clap: None,
253 colr,
254 pasp: Some(Pasp::new()),
255 }
256 }
257}
258
259impl SampleEntryExtension for VisualSampleEntry {
260 fn demux<T: io::Read>(reader: &mut T) -> io::Result<Self> {
261 let pre_defined = reader.read_u16::<BigEndian>()?;
262 let reserved = reader.read_u16::<BigEndian>()?;
263 let pre_defined2 = [
264 reader.read_u32::<BigEndian>()?,
265 reader.read_u32::<BigEndian>()?,
266 reader.read_u32::<BigEndian>()?,
267 ];
268 let width = reader.read_u16::<BigEndian>()?;
269 let height = reader.read_u16::<BigEndian>()?;
270 let horizresolution = reader.read_u32::<BigEndian>()?;
271 let vertresolution = reader.read_u32::<BigEndian>()?;
272 let reserved2 = reader.read_u32::<BigEndian>()?;
273 let frame_count = reader.read_u16::<BigEndian>()?;
274 let mut compressorname = [0; 32];
275 reader.read_exact(&mut compressorname)?;
276 let depth = reader.read_u16::<BigEndian>()?;
277 let pre_defined3 = reader.read_i16::<BigEndian>()?;
278
279 Ok(Self {
280 pre_defined,
281 reserved,
282 pre_defined2,
283 width,
284 height,
285 horizresolution,
286 vertresolution,
287 reserved2,
288 frame_count,
289 compressorname,
290 depth,
291 pre_defined3,
292 colr: None,
293 clap: None,
294 pasp: None,
295 })
296 }
297
298 fn size(&self) -> u64 {
299 2 + 2 + 4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 2 + 32 + 2 + 2 + self.clap.as_ref().map_or(0, |clap| clap.size())
314 + self.pasp.as_ref().map_or(0, |pasp| pasp.size())
315 + self.colr.as_ref().map_or(0, |colr| colr.size())
316 }
317
318 fn mux<T: io::Write>(&self, writer: &mut T) -> io::Result<()> {
319 writer.write_u16::<BigEndian>(self.pre_defined).unwrap();
320 writer.write_u16::<BigEndian>(self.reserved).unwrap();
321 writer.write_u32::<BigEndian>(self.pre_defined2[0]).unwrap();
322 writer.write_u32::<BigEndian>(self.pre_defined2[1]).unwrap();
323 writer.write_u32::<BigEndian>(self.pre_defined2[2]).unwrap();
324 writer.write_u16::<BigEndian>(self.width).unwrap();
325 writer.write_u16::<BigEndian>(self.height).unwrap();
326 writer.write_u32::<BigEndian>(self.horizresolution).unwrap();
327 writer.write_u32::<BigEndian>(self.vertresolution).unwrap();
328 writer.write_u32::<BigEndian>(self.reserved2).unwrap();
329 writer.write_u16::<BigEndian>(self.frame_count).unwrap();
330 writer.write_all(&self.compressorname).unwrap();
331 writer.write_u16::<BigEndian>(self.depth).unwrap();
332 writer.write_i16::<BigEndian>(self.pre_defined3).unwrap();
333 if let Some(clap) = &self.clap {
334 clap.mux(writer).unwrap();
335 }
336 if let Some(pasp) = &self.pasp {
337 pasp.mux(writer).unwrap();
338 }
339 if let Some(colr) = &self.colr {
340 colr.mux(writer).unwrap();
341 }
342 Ok(())
343 }
344
345 fn validate(&self) -> io::Result<()> {
346 if self.pre_defined != 0 {
347 return Err(io::Error::new(io::ErrorKind::InvalidData, "pre_defined field must be 0"));
348 }
349
350 if self.reserved != 0 {
351 return Err(io::Error::new(io::ErrorKind::InvalidData, "reserved field must be 0"));
352 }
353
354 if self.pre_defined2 != [0, 0, 0] {
355 return Err(io::Error::new(io::ErrorKind::InvalidData, "pre_defined2 field must be 0"));
356 }
357
358 if self.reserved2 != 0 {
359 return Err(io::Error::new(io::ErrorKind::InvalidData, "reserved2 field must be 0"));
360 }
361
362 if self.pre_defined3 != -1 {
363 return Err(io::Error::new(io::ErrorKind::InvalidData, "pre_defined3 field must be -1"));
364 }
365
366 Ok(())
367 }
368}
369
370impl BoxType for Stsd {
371 const NAME: [u8; 4] = *b"stsd";
372
373 fn demux(header: BoxHeader, data: Bytes) -> io::Result<Self> {
374 let mut reader = io::Cursor::new(data);
375
376 let header = FullBoxHeader::demux(header, &mut reader)?;
377
378 let entry_count = reader.read_u32::<BigEndian>()?;
379 let mut entries = Vec::with_capacity(entry_count as usize);
380
381 for _ in 0..entry_count {
382 let entry = DynBox::demux(&mut reader)?;
383 entries.push(entry);
384 }
385
386 Ok(Self { header, entries })
387 }
388
389 fn primitive_size(&self) -> u64 {
390 self.header.size()
391 + 4 + self.entries.iter().map(|entry| entry.size()).sum::<u64>()
393 }
394
395 fn primitive_mux<T: io::Write>(&self, writer: &mut T) -> io::Result<()> {
396 self.header.mux(writer)?;
397 writer.write_u32::<BigEndian>(self.entries.len() as u32)?;
398 for entry in &self.entries {
399 entry.mux(writer)?;
400 }
401 Ok(())
402 }
403
404 fn validate(&self) -> io::Result<()> {
405 if self.header.flags != 0 {
406 return Err(io::Error::new(io::ErrorKind::InvalidData, "stsd flags must be 0"));
407 }
408
409 if self.header.version != 0 {
410 return Err(io::Error::new(io::ErrorKind::InvalidData, "stsd version must be 0"));
411 }
412
413 Ok(())
414 }
415}