scuffle_mp4/boxes/types/
sbgp.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 Sbgp {
13 pub header: FullBoxHeader,
14 pub grouping_type: Option<u32>,
15 pub entries: Vec<SbgpEntry>,
16}
17
18#[derive(Debug, Clone, PartialEq)]
19pub struct SbgpEntry {
20 pub sample_count: u32,
21 pub group_description_index: u32,
22}
23
24impl BoxType for Sbgp {
25 const NAME: [u8; 4] = *b"sbgp";
26
27 fn demux(header: BoxHeader, data: Bytes) -> io::Result<Self> {
28 let mut data = io::Cursor::new(data);
29
30 let header = FullBoxHeader::demux(header, &mut data)?;
31
32 let grouping_type = if header.version == 1 {
33 Some(data.read_u32::<BigEndian>()?)
34 } else {
35 None
36 };
37 let entry_count = data.read_u32::<BigEndian>()?;
38
39 let mut entries = Vec::with_capacity(entry_count as usize);
40
41 for _ in 0..entry_count {
42 let sample_count = data.read_u32::<BigEndian>()?;
43 let group_description_index = data.read_u32::<BigEndian>()?;
44
45 entries.push(SbgpEntry {
46 sample_count,
47 group_description_index,
48 });
49 }
50
51 Ok(Self {
52 header,
53 grouping_type,
54 entries,
55 })
56 }
57
58 fn primitive_size(&self) -> u64 {
59 self.header.size()
60 + 4 + 4 + (self.entries.len() as u64 * 8) }
64
65 fn primitive_mux<T: io::Write>(&self, writer: &mut T) -> io::Result<()> {
66 self.header.mux(writer)?;
67
68 if let Some(grouping_type) = self.grouping_type {
69 writer.write_u32::<BigEndian>(grouping_type)?;
70 }
71
72 writer.write_u32::<BigEndian>(self.entries.len() as u32)?;
73
74 for entry in &self.entries {
75 writer.write_u32::<BigEndian>(entry.sample_count)?;
76 writer.write_u32::<BigEndian>(entry.group_description_index)?;
77 }
78
79 Ok(())
80 }
81
82 fn validate(&self) -> io::Result<()> {
83 if self.header.version > 1 {
84 return Err(io::Error::new(io::ErrorKind::InvalidData, "sbgp box version must be 0 or 1"));
85 }
86
87 if self.header.flags != 0 {
88 return Err(io::Error::new(io::ErrorKind::InvalidData, "sbgp box flags must be 0"));
89 }
90
91 if self.header.version == 1 && self.grouping_type.is_none() {
92 return Err(io::Error::new(
93 io::ErrorKind::InvalidData,
94 "sbgp box grouping_type must be present when version is 1",
95 ));
96 } else if self.header.version == 0 && self.grouping_type.is_some() {
97 return Err(io::Error::new(
98 io::ErrorKind::InvalidData,
99 "sbgp box grouping_type must not be present when version is 0",
100 ));
101 }
102
103 Ok(())
104 }
105}