1use std::{
2 io::{Read, Write},
3 ops::{BitAnd, Shl, Shr, Sub},
4 time::Duration,
5};
6
7use crate::{
8 Decode, Encode, Error, Result,
9 boxes::{FtypBox, RootBox},
10 io::PeekReader,
11};
12
13pub trait BaseBox {
18 fn box_type(&self) -> BoxType;
20
21 fn box_size(&self) -> BoxSize {
25 BoxSize::with_payload_size(self.box_type(), self.box_payload_size())
26 }
27
28 fn box_payload_size(&self) -> u64;
30
31 fn is_unknown_box(&self) -> bool {
37 false
38 }
39
40 fn children<'a>(&'a self) -> Box<dyn 'a + Iterator<Item = &'a dyn BaseBox>>;
42}
43
44pub(crate) fn as_box_object<T: BaseBox>(t: &T) -> &dyn BaseBox {
45 t
46}
47
48pub trait FullBox: BaseBox {
50 fn full_box_version(&self) -> u8;
52
53 fn full_box_flags(&self) -> FullBoxFlags;
55}
56
57#[derive(Debug, Clone, PartialEq, Eq)]
59pub struct Mp4File<B = RootBox> {
60 pub ftyp_box: FtypBox,
62
63 pub boxes: Vec<B>,
65}
66
67impl<B: BaseBox> Mp4File<B> {
68 pub fn iter(&self) -> impl Iterator<Item = &dyn BaseBox> {
70 std::iter::empty()
71 .chain(std::iter::once(&self.ftyp_box).map(as_box_object))
72 .chain(self.boxes.iter().map(as_box_object))
73 }
74}
75
76impl<B: BaseBox + Decode> Decode for Mp4File<B> {
77 fn decode<R: Read>(mut reader: R) -> Result<Self> {
78 let ftyp_box = FtypBox::decode(&mut reader)?;
79
80 let mut boxes = Vec::new();
81 let mut buf = [0];
82 while reader.read(&mut buf)? != 0 {
83 let b = B::decode(&mut buf.chain(&mut reader))?;
84 boxes.push(b);
85 }
86 Ok(Self { ftyp_box, boxes })
87 }
88}
89
90impl<B: BaseBox + Encode> Encode for Mp4File<B> {
91 fn encode<W: Write>(&self, mut writer: W) -> Result<()> {
92 self.ftyp_box.encode(&mut writer)?;
93
94 for b in &self.boxes {
95 b.encode(&mut writer)?;
96 }
97 Ok(())
98 }
99}
100
101#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
103pub struct BoxHeader {
104 pub box_type: BoxType,
106
107 pub box_size: BoxSize,
109}
110
111impl BoxHeader {
112 const MAX_SIZE: usize = (4 + 8) + (4 + 16);
113
114 pub fn from_box<B: BaseBox>(b: &B) -> Self {
116 let box_type = b.box_type();
117 let box_size = b.box_size();
118 Self { box_type, box_size }
119 }
120
121 pub fn external_size(self) -> usize {
123 self.box_type.external_size() + self.box_size.external_size()
124 }
125
126 pub fn with_box_payload_reader<T, R: Read, F>(self, reader: R, f: F) -> Result<T>
128 where
129 F: FnOnce(&mut std::io::Take<R>) -> Result<T>,
130 {
131 let mut reader = if self.box_size.get() == 0 {
132 reader.take(u64::MAX)
133 } else {
134 let payload_size = self
135 .box_size
136 .get()
137 .checked_sub(self.external_size() as u64)
138 .ok_or_else(|| {
139 Error::invalid_data(&format!(
140 "Too small box size: actual={}, expected={} or more",
141 self.box_size.get(),
142 self.external_size()
143 ))
144 .with_box_type(self.box_type)
145 })?;
146 reader.take(payload_size)
147 };
148
149 let value = f(&mut reader).map_err(|e| e.with_box_type(self.box_type))?;
150 if reader.limit() != 0 {
151 return Err(Error::invalid_data(&format!(
152 "Unconsumed {} bytes at the end of the box '{}'",
153 reader.limit(),
154 self.box_type
155 ))
156 .with_box_type(self.box_type));
157 }
158 Ok(value)
159 }
160
161 pub fn peek<R: Read>(reader: R) -> Result<(Self, impl Read)> {
165 let mut reader = PeekReader::<_, { BoxHeader::MAX_SIZE }>::new(reader);
166 let header = BoxHeader::decode(&mut reader)?;
167 Ok((header, reader.into_reader()))
168 }
169}
170
171impl Encode for BoxHeader {
172 fn encode<W: Write>(&self, mut writer: W) -> Result<()> {
173 let large_size = match self.box_size {
174 BoxSize::U32(size) => {
175 size.encode(&mut writer)?;
176 None
177 }
178 BoxSize::U64(size) => {
179 1u32.encode(&mut writer)?;
180 Some(size)
181 }
182 };
183
184 match self.box_type {
185 BoxType::Normal(ty) => {
186 writer.write_all(&ty)?;
187 }
188 BoxType::Uuid(ty) => {
189 writer.write_all("uuid".as_bytes())?;
190 writer.write_all(&ty)?;
191 }
192 }
193
194 if let Some(large_size) = large_size {
195 large_size.encode(writer)?;
196 }
197
198 Ok(())
199 }
200}
201
202impl Decode for BoxHeader {
203 fn decode<R: Read>(mut reader: R) -> Result<Self> {
204 let box_size = u32::decode(&mut reader)?;
205
206 let mut box_type = [0; 4];
207 reader.read_exact(&mut box_type)?;
208
209 let box_type = if box_type == [b'u', b'u', b'i', b'd'] {
210 let mut box_type = [0; 16];
211 reader.read_exact(&mut box_type)?;
212 BoxType::Uuid(box_type)
213 } else {
214 BoxType::Normal(box_type)
215 };
216
217 let box_size = if box_size == 1 {
218 BoxSize::U64(u64::decode(reader)?)
219 } else {
220 BoxSize::U32(box_size)
221 };
222 if box_size.get() != 0
223 && box_size.get() < (box_size.external_size() + box_type.external_size()) as u64
224 {
225 return Err(Error::invalid_data(&format!(
226 "Too small box size: actual={}, expected={} or more",
227 box_size.get(),
228 box_size.external_size() + box_type.external_size()
229 ))
230 .with_box_type(box_type));
231 };
232
233 Ok(Self { box_type, box_size })
234 }
235}
236
237#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
239pub struct FullBoxHeader {
240 pub version: u8,
242
243 pub flags: FullBoxFlags,
245}
246
247impl FullBoxHeader {
248 pub fn from_box<B: FullBox>(b: &B) -> Self {
250 Self {
251 version: b.full_box_version(),
252 flags: b.full_box_flags(),
253 }
254 }
255}
256
257impl Encode for FullBoxHeader {
258 fn encode<W: Write>(&self, mut writer: W) -> Result<()> {
259 self.version.encode(&mut writer)?;
260 self.flags.encode(writer)?;
261 Ok(())
262 }
263}
264
265impl Decode for FullBoxHeader {
266 fn decode<R: Read>(mut reader: R) -> Result<Self> {
267 Ok(Self {
268 version: Decode::decode(&mut reader)?,
269 flags: Decode::decode(reader)?,
270 })
271 }
272}
273
274#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
276pub struct FullBoxFlags(u32);
277
278impl FullBoxFlags {
279 pub const fn empty() -> Self {
281 Self(0)
282 }
283
284 pub const fn new(flags: u32) -> Self {
286 Self(flags)
287 }
288
289 pub fn from_flags<I>(iter: I) -> Self
291 where
292 I: IntoIterator<Item = (usize, bool)>,
293 {
294 let flags = iter.into_iter().filter(|x| x.1).map(|x| 1 << x.0).sum();
295 Self(flags)
296 }
297
298 pub const fn get(self) -> u32 {
300 self.0
301 }
302
303 pub const fn is_set(self, i: usize) -> bool {
305 (self.0 & (1 << i)) != 0
306 }
307}
308
309impl Encode for FullBoxFlags {
310 fn encode<W: Write>(&self, mut writer: W) -> Result<()> {
311 writer.write_all(&self.0.to_be_bytes()[1..])?;
312 Ok(())
313 }
314}
315
316impl Decode for FullBoxFlags {
317 fn decode<R: Read>(mut reader: R) -> Result<Self> {
318 let mut buf = [0; 4];
319 reader.read_exact(&mut buf[1..])?;
320 Ok(Self(u32::from_be_bytes(buf)))
321 }
322}
323
324#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
329#[allow(missing_docs)]
330pub enum BoxSize {
331 U32(u32),
332 U64(u64),
333}
334
335impl BoxSize {
336 pub const VARIABLE_SIZE: Self = Self::U32(0);
338
339 pub fn with_payload_size(box_type: BoxType, payload_size: u64) -> Self {
341 let mut size = 4 + box_type.external_size() as u64 + payload_size;
342 if let Ok(size) = u32::try_from(size) {
343 Self::U32(size)
344 } else {
345 size += 8;
346 Self::U64(size)
347 }
348 }
349
350 pub const fn get(self) -> u64 {
352 match self {
353 BoxSize::U32(v) => v as u64,
354 BoxSize::U64(v) => v,
355 }
356 }
357
358 pub const fn external_size(self) -> usize {
360 match self {
361 BoxSize::U32(_) => 4,
362 BoxSize::U64(_) => 4 + 8,
363 }
364 }
365}
366
367#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
369pub enum BoxType {
370 Normal([u8; 4]),
372
373 Uuid([u8; 16]),
375}
376
377impl BoxType {
378 pub fn as_bytes(&self) -> &[u8] {
380 match self {
381 BoxType::Normal(ty) => &ty[..],
382 BoxType::Uuid(ty) => &ty[..],
383 }
384 }
385
386 pub const fn external_size(self) -> usize {
388 if matches!(self, Self::Normal(_)) {
389 4
390 } else {
391 4 + 16
392 }
393 }
394
395 pub fn expect(self, expected: Self) -> Result<()> {
397 if self == expected {
398 Ok(())
399 } else {
400 Err(Error::invalid_data(&format!(
401 "Expected box type `{}`, but got `{}`",
402 expected, self
403 )))
404 }
405 }
406}
407
408impl std::fmt::Debug for BoxType {
409 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
410 match self {
411 BoxType::Normal(ty) => {
412 if let Ok(ty) = std::str::from_utf8(ty) {
413 f.debug_tuple("BoxType").field(&ty).finish()
414 } else {
415 f.debug_tuple("BoxType").field(ty).finish()
416 }
417 }
418 BoxType::Uuid(ty) => f.debug_tuple("BoxType").field(ty).finish(),
419 }
420 }
421}
422
423impl std::fmt::Display for BoxType {
424 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
425 if let BoxType::Normal(ty) = self {
426 if let Ok(ty) = std::str::from_utf8(&ty[..]) {
427 return write!(f, "{ty}");
428 }
429 }
430 write!(f, "{:?}", self.as_bytes())
431 }
432}
433
434#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
436pub struct Mp4FileTime(u64);
437
438impl Mp4FileTime {
439 pub const fn from_secs(secs: u64) -> Self {
441 Self(secs)
442 }
443
444 pub const fn as_secs(self) -> u64 {
446 self.0
447 }
448
449 pub const fn from_unix_time(unix_time: Duration) -> Self {
451 let delta = 2082844800; let unix_time_secs = unix_time.as_secs();
453 Self::from_secs(unix_time_secs + delta)
454 }
455}
456
457#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
459pub struct FixedPointNumber<I, F = I> {
460 pub integer: I,
462
463 pub fraction: F,
465}
466
467impl<I, F> FixedPointNumber<I, F> {
468 pub const fn new(integer: I, fraction: F) -> Self {
470 Self { integer, fraction }
471 }
472}
473
474impl<I: Encode, F: Encode> Encode for FixedPointNumber<I, F> {
475 fn encode<W: Write>(&self, mut writer: W) -> Result<()> {
476 self.integer.encode(&mut writer)?;
477 self.fraction.encode(writer)?;
478 Ok(())
479 }
480}
481
482impl<I: Decode, F: Decode> Decode for FixedPointNumber<I, F> {
483 fn decode<R: Read>(mut reader: R) -> Result<Self> {
484 Ok(Self {
485 integer: I::decode(&mut reader)?,
486 fraction: F::decode(reader)?,
487 })
488 }
489}
490
491#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
493pub struct Utf8String(String);
494
495impl Utf8String {
496 pub const EMPTY: Self = Utf8String(String::new());
498
499 pub fn new(s: &str) -> Option<Self> {
503 if s.as_bytes().contains(&0) {
504 return None;
505 }
506 Some(Self(s.to_owned()))
507 }
508
509 pub fn get(&self) -> &str {
511 &self.0
512 }
513
514 pub fn into_null_terminated_bytes(self) -> Vec<u8> {
516 let mut v = self.0.into_bytes();
517 v.push(0);
518 v
519 }
520}
521
522impl Encode for Utf8String {
523 fn encode<W: Write>(&self, mut writer: W) -> Result<()> {
524 writer.write_all(self.0.as_bytes())?;
525 writer.write_all(&[0])?;
526 Ok(())
527 }
528}
529
530impl Decode for Utf8String {
531 fn decode<R: Read>(mut reader: R) -> Result<Self> {
532 let mut bytes = Vec::new();
533 loop {
534 let b = u8::decode(&mut reader)?;
535 if b == 0 {
536 break;
537 }
538 bytes.push(b);
539 }
540 let s = String::from_utf8(bytes).map_err(|e| {
541 Error::invalid_data(&format!("Invalid UTF-8 string: {:?}", e.as_bytes()))
542 })?;
543 Ok(Self(s))
544 }
545}
546
547#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
549#[allow(missing_docs)]
550pub enum Either<A, B> {
551 A(A),
552 B(B),
553}
554
555impl<A: BaseBox, B: BaseBox> Either<A, B> {
556 fn inner_box(&self) -> &dyn BaseBox {
557 match self {
558 Self::A(x) => x,
559 Self::B(x) => x,
560 }
561 }
562}
563
564impl<A: BaseBox, B: BaseBox> BaseBox for Either<A, B> {
565 fn box_type(&self) -> BoxType {
566 self.inner_box().box_type()
567 }
568
569 fn box_size(&self) -> BoxSize {
570 self.inner_box().box_size()
571 }
572
573 fn box_payload_size(&self) -> u64 {
574 self.inner_box().box_payload_size()
575 }
576
577 fn is_unknown_box(&self) -> bool {
578 self.inner_box().is_unknown_box()
579 }
580
581 fn children<'a>(&'a self) -> Box<dyn 'a + Iterator<Item = &'a dyn BaseBox>> {
582 self.inner_box().children()
583 }
584}
585
586#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
592pub struct Uint<T, const BITS: u32, const OFFSET: u32 = 0>(T);
593
594impl<T, const BITS: u32, const OFFSET: u32> Uint<T, BITS, OFFSET>
595where
596 T: Shr<u32, Output = T>
597 + Shl<u32, Output = T>
598 + BitAnd<Output = T>
599 + Sub<Output = T>
600 + From<u8>,
601{
602 pub const fn new(v: T) -> Self {
604 Self(v)
605 }
606
607 pub fn get(self) -> T {
609 self.0
610 }
611
612 pub fn from_bits(v: T) -> Self {
614 Self((v >> OFFSET) & ((T::from(1) << BITS) - T::from(1)))
615 }
616
617 pub fn to_bits(self) -> T {
621 self.0 << OFFSET
622 }
623}