muxide 0.1.4

Zero-dependency pure-Rust MP4 muxer for recording applications. Includes CLI tool and library API.
Documentation

Muxide takes correctly-timestamped, already-encoded audio/video frames and produces a standards-compliant MP4 β€” pure Rust, zero runtime dependencies, no FFmpeg.


Why Muxide Exists

If you're building a recording pipeline in Rust, you know the tradeoffs:

Approach Tradeoff
FFmpeg CLI/libs External binary, GPL licensing concerns, "which build is this?"
GStreamer Complex plugin system, C dependencies, heavy runtime
Raw MP4 writing ISO-BMFF expertise required (sample tables, interleaving, moov layout)
"Minimal" crates Often missing fast-start, strict validation, or production ergonomics

Muxide solves one job cleanly:

Take already-encoded frames with correct timestamps β†’ produce a standards-compliant, immediately-playable MP4 β†’ using pure Rust.

Nothing more. Nothing less.

Installation & Usage

As a Library

cargo add muxide
use muxide::api::{MuxerBuilder, VideoCodec};

let mut muxer = MuxerBuilder::new(file)
    .video(VideoCodec::H264, 1920, 1080, 30.0)?
    .build()?;

// Write your encoded frames...
muxer.write_video(0.0, &h264_frame, true)?;
muxer.finish()?;

As a CLI Tool

# Install globally
cargo install muxide

# Or download pre-built binary from releases
# Then use:
muxide --help

# Quick examples:
muxide mux --video frames/ --output output.mp4 --width 1920 --height 1080 --fps 30
muxide mux --video video.h264 --audio audio.aac --output output.mp4
muxide validate --video frames/ --audio audio.aac
muxide info input.mp4

The CLI tool accepts raw encoded frames from stdin or files and produces MP4 output.

πŸ¦€ Used By CrabCamera

Muxide powers CrabCamera - the production-ready desktop camera plugin for Tauri applications. CrabCamera uses Muxide for reliable MP4 output with perfect A/V synchronization.

Check out CrabCamera if you need camera/audio recording in your Tauri app! It provides unified access to desktop cameras and microphones with professional controls.

Core Invariant

Muxide enforces a strict contract:

Your Responsibility Muxide's Guarantee
βœ“ Frames are already encoded βœ“ Valid ISO-BMFF (MP4)
βœ“ Timestamps are monotonic βœ“ Correct sample tables
βœ“ DTS provided for B-frames βœ“ Fast-start layout
βœ“ Codec headers in keyframes βœ“ No post-processing needed

If input violates the contract, Muxide fails fast with explicit errorsβ€”no silent corruption, no guessing.


Features

Category Supported Notes
Video H.264/AVC Annex B format
H.265/HEVC Annex B with VPS/SPS/PPS
AV1 OBU stream format
Audio AAC All profiles: LC, Main, SSR, LTP, HE, HEv2
Opus Raw packets, 48kHz
Container Fast-start moov before mdat for web playback
B-frames Explicit PTS/DTS support
Fragmented MP4 For DASH/HLS streaming
Metadata Title, creation time, language
Quality World-class errors Detailed diagnostics, hex dumps, JSON output
Production tested FFmpeg compatibility verified
Comprehensive testing 80+ tests, property-based validation

Design Principles

Principle Implementation
πŸ¦€ Pure Rust No unsafe, no FFI, no C bindings
πŸ“¦ Zero deps Only std β€” no runtime dependencies
🧡 Thread-safe Send + Sync when writer is
βœ… Well-tested Unit, integration, property tests
πŸ“œ MIT license No GPL, no copyleft concerns
🚨 Developer-friendly Exceptional error messages make debugging 10x faster

Note: no_std is not supported. Muxide requires std::io::Write.


Quick Start

