mp4-atom 0.5.0

A MP4/ISOBMFF atom decoder and encoder
Documentation
[![crates.io](https://img.shields.io/crates/v/mp4-atom)](https://crates.io/crates/mp4-atom)
[![docs.rs](https://img.shields.io/docsrs/mp4-atom)](https://docs.rs/mp4-atom)
[![discord](https://img.shields.io/discord/1124083992740761730)](https://discord.gg/FCYF3p99mr)

# 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 4-byte 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.

See the [documentation](https://docs.rs/mp4-atom).

## Examples
### Decoding/encoding a byte buffer
```rust
use bytes::{Bytes, BufMut};
use mp4_atom::{Any, Encode, Decode, Ftyp};

 // 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 = BufMut::new();
atom.encode(&mut output)?;

assert_eq!(input, output.freeze());
```

### Synchronous IO
NOTE: reading a `Mdat` atom will read the entire contents into memory.
See the next example to avoid this.

```rust
use mp4_atom::{Any, ReadFrom, WriteTo, Ftyp};

let mut reader = std::io::stdin();
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();
atom.write_to(&mut writer)?;
```

### Handling large atoms
To avoid reading large files into memory, you can call `Header::read_from` manually:

```rust
use mp4_atom::{Atom, Any, Header, ReadFrom, ReadAtom, WriteTo, Ftyp, Moov};

let mut reader = std::io::stdin();

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);
   }
};
```

### Asynchronous IO
Enable using the `tokio` feature.
It's the same as the above two but using the `AsyncReadFrom`, `AsyncWriteTo`, and `AsyncReadAtom` traits instead.

There's also the `bytes` features which enables encoding for `Bytes` and `BytesMut` from the `bytes` crate, often used with tokio.