mp4forge 0.8.0

Rust library and CLI for inspecting, probing, extracting, muxing, and rewriting MP4 structures
Documentation
use std::env;
use std::error::Error;

use mp4forge::FourCc;
use mp4forge::boxes::iso14496_12::{Saiz, Sbgp, Sgpd};
use mp4forge::boxes::iso23001_7::{Senc, Tenc};
use mp4forge::encryption::{
    ResolvedSampleEncryptionSource, SampleEncryptionContext, resolve_sample_encryption,
};
use mp4forge::extract::extract_box_as_bytes;
use mp4forge::walk::BoxPath;

fn main() {
    if let Err(error) = run() {
        eprintln!("{error}");
        std::process::exit(1);
    }
}

fn run() -> Result<(), Box<dyn Error>> {
    let Some(path) = env::args().nth(1) else {
        return Err("usage: cargo run --example resolve_sample_encryption -- <input.mp4>".into());
    };

    let input = std::fs::read(path)?;
    let tenc = extract_box_as_bytes::<Tenc>(
        &input,
        BoxPath::from([
            FourCc::from_bytes(*b"moov"),
            FourCc::from_bytes(*b"trak"),
            FourCc::from_bytes(*b"mdia"),
            FourCc::from_bytes(*b"minf"),
            FourCc::from_bytes(*b"stbl"),
            FourCc::from_bytes(*b"stsd"),
            FourCc::ANY,
            FourCc::from_bytes(*b"sinf"),
            FourCc::from_bytes(*b"schi"),
            FourCc::from_bytes(*b"tenc"),
        ]),
    )?
    .into_iter()
    .next();

    let senc = extract_box_as_bytes::<Senc>(
        &input,
        BoxPath::from([
            FourCc::from_bytes(*b"moof"),
            FourCc::from_bytes(*b"traf"),
            FourCc::from_bytes(*b"senc"),
        ]),
    )?
    .into_iter()
    .next()
    .ok_or("no senc box found")?;

    let sgpd = extract_box_as_bytes::<Sgpd>(
        &input,
        BoxPath::from([
            FourCc::from_bytes(*b"moof"),
            FourCc::from_bytes(*b"traf"),
            FourCc::from_bytes(*b"sgpd"),
        ]),
    )?
    .into_iter()
    .next();
    let sbgp = extract_box_as_bytes::<Sbgp>(
        &input,
        BoxPath::from([
            FourCc::from_bytes(*b"moof"),
            FourCc::from_bytes(*b"traf"),
            FourCc::from_bytes(*b"sbgp"),
        ]),
    )?
    .into_iter()
    .next();
    let saiz = extract_box_as_bytes::<Saiz>(
        &input,
        BoxPath::from([
            FourCc::from_bytes(*b"moof"),
            FourCc::from_bytes(*b"traf"),
            FourCc::from_bytes(*b"saiz"),
        ]),
    )?
    .into_iter()
    .next();

    let resolved = resolve_sample_encryption(
        &senc,
        SampleEncryptionContext {
            tenc: tenc.as_ref(),
            sgpd: sgpd.as_ref(),
            sbgp: sbgp.as_ref(),
            saiz: saiz.as_ref(),
        },
    )?;

    for sample in resolved.samples {
        let source = match sample.metadata_source {
            ResolvedSampleEncryptionSource::TrackEncryptionBox => "tenc".to_string(),
            ResolvedSampleEncryptionSource::SampleGroupDescription {
                group_description_index,
                description_index,
                fragment_local,
            } => format!(
                "sgpd(seig) group_description_index={} description_index={} fragment_local={}",
                group_description_index, description_index, fragment_local
            ),
        };

        println!(
            "sample {} source={} protected={} iv_len={} aux_size={}",
            sample.sample_index,
            source,
            sample.is_protected,
            sample.effective_initialization_vector().len(),
            sample.auxiliary_info_size
        );
    }

    Ok(())
}