flowly_mp4/mp4box/
mod.rs

1//! All ISO-MP4 boxes (atoms) and operations.
2//!
3//! * [ISO/IEC 14496-12](https://en.wikipedia.org/wiki/MPEG-4_Part_14) - ISO Base Media File Format (QuickTime, MPEG-4, etc)
4//! * [ISO/IEC 14496-14](https://en.wikipedia.org/wiki/MPEG-4_Part_14) - MP4 file format
5//! * ISO/IEC 14496-17 - Streaming text format
6//! * [ISO 23009-1](https://www.iso.org/standard/79329.html) -Dynamic adaptive streaming over HTTP (DASH)
7//!
8//! http://developer.apple.com/documentation/QuickTime/QTFF/index.html
9//! http://www.adobe.com/devnet/video/articles/mp4_movie_atom.html
10//! http://mp4ra.org/#/atoms
11//!
12//! Supported Atoms:
13//! ftyp
14//! moov
15//!     mvhd
16//!     udta
17//!         meta
18//!             ilst
19//!                 data
20//!     trak
21//!         tkhd
22//!         mdia
23//!             mdhd
24//!             hdlr
25//!             minf
26//!                 stbl
27//!                     stsd
28//!                         avc1
29//!                         hev1
30//!                         mp4a
31//!                         tx3g
32//!                     stts
33//!                     stsc
34//!                     stsz
35//!                     stss
36//!                     stco
37//!                     co64
38//!                     ctts
39//!                 dinf
40//!                     dref
41//!                 smhd
42//!                 vmhd
43//!         edts
44//!             elst
45//!     mvex
46//!         mehd
47//!         trex
48//! emsg
49//! moof
50//!     mfhd
51//!     traf
52//!         tfhd
53//!         tfdt
54//!         trun
55//! mdat
56//! free
57//!
58
59use byteorder::{BigEndian, ByteOrder, WriteBytesExt};
60use bytes::Buf;
61use std::io::Write;
62use std::{convert::TryInto, marker::PhantomData};
63use tokio::io::{AsyncRead, AsyncReadExt};
64
65use crate::*;
66
67pub(crate) mod avc1;
68pub(crate) mod co64;
69pub(crate) mod ctts;
70pub(crate) mod data;
71pub(crate) mod dinf;
72pub(crate) mod edts;
73pub(crate) mod elst;
74pub(crate) mod emsg;
75pub(crate) mod ftyp;
76pub(crate) mod hdlr;
77pub(crate) mod hev1;
78pub(crate) mod ilst;
79pub(crate) mod mdhd;
80pub(crate) mod mdia;
81pub(crate) mod mehd;
82pub(crate) mod meta;
83pub(crate) mod mfhd;
84pub(crate) mod minf;
85pub(crate) mod moof;
86pub(crate) mod moov;
87pub(crate) mod mp4a;
88pub(crate) mod mvex;
89pub(crate) mod mvhd;
90pub(crate) mod smhd;
91pub(crate) mod stbl;
92pub(crate) mod stco;
93pub(crate) mod stsc;
94pub(crate) mod stsd;
95pub(crate) mod stss;
96pub(crate) mod stsz;
97pub(crate) mod stts;
98pub(crate) mod tfdt;
99pub(crate) mod tfhd;
100pub(crate) mod tkhd;
101pub(crate) mod traf;
102pub(crate) mod trak;
103pub(crate) mod trex;
104pub(crate) mod trun;
105pub(crate) mod tx3g;
106pub(crate) mod udta;
107pub(crate) mod vmhd;
108pub(crate) mod vp09;
109pub(crate) mod vpcc;
110
111pub use avc1::Avc1Box;
112pub use co64::Co64Box;
113pub use ctts::CttsBox;
114pub use data::DataBox;
115pub use dinf::DinfBox;
116pub use edts::EdtsBox;
117pub use elst::ElstBox;
118pub use emsg::EmsgBox;
119pub use ftyp::FtypBox;
120pub use hdlr::HdlrBox;
121pub use hev1::Hev1Box;
122pub use ilst::IlstBox;
123pub use mdhd::MdhdBox;
124pub use mdia::MdiaBox;
125pub use mehd::MehdBox;
126pub use meta::MetaBox;
127pub use mfhd::MfhdBox;
128pub use minf::MinfBox;
129pub use moof::MoofBox;
130pub use moov::MoovBox;
131pub use mp4a::Mp4aBox;
132pub use mvex::MvexBox;
133pub use mvhd::MvhdBox;
134pub use smhd::SmhdBox;
135pub use stbl::StblBox;
136pub use stco::StcoBox;
137pub use stsc::StscBox;
138pub use stsd::StsdBox;
139pub use stss::StssBox;
140pub use stsz::StszBox;
141pub use stts::SttsBox;
142pub use tfdt::TfdtBox;
143pub use tfhd::TfhdBox;
144pub use tkhd::TkhdBox;
145pub use traf::TrafBox;
146pub use trak::TrakBox;
147pub use trex::TrexBox;
148pub use trun::TrunBox;
149pub use tx3g::Tx3gBox;
150pub use udta::UdtaBox;
151pub use vmhd::VmhdBox;
152pub use vp09::Vp09Box;
153pub use vpcc::VpccBox;
154
155pub const HEADER_SIZE: u64 = 8;
156// const HEADER_LARGE_SIZE: u64 = 16;
157pub const HEADER_EXT_SIZE: u64 = 4;
158
159macro_rules! boxtype {
160    ($( $name:ident => $value:expr ),*) => {
161        #[derive(Clone, Copy, PartialEq, Eq, Hash)]
162        pub enum BoxType {
163            $( $name, )*
164            UnknownBox(u32),
165        }
166
167        impl BoxType {
168            pub const fn as_str(&self) -> &'static str {
169                match self {
170                    $( BoxType::$name => stringify!($name), )*
171                    BoxType::UnknownBox(_) => "unknown",
172                }
173            }
174        }
175
176        impl From<u32> for BoxType {
177            fn from(t: u32) -> BoxType {
178                match t {
179                    $( $value => BoxType::$name, )*
180                    _ => BoxType::UnknownBox(t),
181                }
182            }
183        }
184
185        impl From<BoxType> for u32 {
186            fn from(b: BoxType) -> u32 {
187                match b {
188                    $( BoxType::$name => $value, )*
189                    BoxType::UnknownBox(t) => t,
190                }
191            }
192        }
193    }
194}
195
196boxtype! {
197    FtypBox => 0x66747970,
198    MvhdBox => 0x6d766864,
199    MfhdBox => 0x6d666864,
200    FreeBox => 0x66726565,
201    MdatBox => 0x6d646174,
202    MoovBox => 0x6d6f6f76,
203    MvexBox => 0x6d766578,
204    MehdBox => 0x6d656864,
205    TrexBox => 0x74726578,
206    EmsgBox => 0x656d7367,
207    MoofBox => 0x6d6f6f66,
208    TkhdBox => 0x746b6864,
209    TfhdBox => 0x74666864,
210    TfdtBox => 0x74666474,
211    EdtsBox => 0x65647473,
212    MdiaBox => 0x6d646961,
213    ElstBox => 0x656c7374,
214    MdhdBox => 0x6d646864,
215    HdlrBox => 0x68646c72,
216    MinfBox => 0x6d696e66,
217    VmhdBox => 0x766d6864,
218    StblBox => 0x7374626c,
219    StsdBox => 0x73747364,
220    SttsBox => 0x73747473,
221    CttsBox => 0x63747473,
222    StssBox => 0x73747373,
223    StscBox => 0x73747363,
224    StszBox => 0x7374737A,
225    StcoBox => 0x7374636F,
226    Co64Box => 0x636F3634,
227    TrakBox => 0x7472616b,
228    TrafBox => 0x74726166,
229    TrunBox => 0x7472756E,
230    UdtaBox => 0x75647461,
231    MetaBox => 0x6d657461,
232    DinfBox => 0x64696e66,
233    DrefBox => 0x64726566,
234    UrlBox  => 0x75726C20,
235    SmhdBox => 0x736d6864,
236    Avc1Box => 0x61766331,
237    AvcCBox => 0x61766343,
238    Hev1Box => 0x68657631,
239    HvcCBox => 0x68766343,
240    Mp4aBox => 0x6d703461,
241    EsdsBox => 0x65736473,
242    Tx3gBox => 0x74783367,
243    VpccBox => 0x76706343,
244    Vp09Box => 0x76703039,
245    DataBox => 0x64617461,
246    IlstBox => 0x696c7374,
247    NameBox => 0xa96e616d,
248    DayBox => 0xa9646179,
249    CovrBox => 0x636f7672,
250    DescBox => 0x64657363,
251    WideBox => 0x77696465,
252    WaveBox => 0x77617665
253}
254
255pub trait Mp4Box: Sized {
256    const TYPE: BoxType;
257
258    fn box_size(&self) -> u64;
259    fn to_json(&self) -> Result<String, Error>;
260    fn summary(&self) -> Result<String, Error>;
261}
262
263pub struct BoxReader<'a, R: Reader<'a>> {
264    kind: BoxType,
265    inner: R,
266    m: PhantomData<&'a ()>,
267}
268
269impl<'a, R: Reader<'a>> BoxReader<'a, R> {
270    #[inline]
271    pub fn try_read<T: Mp4Box + BlockReader>(&mut self) -> Result<Option<T>, Error> {
272        if T::TYPE == self.kind {
273            Ok(Some(T::read_block(&mut self.inner)?))
274        } else {
275            Ok(None)
276        }
277    }
278
279    #[inline]
280    pub fn read<T: Mp4Box + BlockReader>(&mut self) -> Result<T, Error> {
281        if T::TYPE == self.kind {
282            T::read_block(&mut self.inner)
283        } else {
284            Err(Error::BoxNotFound(T::TYPE))
285        }
286    }
287}
288
289pub trait Reader<'a> {
290    fn take(&mut self, size: usize) -> Result<impl Reader<'a> + '_, Error>;
291    fn remaining(&self) -> usize;
292    fn skip(&mut self, size: usize);
293
294    fn peek_u32(&self) -> u32;
295
296    fn get_u8(&mut self) -> u8;
297    fn get_u16(&mut self) -> u16;
298    fn get_u24(&mut self) -> u32;
299    fn get_u32(&mut self) -> u32;
300    fn get_u48(&mut self) -> u64;
301    fn get_u64(&mut self) -> u64;
302
303    fn get_i8(&mut self) -> i8;
304    fn get_i16(&mut self) -> i16;
305    fn get_i24(&mut self) -> i32;
306    fn get_i32(&mut self) -> i32;
307    fn get_i48(&mut self) -> i64;
308    fn get_i64(&mut self) -> i64;
309
310    #[inline]
311    fn try_get_u8(&mut self) -> Result<u8, Error> {
312        if self.remaining() < 1 {
313            Err(Error::InvalidData("expected at least 1 byte more"))
314        } else {
315            Ok(self.get_u8())
316        }
317    }
318    #[inline]
319    fn try_get_u16(&mut self) -> Result<u16, Error> {
320        if self.remaining() < 2 {
321            Err(Error::InvalidData("expected at least 2 byte more"))
322        } else {
323            Ok(self.get_u16())
324        }
325    }
326    #[inline]
327    fn try_get_u24(&mut self) -> Result<u32, Error> {
328        if self.remaining() < 3 {
329            Err(Error::InvalidData("expected at least 3 byte more"))
330        } else {
331            Ok(self.get_u24())
332        }
333    }
334    #[inline]
335    fn try_get_u32(&mut self) -> Result<u32, Error> {
336        if self.remaining() < 4 {
337            Err(Error::InvalidData("expected at least 4 byte more"))
338        } else {
339            Ok(self.get_u32())
340        }
341    }
342    #[inline]
343    fn try_get_u48(&mut self) -> Result<u64, Error> {
344        if self.remaining() < 6 {
345            Err(Error::InvalidData("expected at least 6 byte more"))
346        } else {
347            Ok(self.get_u48())
348        }
349    }
350    #[inline]
351    fn try_get_u64(&mut self) -> Result<u64, Error> {
352        if self.remaining() < 8 {
353            Err(Error::InvalidData("expected at least 8 byte more"))
354        } else {
355            Ok(self.get_u64())
356        }
357    }
358
359    #[inline]
360    fn try_get_i8(&mut self) -> Result<i8, Error> {
361        if self.remaining() < 1 {
362            Err(Error::InvalidData("expected at least 1 byte more"))
363        } else {
364            Ok(self.get_i8())
365        }
366    }
367    #[inline]
368    fn try_get_i16(&mut self) -> Result<i16, Error> {
369        if self.remaining() < 2 {
370            Err(Error::InvalidData("expected at least 2 byte more"))
371        } else {
372            Ok(self.get_i16())
373        }
374    }
375    #[inline]
376    fn try_get_i24(&mut self) -> Result<i32, Error> {
377        if self.remaining() < 3 {
378            Err(Error::InvalidData("expected at least 3 byte more"))
379        } else {
380            Ok(self.get_i24())
381        }
382    }
383    #[inline]
384    fn try_get_i32(&mut self) -> Result<i32, Error> {
385        if self.remaining() < 4 {
386            Err(Error::InvalidData("expected at least 4 byte more"))
387        } else {
388            Ok(self.get_i32())
389        }
390    }
391    #[inline]
392    fn try_get_i48(&mut self) -> Result<i64, Error> {
393        if self.remaining() < 6 {
394            Err(Error::InvalidData("expected at least 6 byte more"))
395        } else {
396            Ok(self.get_i48())
397        }
398    }
399    #[inline]
400    fn try_get_i64(&mut self) -> Result<i64, Error> {
401        if self.remaining() < 8 {
402            Err(Error::InvalidData("expected at least 8 byte more"))
403        } else {
404            Ok(self.get_i64())
405        }
406    }
407    fn get_null_terminated_string(&mut self) -> String;
408    fn collect(&mut self, size: usize) -> Result<Vec<u8>, Error> {
409        let mut buf = vec![0; size];
410        self.copy_to_slice(&mut buf)?;
411
412        Ok(buf)
413    }
414
415    #[inline]
416    fn collect_remaining(&mut self) -> Vec<u8> {
417        self.collect(self.remaining()).unwrap()
418    }
419
420    fn copy_to_slice(&mut self, slice: &mut [u8]) -> Result<(), Error>;
421    fn get_box(&mut self) -> Result<Option<BoxReader<'a, impl Reader<'a> + '_>>, Error>;
422
423    fn find_box<B: Mp4Box + BlockReader>(&mut self) -> Result<B, Error> {
424        self.try_find_box()
425            .and_then(|x| x.ok_or(Error::InvalidData("expected box")))
426    }
427
428    fn try_find_box2<A: Mp4Box + BlockReader, B: Mp4Box + BlockReader>(
429        &mut self,
430    ) -> Result<(Option<A>, Option<B>), Error> {
431        let mut a = None;
432        let mut b = None;
433
434        while let Some(mut bx) = self.get_box()? {
435            if a.is_none() {
436                if let Some(inner) = bx.try_read::<A>()? {
437                    a = Some(inner);
438                    continue;
439                }
440            }
441
442            if b.is_none() {
443                if let Some(inner) = bx.try_read::<B>()? {
444                    b = Some(inner);
445                    continue;
446                }
447            }
448
449            println!(" 1 unknown box {}", bx.kind);
450        }
451
452        Ok((a, b))
453    }
454
455    fn try_find_box3<A, B, C>(&mut self) -> Result<(Option<A>, Option<B>, Option<C>), Error>
456    where
457        A: Mp4Box + BlockReader,
458        B: Mp4Box + BlockReader,
459        C: Mp4Box + BlockReader,
460    {
461        let mut a = None;
462        let mut b = None;
463        let mut c = None;
464
465        while let Some(mut bx) = self.get_box()? {
466            if a.is_none() {
467                if let Some(inner) = bx.try_read::<A>()? {
468                    a = Some(inner);
469                    continue;
470                }
471            }
472            if b.is_none() {
473                if let Some(inner) = bx.try_read::<B>()? {
474                    b = Some(inner);
475                    continue;
476                }
477            }
478
479            if c.is_none() {
480                if let Some(inner) = bx.try_read::<C>()? {
481                    c = Some(inner);
482                    continue;
483                }
484            }
485
486            println!(" 2 unknown box {}", bx.kind);
487        }
488
489        Ok((a, b, c))
490    }
491
492    #[inline]
493    fn find_box3<A, B, C>(&mut self) -> Result<(A, B, C), Error>
494    where
495        A: Mp4Box + BlockReader,
496        B: Mp4Box + BlockReader,
497        C: Mp4Box + BlockReader,
498    {
499        let (a, b, c) = self.try_find_box3()?;
500
501        let Some(a) = a else {
502            return Err(Error::BoxNotFound(A::TYPE));
503        };
504
505        let Some(b) = b else {
506            return Err(Error::BoxNotFound(B::TYPE));
507        };
508
509        let Some(c) = c else {
510            return Err(Error::BoxNotFound(C::TYPE));
511        };
512
513        Ok((a, b, c))
514    }
515
516    fn try_find_box4<A, B, C, D>(
517        &mut self,
518    ) -> Result<(Option<A>, Option<B>, Option<C>, Option<D>), Error>
519    where
520        A: Mp4Box + BlockReader,
521        B: Mp4Box + BlockReader,
522        C: Mp4Box + BlockReader,
523        D: Mp4Box + BlockReader,
524    {
525        let mut a = None;
526        let mut b = None;
527        let mut c = None;
528        let mut d = None;
529
530        while let Some(mut bx) = self.get_box()? {
531            if a.is_none() {
532                if let Some(inner) = bx.try_read::<A>()? {
533                    a = Some(inner);
534                    continue;
535                }
536            }
537
538            if b.is_none() {
539                if let Some(inner) = bx.try_read::<B>()? {
540                    b = Some(inner);
541                    continue;
542                }
543            }
544
545            if c.is_none() {
546                if let Some(inner) = bx.try_read::<C>()? {
547                    c = Some(inner);
548                    continue;
549                }
550            }
551
552            if d.is_none() {
553                if let Some(inner) = bx.try_read::<D>()? {
554                    d = Some(inner);
555                    continue;
556                }
557            }
558
559            println!(" 3 unknown box {}", bx.kind);
560        }
561
562        Ok((a, b, c, d))
563    }
564
565    #[inline]
566    fn try_find_box<B: Mp4Box + BlockReader>(&mut self) -> Result<Option<B>, Error> {
567        while let Some(mut bx) = self.get_box()? {
568            if let Some(inner) = bx.try_read::<B>()? {
569                return Ok(Some(inner));
570            }
571
572            println!(" 4 unknown box {}", bx.kind);
573        }
574
575        Ok(None)
576    }
577}
578
579impl<'a> Reader<'a> for &'a [u8] {
580    #[inline]
581    fn take(&mut self, size: usize) -> Result<impl Reader<'a> + '_, Error> {
582        if self.len() < size {
583            return Err(Error::InvalidData("no bytes left"));
584        }
585
586        let buff = &(*self)[0..size];
587        self.advance(size);
588
589        Ok(buff)
590    }
591
592    #[inline]
593    fn skip(&mut self, size: usize) {
594        Buf::advance(self, size)
595    }
596
597    #[inline]
598    fn remaining(&self) -> usize {
599        Buf::remaining(self)
600    }
601
602    fn peek_u32(&self) -> u32 {
603        BigEndian::read_u32(self.chunk())
604    }
605
606    #[inline]
607    fn get_u8(&mut self) -> u8 {
608        Buf::get_u8(self)
609    }
610
611    #[inline]
612    fn get_u16(&mut self) -> u16 {
613        Buf::get_u16(self)
614    }
615
616    #[inline]
617    fn get_u24(&mut self) -> u32 {
618        let val = BigEndian::read_u24(self.chunk());
619        self.skip(3);
620        val
621    }
622
623    #[inline]
624    fn get_u32(&mut self) -> u32 {
625        Buf::get_u32(self)
626    }
627
628    #[inline]
629    fn get_u48(&mut self) -> u64 {
630        let val = BigEndian::read_u48(self.chunk());
631        self.skip(6);
632        val
633    }
634
635    #[inline]
636    fn get_u64(&mut self) -> u64 {
637        Buf::get_u64(self)
638    }
639
640    #[inline]
641    fn get_i8(&mut self) -> i8 {
642        Buf::get_i8(self)
643    }
644
645    #[inline]
646    fn get_i16(&mut self) -> i16 {
647        Buf::get_i16(self)
648    }
649
650    #[inline]
651    fn get_i24(&mut self) -> i32 {
652        todo!()
653    }
654
655    #[inline]
656    fn get_i32(&mut self) -> i32 {
657        Buf::get_i32(self)
658    }
659
660    #[inline]
661    fn get_i48(&mut self) -> i64 {
662        todo!()
663    }
664
665    #[inline]
666    fn get_i64(&mut self) -> i64 {
667        Buf::get_i64(self)
668    }
669
670    #[inline]
671    fn copy_to_slice(&mut self, slice: &mut [u8]) -> Result<(), Error> {
672        if self.len() < slice.len() {
673            return Err(Error::InvalidData("expected more bytes"));
674        }
675
676        Buf::copy_to_slice(self, slice);
677
678        Ok(())
679    }
680
681    #[inline]
682    fn get_null_terminated_string(&mut self) -> String {
683        let rem = self.len();
684
685        if rem > 0 {
686            let size = self.iter().position(|&b| b == b'\0');
687
688            let (size, eat) = if let Some(size) = size {
689                (size, size + 1)
690            } else {
691                (rem, rem)
692            };
693
694            let val = String::from_utf8_lossy(&self[0..size]).to_string();
695            self.advance(eat);
696            val
697        } else {
698            String::new()
699        }
700    }
701
702    #[inline]
703    fn get_box(&mut self) -> Result<Option<BoxReader<'a, impl Reader<'a> + '_>>, Error> {
704        let mut offset = 0;
705        let Some(BoxHeader { kind, size }) = BoxHeader::read_sync(self, &mut offset)? else {
706            return Ok(None);
707        };
708
709        Ok(Some(BoxReader {
710            kind,
711            inner: Reader::take(self, (size - offset) as _)?,
712            m: PhantomData,
713        }))
714    }
715}
716
717pub trait BlockReader: Sized {
718    fn read_block<'a>(block: &mut impl Reader<'a>) -> Result<Self, Error>;
719    fn size_hint() -> usize;
720}
721
722pub trait WriteBox<T>: Sized {
723    fn write_box(&self, _: T) -> Result<u64, Error>;
724}
725
726#[derive(Debug, Clone, Copy)]
727pub struct BoxHeader {
728    pub kind: BoxType,
729    pub size: u64,
730}
731
732impl BoxHeader {
733    pub fn new(name: BoxType, size: u64) -> Self {
734        Self { kind: name, size }
735    }
736
737    pub fn read_sync<'a>(
738        reader: &mut impl Reader<'a>,
739        offset: &mut u64,
740    ) -> Result<Option<Self>, Error> {
741        if reader.remaining() < 8 {
742            return Ok(None);
743        }
744
745        let sz = reader.get_u32();
746        let typ = reader.get_u32();
747
748        *offset += 8;
749
750        // Get largesize if size is 1
751        let size = if sz == 1 {
752            if reader.remaining() < 8 {
753                return Err(Error::InvalidData("expected 8 bytes more"));
754            }
755
756            *offset += 8;
757
758            let largesize = reader.get_u64();
759            // Subtract the length of the serialized largesize, as callers assume `size - HEADER_SIZE` is the length
760            // of the box data. Disallow `largesize < 16`, or else a largesize of 8 will result in a BoxHeader::size
761            // of 0, incorrectly indicating that the box data extends to the end of the stream.
762            match largesize {
763                0 => 0,
764                1..=15 => return Err(Error::InvalidData("64-bit box size too small")),
765                16..=u64::MAX => largesize - 8,
766            }
767        } else {
768            sz as _
769        };
770
771        println!(
772            "{} box {} {}",
773            if sz == 1 { "big" } else { "small" },
774            BoxType::from(typ).as_str(),
775            size
776        );
777
778        Ok(Some(BoxHeader {
779            kind: BoxType::from(typ),
780            size,
781        }))
782    }
783
784    // TODO: if size is 0, then this box is the last one in the file
785    pub async fn read<R: AsyncRead + Unpin>(
786        reader: &mut R,
787        offset: &mut u64,
788    ) -> Result<Option<Self>, Error> {
789        // Create and read to buf.
790        let mut buf = [0u8; 8]; // 8 bytes for box header.
791        match reader.read_exact(&mut buf).await {
792            Ok(_) => (),
793            Err(err) => match err.kind() {
794                std::io::ErrorKind::UnexpectedEof => return Ok(None),
795                _ => return Err(err.into()),
796            },
797        }
798        *offset += 8;
799
800        // Get size.
801        let s = buf[0..4].try_into().unwrap();
802        let sz = u32::from_be_bytes(s);
803
804        // Get box type string.
805        let t = buf[4..8].try_into().unwrap();
806        let typ = u32::from_be_bytes(t);
807
808        // Get largesize if size is 1
809        let size = if sz == 1 {
810            match reader.read_exact(&mut buf).await {
811                Ok(_) => (),
812                Err(err) => match err.kind() {
813                    std::io::ErrorKind::UnexpectedEof => return Ok(None),
814                    _ => return Err(err.into()),
815                },
816            }
817
818            *offset += 8;
819            let largesize = u64::from_be_bytes(buf);
820
821            // Subtract the length of the serialized largesize, as callers assume `size - HEADER_SIZE` is the length
822            // of the box data. Disallow `largesize < 16`, or else a largesize of 8 will result in a BoxHeader::size
823            // of 0, incorrectly indicating that the box data extends to the end of the stream.
824            match largesize {
825                0 => 0,
826                1..=15 => return Err(Error::InvalidData("64-bit box size too small")),
827                16..=u64::MAX => largesize - 8,
828            }
829        } else {
830            sz as _
831        };
832
833        println!(
834            "{} box {} {}",
835            if sz == 1 { "big" } else { "small" },
836            BoxType::from(typ).as_str(),
837            size
838        );
839
840        Ok(Some(BoxHeader {
841            kind: BoxType::from(typ),
842            size,
843        }))
844    }
845
846    pub fn write<W: Write>(&self, writer: &mut W) -> Result<u64, Error> {
847        if self.size > u32::MAX as u64 {
848            writer.write_u32::<BigEndian>(1)?;
849            writer.write_u32::<BigEndian>(self.kind.into())?;
850            writer.write_u64::<BigEndian>(self.size)?;
851            Ok(16)
852        } else {
853            writer.write_u32::<BigEndian>(self.size as u32)?;
854            writer.write_u32::<BigEndian>(self.kind.into())?;
855            Ok(8)
856        }
857    }
858}
859
860#[inline]
861pub fn read_box_header_ext<'a, R: Reader<'a>>(reader: &mut R) -> (u8, u32) {
862    (reader.get_u8(), reader.get_u24())
863}
864
865pub fn write_box_header_ext<W: Write>(w: &mut W, v: u8, f: u32) -> Result<u64, Error> {
866    w.write_u8(v)?;
867    w.write_u24::<BigEndian>(f)?;
868    Ok(4)
869}
870
871pub fn write_zeros<W: Write>(writer: &mut W, size: u64) -> Result<(), Error> {
872    for _ in 0..size {
873        writer.write_u8(0)?;
874    }
875    Ok(())
876}
877
878mod value_u32 {
879    use crate::types::FixedPointU16;
880    use serde::{self, Serializer};
881
882    pub fn serialize<S>(fixed: &FixedPointU16, serializer: S) -> Result<S::Ok, S::Error>
883    where
884        S: Serializer,
885    {
886        serializer.serialize_u16(fixed.value())
887    }
888}
889
890mod value_i16 {
891    use crate::types::FixedPointI8;
892    use serde::{self, Serializer};
893
894    pub fn serialize<S>(fixed: &FixedPointI8, serializer: S) -> Result<S::Ok, S::Error>
895    where
896        S: Serializer,
897    {
898        serializer.serialize_i8(fixed.value())
899    }
900}
901
902mod value_u8 {
903    use crate::types::FixedPointU8;
904    use serde::{self, Serializer};
905
906    pub fn serialize<S>(fixed: &FixedPointU8, serializer: S) -> Result<S::Ok, S::Error>
907    where
908        S: Serializer,
909    {
910        serializer.serialize_u8(fixed.value())
911    }
912}
913
914#[cfg(test)]
915mod tests {
916    use super::*;
917
918    #[test]
919    fn test_fourcc() {
920        let ftyp_fcc = 0x66747970;
921        let ftyp_value = FourCC::from(ftyp_fcc);
922        assert_eq!(&ftyp_value.value[..], b"ftyp");
923        let ftyp_fcc2: u32 = ftyp_value.into();
924        assert_eq!(ftyp_fcc, ftyp_fcc2);
925    }
926
927    #[tokio::test]
928    async fn test_largesize_too_small() {
929        let error = BoxHeader::read(
930            &mut &[0, 0, 0, 1, 1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 7][..],
931            &mut 0,
932        )
933        .await;
934        assert!(matches!(error, Err(Error::InvalidData(_))));
935    }
936
937    #[tokio::test]
938    async fn test_zero_largesize() {
939        let error = BoxHeader::read(
940            &mut &[0, 0, 0, 1, 1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 8][..],
941            &mut 0,
942        )
943        .await;
944        assert!(matches!(error, Err(Error::InvalidData(_))));
945    }
946
947    #[tokio::test]
948    async fn test_nonzero_largesize_too_small() {
949        let error = BoxHeader::read(
950            &mut &[0, 0, 0, 1, 1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 15][..],
951            &mut 0,
952        )
953        .await;
954        assert!(matches!(error, Err(Error::InvalidData(_))));
955    }
956
957    #[tokio::test]
958    async fn test_valid_largesize() {
959        let header = BoxHeader::read(
960            &mut &[0, 0, 0, 1, 1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 16][..],
961            &mut 0,
962        )
963        .await;
964        assert!(matches!(header, Ok(Some(BoxHeader { size: 8, .. }))));
965    }
966}