use muxide::api::{MuxerBuilder, VideoCodec, AudioCodec, Metadata};
use std::fs::File;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let file = File::create("recording.mp4")?;
    
    let mut muxer = MuxerBuilder::new(file)
        .video(VideoCodec::H264, 1920, 1080, 30.0)
        .audio(AudioCodec::Aac, 48000, 2)
        .with_metadata(Metadata::new().with_title("My Recording"))
        .with_fast_start(true)
        .build()?;

    // Write encoded frames (from your encoder)
    // muxer.write_video(pts_seconds, h264_annex_b_bytes, is_keyframe)?;
    // muxer.write_audio(pts_seconds, aac_adts_bytes)?;

    let stats = muxer.finish_with_stats()?;
    println!("Wrote {} frames, {} bytes", stats.video_frames, stats.bytes_written);
    Ok(())
}

HEVC/H.265 (4K)

// Requires VPS, SPS, PPS in first keyframe
let mut muxer = MuxerBuilder::new(file)
    .video(VideoCodec::H265, 3840, 2160, 30.0)
    .build()?;
muxer.write_video(0.0, &hevc_annexb_with_vps_sps_pps, true)?;

AV1

// Requires Sequence Header OBU in first keyframe
let mut muxer = MuxerBuilder::new(file)
    .video(VideoCodec::Av1, 1920, 1080, 60.0)
    .build()?;
muxer.write_video(0.0, &av1_obu_with_sequence_header, true)?;

Opus Audio

// Opus always uses 48kHz internally (per spec)
let mut muxer = MuxerBuilder::new(file)
    .video(VideoCodec::H264, 1920, 1080, 30.0)
    .audio(AudioCodec::Opus, 48000, 2)
    .build()?;
muxer.write_audio(0.0, &opus_packet)?;

Fragmented MP4 (DASH/HLS)

let mut muxer = MuxerBuilder::new(file)
    .video(VideoCodec::H264, 1920, 1080, 30.0)
    .fragmented(true)  // Enable fMP4 mode
    .build()?;

// Write frames, then flush fragments periodically
muxer.write_video(0.0, &frame, true)?;
muxer.flush_fragment()?;  // Writes an moof+mdat pair

B-Frames with Explicit DTS

// When encoder produces B-frames, provide both PTS and DTS
muxer.write_video_with_dts(
    pts_seconds,  // Presentation timestamp
    dts_seconds,  // Decode timestamp (for B-frame ordering)
    &frame_data,
    is_keyframe
)?;

Command Line Tool

Muxide includes a command-line tool for quick testing and development workflows:

# Install the CLI tool
cargo install muxide

# Basic video-only muxing
muxide mux \
  --video keyframes.h264 \
  --width 1920 --height 1080 --fps 30 \
  --output recording.mp4

# Video + audio with metadata
muxide mux \
  --video stream.h264 \
  --audio stream.aac \
  --video-codec h264 \
  --audio-codec aac-he \
  --width 1920 --height 1080 --fps 30 \
  --sample-rate 44100 --channels 2 \
  --title "My Recording" \
  --language eng \
  --output final.mp4

# JSON output for automation
muxide mux --json [args...] > stats.json

# Validate input files without muxing
muxide validate --video input.h264 --audio input.aac

# Get info about supported codecs
muxide info

Supported Codecs:

  • Video: H.264 (AVC), H.265 (HEVC), AV1
  • Audio: AAC (all profiles), Opus

Features:

  • Progress reporting with --verbose
  • JSON output for CI/CD integration
  • Comprehensive error messages
  • Fast-start MP4 layout by default
  • Metadata support (title, language, creation time)

What Muxide Is Not

Muxide is intentionally focused. It does not:

Not Supported Why
Encoding/decoding Use openh264, x264, rav1e, etc.
Transcoding Not a codec library
Demuxing/reading MP4 Write-only by design
Timestamp correction Garbage in = error out
Non-MP4 containers MKV, WebM, AVI not supported
DRM/encryption Out of scope

Muxide is the last mile: encoder output β†’ playable file.


