mp4 Rust Library

repository·master·Indexed 43 days ago

https://github.com/alfg/mp4-rust

A Rust library for reading and writing ISO-MP4 files, supporting specifications ISO/IEC 14496-12, 14496-14, and 14496-17. Version 0.14.0 provides tools for parsing MP4 box data (such as CttsBox, ElstBox, StscBox, and TkhdBox), managing track references, and extracting metadata via Mp4Reader and Mp4Track.

Tokens
7.1K
Snippets
28
Records
35
Agent score
56%

What's inside mp4

  1. Configure an Mp4Track using TrackConfig

    master

    When creating a new track (e.g., for writing a new MP4 file), use TrackConfig to define the track's properties. TrackConfig is constructed from a MediaConfig which specifies the codec-specific parameters.

    Common TrackType values include Video, Audio, and Subtitle. The timescale determines the temporal resolution of the track.

    // Example: Configuring a video track with H264
    let media_conf = MediaConfig::AvcConfig(AvcConfig {
        width: 1920,
        height: 1080,
        // ... other AvcConfig fields
    });
    
    let config = TrackConfig {
        track_type: TrackType::Video,
        timescale: 1000,
        language: String::from("eng"),
        media_conf,
    };
  2. Run mp4 CLI examples

    master

    The repository includes example CLI tools that you can run directly using cargo run. These are useful for inspecting MP4 files from the command line.

    • mp4info: Displays information about a movie file.
    • mp4dump: Dumps the contents of an MP4 file.
    # Run mp4info
    cargo run --example mp4info <movie.mp4>
    
    # Run mp4dump
    cargo run --example mp4dump <movie.mp4>
  3. Read MP4 file headers with Mp4Reader

    master

    To read an MP4 file, use mp4::Mp4Reader::read_header. This requires a reader that implements Read + Seek (such as std::io::BufReader) and the total size of the file in bytes.

    Once initialized, you can access metadata such as the major_brand from the ftyp box, the timescale from the moov.mvhd box, the file size(), duration(), and compatible_brands(). You can also iterate through tracks using the tracks() method to inspect track IDs, languages, types, and box types.

    use std::fs::File;
    use std::io::{BufReader};
    use mp4::{Result};
    
    fn main() -> Result<()> {
        let f = File::open("tests/samples/minimal.mp4").unwrap();
        let size = f.metadata()?.len();
        let reader = BufReader::new(f);
    
        let mp4 = mp4::Mp4Reader::read_header(reader, size)?;
    
        // Print boxes.
        println!("major brand: {}", mp4.ftyp.major_brand);
        println!("timescale: {}", mp4.moov.mvhd.timescale);
    
        // Use available methods.
        println!("size: {}", mp4.size());
    
        let mut compatible_brands = String::new();
        for brand in mp4.compatible_brands().iter() {
            compatible_brands.push_str(&brand.to_string());
            compatible_brands.push_str(",");
        }
        println!("compatible brands: {}", compatible_brands);
        println!("duration: {:?}", mp4.duration());
    
        // Track info.
        for track in mp4.tracks().values() {
            println!(
                "track: #{}({}) {} : {}",
                track.track_id(),
                track.language(),
                track.track_type()?,
                track.box_type()?,
            );
        }
        Ok(())
    }
  4. Configure MP4 file metadata with Mp4Config

    master

    Use Mp4Config to define the global metadata for your MP4 file. This includes the brand identifiers and the timescale used for all tracks.

    Fields:

    • major_brand: A FourCC representing the primary brand (e.g., isom).
    • minor_version: A u32 version number.
    • compatible_brands: A Vec<FourCC> of other brands the file is compatible with.
    • timescale: A u32 value defining the number of units per second, used to calculate durations.
  5. Write media samples to a new MP4 track

    master

    The Mp4TrackWriter (internal/utility) is used to build a track by feeding it Mp4Sample objects. It manages the underlying MP4 boxes like stsz (sample sizes), stts (time-to-sample), and co64 (chunk offsets) automatically.

    To complete a track, you must call write_end, which flushes any remaining buffered data and returns the final TrakBox required to finalize the MP4 container.

    // Note: Mp4TrackWriter is marked pub(crate) in this file,
    // implying it is used by higher-level components in the mp4 crate.
    // The pattern for usage is:
    // 1. Initialize writer with TrackConfig
    // 2. Loop: writer.write_sample(writer, &sample, movie_timescale)?
    // 3. Finalize: writer.write_end(writer)?
  6. Use UrlBox to specify track locations

    master

    The UrlBox is used within a DrefBox to provide a string-based location (URL or file path) for track data.

    Fields:

    • version: u8
    • flags: u32
    • location: String (The actual path or URL)

    Key methods:

    • get_type(): Returns BoxType::UrlBox.
    • get_size(): Returns the size including the header and the null-terminated location string.
    • to_json(): Serializes the box to a JSON string.
    • summary(): Returns a summary string in the format location=<location_string>.
    use mp4::mp4box::UrlBox;
    
    let url_box = UrlBox {
        version: 0,
        flags: 1,
        location: "/path/to/track.mp4".to_string(),
    };
    
    println!("{}", url_box.summary()); // Outputs: location=/path/to/track.mp4
  7. Use CttsBox and CttsEntry for MP4 parsing

    master

    The CttsBox (Composition Time to Sample) and CttsEntry types are used to handle MP4 box data that defines the composition time offsets for samples.

    CttsBox

    Represents the ctts box. It contains:

    • version: u8
    • flags: u32
    • entries: A Vec<CttsEntry> (Note: this field is skipped during JSON serialization).

    CttsEntry

    Represents an individual entry within the box:

    • sample_count: u32
    • sample_offset: i32 (The offset applied to the sample's composition time).
    use crate::mp4box::CttsBox;
    use crate::mp4box::CttsEntry;
    
    let ctts = CttsBox {
        version: 0,
        flags: 0,
        entries: vec![
            CttsEntry {
                sample_count: 1,
                sample_offset: 200,
            },
            CttsEntry {
                sample_count: 2,
                sample_offset: -100,
            },
        ],
    };
  8. Convert MP4 creation time to Unix epoch

    master

    MP4 files use an epoch starting from 1904-01-01. Use the creation_time function to convert these values to the standard Unix epoch (1970-01-01).

    let mp4_time: u64 = 2082844800; // Example value
    let unix_time = creation_time(mp4_time);
  9. Serialize SttsBox to JSON

    master
    The SttsBox implements Serialize via serde. You can convert a SttsBox instance into a JSON string using the to_json() method provided by the Mp4Box trait implementation. Note that the entries field is marked with #[serde(skip_serializing)], meaning the resulting JSON will only contain the version and flags fields.
  10. Use ElstBox and ElstEntry for MP4 track edit list parsing

    master

    The ElstBox represents the 'Edit List Box' in an MP4 container, which defines how a track's media should be played (e.g., offsets, durations, and rates). It contains a collection of ElstEntry objects.

    ElstBox Structure

    • version: The version of the box (0 or 1).
    • flags: Box flags.
    • entries: A Vec<ElstEntry> containing the edit list entries. Note that entries is skipped during serialization to JSON.

    ElstEntry Structure

    • segment_duration: The duration of the segment.
    • media_time: The time in the media.
    • media_rate: The integer part of the media rate.
    • media_rate_fraction: The fractional part of the media rate.

    Version Differences

    • Version 0: Uses 32-bit integers for segment_duration and media_time.
    • Version 1: Uses 64-bit integers for segment_duration and media_time.

    Implementation Details

    ElstBox implements the Mp4Box, ReadBox, and WriteBox traits, allowing it to be read from or written to any type implementing Read + Seek or Write.

    use crate::mp4box::ElstBox;
    use crate::mp4box::ElstEntry;
    
    let elst = ElstBox {
        version: 1,
        flags: 0,
        entries: vec![ElstEntry {
            segment_duration: 634634,
            media_time: 0,
            media_rate: 1,
            media_rate_fraction: 0,
        }],
    };
    
    // To write the box to a buffer:
    let mut buf = Vec::new();
    elst.write_box(&mut buf).unwrap();
    
    // To read the box from a reader:
    // let elst = ElstBox::read_box(reader, size).unwrap();