mp4_atom/moov/trak/mdia/minf/stbl/stsd/
spatial.rs1use crate::*;
2
3#[derive(Debug, Clone, PartialEq, Default)]
32#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
33#[cfg_attr(feature = "serde", serde(default))]
34pub struct Spatial {
35 pub st3d: Option<St3d>,
36 pub sv3d: Option<Sv3d>,
37 pub vexu: Option<Vexu>,
38 pub hfov: Option<Hfov>,
39 pub unknown: Vec<Any>,
41}
42
43impl Eq for Spatial {}
44
45impl Spatial {
46 pub(crate) fn decode_child<T: Atom>(
49 spatial: &mut Option<Box<Spatial>>,
50 atom: Any,
51 ) -> Result<()> {
52 match atom {
53 Any::Unknown(kind @ (St3d::KIND | Sv3d::KIND | Vexu::KIND | Hfov::KIND), body) => {
54 let spatial: &mut Spatial = spatial.get_or_insert_with(Default::default);
55 let unknown = &mut spatial.unknown;
56 match kind {
57 St3d::KIND => decode_slot(T::KIND, &mut spatial.st3d, &body, unknown),
58 Sv3d::KIND => decode_slot(T::KIND, &mut spatial.sv3d, &body, unknown),
59 Vexu::KIND => decode_slot(T::KIND, &mut spatial.vexu, &body, unknown),
60 _ => decode_slot(T::KIND, &mut spatial.hfov, &body, unknown),
61 }
62 Ok(())
63 }
64 atom => T::decode_unknown(&atom),
65 }
66 }
67}
68
69impl Encode for Spatial {
70 fn encode<B: BufMut>(&self, buf: &mut B) -> Result<()> {
71 self.st3d.encode(buf)?;
72 encode_kept(&self.unknown, |kind| kind == St3d::KIND, buf)?;
73 self.sv3d.encode(buf)?;
74 encode_kept(&self.unknown, |kind| kind == Sv3d::KIND, buf)?;
75 self.vexu.encode(buf)?;
76 encode_kept(&self.unknown, |kind| kind == Vexu::KIND, buf)?;
77 self.hfov.encode(buf)?;
78 encode_kept(&self.unknown, |kind| kind == Hfov::KIND, buf)?;
79 encode_kept(
80 &self.unknown,
81 |kind| !matches!(kind, St3d::KIND | Sv3d::KIND | Vexu::KIND | Hfov::KIND),
82 buf,
83 )
84 }
85}
86
87#[derive(Debug, Clone, Copy, Default)]
91pub(crate) struct FullBoxV0;
92
93impl Ext for FullBoxV0 {
94 fn encode(&self) -> Result<u32> {
95 Ok(0)
96 }
97
98 fn decode(v: u32) -> Result<Self> {
99 match v {
100 0 => Ok(Self),
101 v if v >> 24 != 0 => Err(Error::UnknownVersion((v >> 24) as u8)),
102 _ => Err(Error::Unsupported("non-zero FullBox flags")),
103 }
104 }
105}
106
107pub(super) fn ignore_trailing<B: Buf>(kind: FourCC, buf: &mut B) {
110 if buf.has_remaining() {
111 tracing::warn!(%kind, bytes = buf.remaining(), "ignoring trailing bytes");
112 buf.advance(buf.remaining());
113 }
114}
115
116pub(super) fn decode_children<B: Buf>(
119 buf: &mut B,
120 mut child: impl FnMut(FourCC, &[u8]),
121) -> Result<()> {
122 while let Some(header) = Header::decode_maybe(buf)? {
123 let size = header.size.unwrap_or(buf.remaining());
124 if size > buf.remaining() {
125 return Err(Error::OutOfBounds);
126 }
127 child(header.kind, buf.slice(size));
128 buf.advance(size);
129 }
130 skip_trailing_padding(buf);
132 Ok(())
133}
134
135pub(super) fn decode_slot<T: Atom>(
138 parent: FourCC,
139 slot: &mut Option<T>,
140 body: &[u8],
141 unknown: &mut Vec<Any>,
142) {
143 decode_variant(parent, slot, body, unknown, |atom: T| atom)
144}
145
146pub(super) fn decode_variant<T: Atom, S>(
149 parent: FourCC,
150 slot: &mut Option<S>,
151 body: &[u8],
152 unknown: &mut Vec<Any>,
153 wrap: impl FnOnce(T) -> S,
154) {
155 let decoded = match slot {
156 Some(_) => Err(Error::DuplicateBox(T::KIND)),
157 None => decode_exact::<T>(body),
158 };
159 match decoded {
160 Ok(atom) => *slot = Some(wrap(atom)),
161 Err(err) => keep_invalid(parent, T::KIND, body, err, unknown),
162 }
163}
164
165fn decode_exact<T: Atom>(mut body: &[u8]) -> Result<T> {
166 let atom = T::decode_body(&mut body)?;
167 match body.is_empty() {
168 true => Ok(atom),
169 false => Err(Error::UnderDecode(T::KIND)),
170 }
171}
172
173pub(super) fn keep_invalid(
175 parent: FourCC,
176 kind: FourCC,
177 body: &[u8],
178 err: Error,
179 unknown: &mut Vec<Any>,
180) {
181 tracing::warn!(%kind, %parent, %err, "keeping spatial box verbatim");
182 unknown.push(Any::Unknown(kind, body.to_vec()));
183}
184
185pub(super) fn encode_kept<B: BufMut>(
187 unknown: &[Any],
188 kind: impl Fn(FourCC) -> bool,
189 buf: &mut B,
190) -> Result<()> {
191 unknown
192 .iter()
193 .filter(|atom| kind(atom.kind()))
194 .try_for_each(|atom| atom.encode(buf))
195}
196
197macro_rules! spatial_children {
205 ($($field:ident: $atom:ident),* $(; last $last:ident: $last_atom:ident)? $(,)?) => {
206 fn decode_body<B: Buf>(buf: &mut B) -> Result<Self> {
207 let mut atom = Self::default();
208 decode_children(buf, |kind, body| match kind {
209 $($atom::KIND => decode_slot(Self::KIND, &mut atom.$field, body, &mut atom.unknown),)*
210 $($last_atom::KIND => decode_slot(Self::KIND, &mut atom.$last, body, &mut atom.unknown),)?
211 kind => atom.unknown.push(Any::Unknown(kind, body.to_vec())),
212 })?;
213 Ok(atom)
214 }
215
216 fn encode_body<B: BufMut>(&self, buf: &mut B) -> Result<()> {
217 $(
218 self.$field.encode(buf)?;
219 encode_kept(&self.unknown, |kind| kind == $atom::KIND, buf)?;
220 )*
221 encode_kept(
222 &self.unknown,
223 |kind| !matches!(kind, $($atom::KIND)|* $(| $last_atom::KIND)?),
224 buf,
225 )?;
226 $(
227 self.$last.encode(buf)?;
228 encode_kept(&self.unknown, |kind| kind == $last_atom::KIND, buf)?;
229 )?
230 Ok(())
231 }
232 };
233}
234
235pub(super) use spatial_children;