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