mp4_atom/
lib.rs

1//! # mp4-atom
2//!
3//! This library provides encoding for the ISO Base Media File Format (ISO/IEC 14496-12).
4//! It's meant to be low level, performing encoding/decoding of the binary format without
5//! validation or interpretation of the data. You have to know what boxes to expect!
6
7//! ## Atoms
8//! MP4 files are made up of atoms, which are boxes of data.
9//! They have an upfront size and a FourCC code to identify the type of box.
10//! Examples include [Moov], [Mdat], [Trak], etc.
11//!
12//! Unfortunately, the specification is quite complex and often gated behind a paywall.
13//! Using this library does require some additional knowledge of the format otherwise you should use a higher level library.
14//!
15//! MP4 atoms are often optional and unordered.
16//! The simplest way to decode with this library is with [Any::decode], returning any supported atom in a giant enum.
17//! For encoding you will call encode on the atom directly, ex: [Moov::encode].
18//!
19//! ## Traits
20//! This library gates functionality behind quite a few traits:
21//!
22//! - [Atom] is primarily used for encoding/decoding but also provides [Atom::KIND].
23//! - [Decode] and [Encode] when using byte slices.
24//! - [ReadFrom] and [WriteTo] when using synchronous IO.
25//! - **(feature = "tokio")** [AsyncReadFrom] and [AsyncWriteTo] when using asynchronous IO.
26//! - [Buf] and [BufMut] for encoding/decoding contiguous byte slices.
27//!
28//! Additionally, there are some extra traits for decoding atoms given a header.
29//! This is useful to avoid decoding large [Mdat] atoms by first reading the header separately.
30//!
31//! - [DecodeAtom] when using byte slices.
32//! - [ReadAtom] when using synchronous IO.
33//! - **(feature = "tokio")** [AsyncReadAtom] when using asynchronous IO.
34//!
35//! There's no equivalent for encoding because the size of the atom is required upfront.
36//!
37//! ## Examples
38//!
39//! ### Decoding/encoding a byte buffer
40//! ```rust
41//! use std::io::Cursor;
42//! use mp4_atom::{Any, Encode, Decode, Ftyp, Buf};
43//!
44//! # fn main() -> anyhow::Result<()> {
45//!  // A simple ftyp atom
46//! let mut input = Cursor::new(b"\0\0\0\x14ftypiso6\0\0\x02\0mp41");
47//! let atom = Any::decode(&mut input)?;
48//!
49//! // Make sure we got the right atom
50//! assert_eq!(atom, Ftyp {
51//!    major_brand: b"iso6".into(),
52//!    minor_version: 512,
53//!    compatible_brands: vec![b"mp41".into()],
54//! }.into());
55//!
56//! // Encode it back
57//! let mut output = Vec::new();
58//! atom.encode(&mut output)?;
59//!
60//! assert_eq!(input.get_ref().as_slice(), output.as_slice());
61//! # Ok(()) }
62//! ```
63//!
64//! ### Synchronous IO
65//! NOTE: reading a [Mdat] atom will read the entire contents into memory.
66//! See the next example to avoid this.
67//!
68//! ```rust
69//! # use std::io::Cursor;
70//! use mp4_atom::{Any, ReadFrom, WriteTo, Ftyp};
71//!
72//! # fn main() -> anyhow::Result<()> {
73//! let mut reader = std::io::stdin();
74//!
75//! # let mut input = Cursor::new(b"\0\0\0\x14ftypiso6\0\0\x02\0mp41");
76//!
77//! let atom = Any::read_from(&mut input)?;
78//!
79//! // Make sure we got the right atom
80//! assert_eq!(atom, Ftyp {
81//!    major_brand: b"iso6".into(),
82//!    minor_version: 512,
83//!    compatible_brands: vec![b"mp41".into()],
84//! }.into());
85//!
86//! // Encode it back to a Write type
87//! let writer = std::io::stdout();
88//! # let mut writer = Vec::new();
89//! atom.write_to(&mut writer)?;
90//!
91//! # assert_eq!(input.get_ref().as_slice(), writer.as_slice());
92//! # Ok(()) }
93//! ```
94//!
95//! ### Handling large atoms
96//! To avoid reading large files into memory, you can call [Header::read_from] manually:
97//!
98//! ```rust
99//! # use std::io::Cursor;
100//! use mp4_atom::{Atom, Any, Header, ReadFrom, ReadAtom, WriteTo, Ftyp, Moov};
101//!
102//! # fn main() -> anyhow::Result<()> {
103//! let mut reader = std::io::stdin();
104//! # let mut reader = Cursor::new(b"\0\0\0\x14ftypiso6\0\0\x02\0mp41");
105//!
106//! let header = Header::read_from(&mut reader)?;
107//! match header.kind {
108//!   Ftyp::KIND => {
109//!     let ftyp = Ftyp::read_atom(&header, &mut reader)?;
110//!
111//!      // Make sure we got the right atom
112//!      assert_eq!(ftyp, Ftyp {
113//!        major_brand: b"iso6".into(),
114//!        minor_version: 512,
115//!        compatible_brands: vec![b"mp41".into()],
116//!      });
117//!    },
118//!    Moov::KIND => {
119//!      // Manually decode the moov
120//!      match header.size {
121//!        Some(size) => { /* read size bytes */ },
122//!        None => { /* read until EOF */ },
123//!      };
124//!    },
125//!    _ => {
126//!      // You can also use Any if you prefer
127//!      let any = Any::read_atom(&header, &mut reader)?;
128//!      println!("Unknown atom: {:?}", any);
129//!    }
130//! };
131//!
132//! # Ok(()) }
133//! ```
134//!
135//! ### Asynchronous IO
136//! Enable using the `tokio` feature.
137//! It's the same as the above two but using [AsyncReadFrom], [AsyncWriteTo], and [AsyncReadAtom] instead.
138//!
139
140mod any;
141mod atom;
142mod atom_ext;
143mod buf;
144mod coding;
145mod emsg;
146mod error;
147mod free;
148mod ftyp;
149mod header;
150mod io;
151mod mdat;
152mod moof;
153mod moov;
154mod styp;
155mod types;
156
157pub use any::*;
158pub use atom::*;
159pub(crate) use atom_ext::*;
160pub use buf::*;
161pub use coding::*;
162pub use emsg::*;
163pub use error::*;
164pub use free::*;
165pub use ftyp::*;
166pub use header::*;
167pub use io::*;
168pub use mdat::*;
169pub use moof::*;
170pub use moov::*;
171pub use styp::*;
172pub use types::*;
173
174#[cfg(feature = "tokio")]
175mod tokio;
176
177#[cfg(feature = "tokio")]
178pub use self::tokio::*;
179
180#[cfg(test)]
181mod test;