# mp4-track
`mp4-track` reads tracks, sample tables, codec configuration, edit lists, event
messages, fragments, and common user metadata from MP4 and ISO base media files.
It also writes progressive MP4 files from encoded samples.
The reader accepts any `Read + Seek` stream. It walks box headers before loading
data, skips media payloads during `open`, and applies configurable limits to movie
boxes, fragment boxes, samples, fragment counts, and nesting depth. Sample offsets
and time values use 64-bit arithmetic. Malformed input returns a typed `Error`.
## Reading samples
```rust
use mp4_track::{Mp4Reader, TrackId};
use std::fs::File;
let file = File::open("movie.mp4")?;
let mut reader = Mp4Reader::open(file)?;
for track in reader.tracks() {
println!("track {} has {} table samples", track.id.0, track.sample_count);
}
if let Some(info) = reader.samples(TrackId(1))?.next() {
let sample = reader.read_sample(TrackId(1), info.index)?;
println!("read {} bytes at decode time {}", sample.data.len(), info.dts);
}
# Ok::<(), Box<dyn std::error::Error>>(())
```
`read_sample_into` reuses a caller-owned `Vec<u8>`. `samples` and `sample_info`
read metadata already expanded during `open`, so they perform no stream I/O.
## Writing a progressive file
Create an `Mp4Writer`, add every track, then pass encoded samples in output order.
Consecutive samples from the same track form one chunk. `finish` writes the movie
box and fixes the media-data size.
```rust
use mp4_track::{Mp4Writer, WriterConfig};
use std::io::Cursor;
let output = Cursor::new(Vec::new());
let writer = Mp4Writer::new(output, WriterConfig::default())?;
// Add TrackConfig values and encoded samples before calling finish.
# let _ = writer;
# Ok::<(), Box<dyn std::error::Error>>(())
```
The writer selects 32-bit chunk offsets when they fit. Set
`ChunkOffsetChoice::Co64` to force 64-bit chunk offsets.
## Supported data
Progressive reads cover `stts`, `ctts`, `stss`, `stsc`, `stsz`, `stco`, and `co64`.
Codec parsing covers `avc1`, `avc3`, `hvc1`, `hev1`, `mp4a`, and `Opus`. Other
sample entries retain their body bytes. Fragmented reads cover `trex`, `tfhd`,
`tfdt`, and `trun` when each track fragment supplies an explicit base offset or
uses `default-base-is-moof`.
The current release targets 64-bit systems. Compact sample sizes, compressed movie
boxes, encryption boxes, sample groups, media item boxes, and fragmented output are
outside its supported surface.
## Resource limits
`Limits::default()` permits movie boxes up to 256 MiB, fragment boxes up to 64 MiB,
samples up to 64 MiB, 500,000 samples per track, one million fragments, and 32
levels of box nesting. Sample tables that declare more samples than the limit are
rejected before any table is allocated. Pass a `Limits` value to
`Mp4Reader::open_with` when an application needs lower bounds.
## License
MIT