Use Cases

Muxide is a great fit for:

  • πŸŽ₯ Screen recorders β€” capture β†’ encode β†’ mux β†’ ship
  • πŸ“Ή Camera apps β€” webcam/IP camera recording pipelines
  • 🎬 Video editors β€” export timeline to MP4
  • πŸ“‘ Streaming β€” generate fMP4 segments for DASH/HLS
  • 🏭 Embedded systems β€” single binary, no external deps
  • πŸ”¬ Scientific apps β€” deterministic, reproducible output

Probably not a fit if you need encoding, demuxing, or legacy codecs (MPEG-2, etc.).


Example: Fast-Start Proof

The faststart_proof example demonstrates a structural MP4 invariant:

  • Two MP4 files are generated from the same encoded inputs
  • One with fast-start enabled, one without
  • No external tools are used at any stage
$ cargo run --example faststart_proof --release

output: recording_faststart.mp4
    layout invariant: moov before mdat = YES

output: recording_normal.mp4
    layout invariant: moov before mdat = NO

When served over HTTP, the fast-start file can begin playback without waiting for the full download (player behavior varies, but the layout property is deterministic).

This example is intentionally minimal:

  • Timestamps are generated in-code
  • No B-frames/DTS paths are exercised
  • The goal is container layout correctness, not encoding quality

Performance

Muxide is designed for minimal overhead. Muxing should never be your bottleneck.

Scenario Time Throughput
1000 H.264 frames 264 Β΅s 3.7M frames/sec
1000 H.264 + fast-start 362 Β΅s 2.8M frames/sec
1000 video + 1500 audio 457 Β΅s 2.2M frames/sec
100 4K frames (~6.5 MB) 14 ms 464 MB/sec
cargo bench

Benchmarks run on standard development hardware. In practice, encoding is always the bottleneck β€” muxing overhead is negligible.


Input Format Requirements

H.264/AVC

  • Format: Annex B (start codes: 00 00 00 01 or 00 00 01)
  • First keyframe must contain: SPS and PPS NAL units
  • NAL unit types: IDR (keyframe), non-IDR, SPS, PPS

H.265/HEVC

  • Format: Annex B (start codes)
  • First keyframe must contain: VPS, SPS, and PPS NAL units
  • NAL unit types: IDR_W_RADL, IDR_N_LP, CRA, VPS, SPS, PPS

AV1

  • Format: OBU (Open Bitstream Unit) stream
  • First keyframe must contain: Sequence Header OBU
  • OBU types: Sequence Header, Frame, Frame Header, Tile Group

AAC

  • Format: ADTS (Audio Data Transport Stream)
  • Header: 7-byte ADTS header per frame
  • Profiles: LC-AAC recommended

Opus

  • Format: Raw Opus packets (no container)
  • Sample rate: Always 48000 Hz (Opus specification)
  • Channels: 1 (mono) or 2 (stereo)

Documentation

Resource Description
πŸ“š API Reference Complete API documentation
πŸ“œ Design Charter Architecture decisions and rationale
πŸ“‹ API Contract Input/output guarantees

FAQ

FFmpeg is excellent, but:

  • External binary dependency (distribution complexity)
  • GPL licensing concerns for some builds
  • Process orchestration overhead
  • "What flags was this built with?" debugging

Muxide is a single cargo add with zero external dependencies.

No. Muxide is muxing only. For encoding, use:

  • openh264 β€” H.264 encoding (BSD)
  • rav1e β€” AV1 encoding (BSD)
  • x264/x265 β€” H.264/HEVC (GPL, via FFI)

Muxide will reject non-monotonic timestamps with a clear error. It does not attempt to "fix" broken input β€” this is by design to ensure predictable output.

Yes. Muxide has an extensive test suite (unit, integration, property-based tests) and is designed for predictable, deterministic behavior.


License

MIT β€” no GPL, no copyleft, no surprises.