Cross-Platform Media Engine, Inspired by BeOS.
Status: 0.1.0-dev. H.264 and HEVC (Main / Main10) decode on Linux (VA-API), Windows (D3D11 Video Decode), and macOS (VideoToolbox), plus an optional Apache-2.0 libhevc software fallback for HEVC. Progressive MP4/MOV demux (
avc1/hvc1/hev1→ Annex-B).Every other codec, in software, without FFmpeg:
mkff-codecs(Rust) andlibmkff_swcodecs(mkff/codecs.h, C) decode MP4/MOV, MKV/WebM, AVI, MXF, MPEG-TS/PS and Ogg with H.264, HEVC Main/Main10, VP8, VP9, AV1, MPEG-1/2, ProRes, DNxHD/HR, APV and MJPEG video plus AAC, Opus, AC-3/E-AC-3, MP1/2/3, FLAC, ALAC and Vorbis audio — adapted from the pure-Rust FilmCraft codec crates.MKFF Player: a desktop media player on egui / wgpu with audio-master A/V sync, seeking, GPU Y'CbCr → RGB and surround downmix, for every file
mkff-codecsopens.
.github/workflows/build.ymlbuilds and runs the full CTest suite on all three platforms (ubuntu-latest/macos-latest/windows-latest) on every push. CI runners typically have no GPU HEVC, so hardware decode fails cleanly; withMKFF_ENABLE_HEVC_SOFTWARE(default ON) the software path is exercised end-to-end against checked-in Annex-B fixtures.
MKFF is a portable media engine core (libmkff) with dynamically-loaded
platform backends (libmkff_platform_linux / _macos / _windows).
The core is C11, has a stable versioned C ABI, and keeps hardware frames
GPU-native (zero-copy export). CPU NV12 / P010 planes are available via
mkff_video_frame_map_cpu_planes for software frames and for hardware
frames when the platform implements readback (D3D11 staging / CVPixelBuffer
lock / VA derive-map).
MP4: progressive moov+mdat (avc1 / hvc1 / hev1) -> Annex-B AUs
Linux: Annex-B -> parser -> VA-API VLD -> NV12/P010 surface -> DMA-BUF
Windows: Annex-B -> parser -> D3D11/DXVA VLD -> NV12/P010 texture -> shared handle
macOS: Annex-B -> parser -> VideoToolbox -> IOSurface-backed CVPixelBuffer
HEVC SW: Annex-B -> in-core libhevc wrapper -> CPU NV12 (Main) / P010 (Main10)
Backend selection (MKFF_VideoBackend on MKFF_VideoDecoderDesc):
| Value | Behavior |
|---|---|
AUTO (default) |
Try platform HW; on failure fall back to software HEVC if built |
HARDWARE_ONLY |
Platform HW only; fail with CODEC_UNAVAILABLE if unsupported |
SOFTWARE_ONLY |
In-core libhevc only (when MKFF_ENABLE_HEVC_SOFTWARE is ON) |
H.264 paths are unchanged and remain hardware-oriented (no software H.264).
include/mkff/ public C API (portable + platform extensions)
src/codecs/h264/ portable H.264 Annex-B/SPS/PPS/slice/POC parser
src/codecs/hevc/ portable HEVC VPS/SPS/PPS/slice/POC parser
src/codecs/hevc/software libhevc C wrapper (optional software fallback)
src/core/ libmkff: context, loader, backend selection, SW glue
src/demux/mp4/ progressive MP4/MOV demux (avc1 / hvc1 / hev1)
src/platform/linux/ VA-API, DMA-BUF, H.264 + HEVC DPB
src/platform/windows/ D3D11/DXVA, shared handles, H.264 + HEVC DPB
src/platform/macos/ VideoToolbox, IOSurface export
src/cli/ mkff CLI
include/mkff/codecs.h C API of libmkff_swcodecs (software codecs)
bindings/rust/mkff-sys raw FFI
bindings/rust/mkff safe RAII wrapper (incl. Mp4Demux)
bindings/rust/mkff-codecs pure-Rust demux + decode of every codec (FilmCraft)
bindings/rust/mkff-codecs-capi libmkff_swcodecs: C ABI for mkff-codecs
bindings/rust/mkff-vk dma-buf -> VkImage (Linux)
bindings/rust/mkff-wgpu decode → map_cpu_planes → wgpu / egui player
bindings/rust/mkff-player MKFF Player: desktop media player (egui / wgpu, A/V sync)
tests/ CTest suite
testdata/ tiny Annex-B + progressive .mp4 fixtures
testdata/codecs/ one tiny clip per container / codec (mkff-codecs)
- C11 compiler: Clang (Linux/macOS) or MSVC (Windows)
- CMake >= 3.20, Ninja
- Linux:
libva,libva-drm,libdrmdevelopment packages - Windows: Windows SDK (D3D11/DXGI/DXVA)
- macOS: Xcode command line tools
- Rust toolchain (stable) for bindings
- Network at CMake configure time when fetching libhevc (or vendored
third_party/libhevc/)
No FFmpeg, GStreamer, or GPL/LGPL dependency is used in the product.
(scripts/gen_codec_fixtures.sh uses an ffmpeg binary only to encode the
test fixtures in testdata/codecs/; nothing links or runs it.)
See THIRD_PARTY_NOTICES for Apache-2.0 libhevc attribution when the software fallback is enabled.
[dependencies]
mkff = { git = "https://github.com/futureboard/mediakit-foundation" }Default features: bundled, hevc, hevc-software-fallback.
| Feature | Effect |
|---|---|
bundled |
Build native libs via CMake during cargo build |
hevc |
MKFF_ENABLE_HEVC=ON (parser + HW paths) |
hevc-software-fallback |
Also MKFF_ENABLE_HEVC_SOFTWARE=ON (libhevc) |
Disable software fallback:
mkff = { git = "...", default-features = false, features = ["bundled", "hevc"] }Helpers: Context::video_decoder_hevc(), video_decoder_hevc_with_backend(),
Context::video_decoder(), Mp4Demux, VideoBackend, PixelFormat::P010,
VideoFrame::map_cpu_planes().
# Linux
cmake --preset linux-clang-debug
cmake --build --preset linux-clang-debug
ctest --preset linux-clang-debug
# macOS
cmake --preset macos-clang-debug
cmake --build --preset macos-clang-debug
ctest --preset macos-clang-debug
# Windows (Ninja + cl on PATH, e.g. Developer Command Prompt / vcvars)
cmake --preset windows-msvc-debug
cmake --build --preset windows-msvc-debug
ctest --preset windows-msvc-debug
# Rust
cargo build -p mkff
cargo test -p mkffCMake options:
MKFF_ENABLE_HEVC(default ON)MKFF_ENABLE_HEVC_SOFTWARE(default ON) — FetchContent libhevc
mkff devices # Linux only
mkff va-info # Linux only
mkff decode-test input.h264 --frames 120
mkff decode-test input.hevc --codec hevc --backend auto --frames 120
mkff decode-test input.hevc --codec hevc --backend sw --frames 10
mkff export-test input.h264 --frames 10 # Linux only
mkff benchmark input.hevc --codec hevc --seconds 10
mkff codec-info hevc --backend swPure-Rust, safe-code demux and decode for every container and codec MKFF handles, on every platform, with no native codec library. It adapts the FilmCraft codec crates (MIT OR Apache-2.0, written from the public specifications), pinned to one revision.
| Kind | Supported |
|---|---|
| Containers | MP4 / MOV / 3GP, Matroska / WebM, AVI (OpenDML), MXF (OP1a / OP-Atom), MPEG-TS / M2TS, MPEG-PS / VOB, Ogg, YUV4MPEG2, standalone audio files; IVF and Annex-B elementary streams via the packet decoders |
| Video | H.264 (8-bit 4:2:0), HEVC Main / Main10, VP8, VP9 (profiles 0-3), AV1, MPEG-1 / MPEG-2, ProRes 422 / 4444 (+alpha), DNxHD / DNxHR, APV, Motion JPEG, uncompressed |
| Audio | AAC (LC, HE-AAC core; raw, ADTS, LATM), Opus, AC-3 / E-AC-3, MPEG audio layers I / II / III, FLAC, ALAC, Vorbis, PCM / LPCM |
Checked against an independent decoder on testdata/codecs/: H.264, HEVC
Main10, VP8, VP9 and AV1 are bit-exact; ProRes, DNxHR and MPEG-2 within ±1
LSB (IDCT rounding the specs allow).
Surround AC-3 / E-AC-3 in MP4 / MOV keeps every channel: the sample entry's
ChannelCount is 2 by specification (ETSI TS 102 366 Annex F), which
FilmCraft's MP4 source took literally, keeping only front left / right of a 5.1
track; MediaFile reads such tracks with the channel count the decoder reports
(testdata/codecs/tone51_*.mp4).
Rust:
[dependencies]
mkff-codecs = { git = "https://github.com/futureboard/mediakit-foundation" }
# or, alongside libmkff: mkff = { git = "...", features = ["software-codecs"] } → mkff::codecsuse mkff_codecs::{MediaFile, VideoCodec, VideoDecoder};
// Any file: random access by frame, audio at any rate.
let clip = MediaFile::open("clip.mkv")?;
let frame = clip.video_frame(42)?; // planar YUV 8/10/12-bit or RGBA
let nv12 = frame.to_nv12(); // or to_p010() / to_rgba8()
let pcm = clip.audio(0, 48_000, 48_000)?; // 1 s of stream 0 at 48 kHz
// Elementary streams, e.g. Annex-B AUs from mkff::Mp4Demux:
let mut dec = VideoDecoder::new(VideoCodec::H264)?;
for frame in dec.decode(access_unit, pts)? { /* … */ }cargo run -p mkff-codecs --release --example probe -- clip.mxf prints what
it sees and can dump NV12 / native planes.
Encode + mux (mkff_codecs::encode): H.264 (Baseline / Main / High, CRF / CBR / VBR,
optional B-frames) and ProRes (Proxy … 4444 XQ, alpha) video from RGBA8 (or planar 4:2:0 for
H.264), AAC-LC audio (1–8 channels, CBR), written to MP4 / MOV by MediaWriter, either
progressive or fragmented (a fragment per video keyframe, so a recording cut short stays
playable). Encoders from the same pinned FilmCraft revision (filmcraft-h264enc,
filmcraft-prores, filmcraft-aac, filmcraft-isobmff).
use mkff_codecs::encode::{AudioEncoder, Container, MediaWriter, VideoEncoder, VideoEncoderConfig};
let mut video = VideoEncoder::new(VideoEncoderConfig::h264(1920, 1080, 60, 1))?;
let mut audio = AudioEncoder::aac(48_000, 2, 192_000)?;
let mut out = MediaWriter::create("show.mp4", Container::Mp4, /* fragmented */ true)?;
let (v, a) = (out.add_video_track(&video)?, out.add_audio_track(&audio)?);
for p in video.encode_rgba(&rgba, frame_index)? { out.write(v, &p)?; }
for p in audio.encode(&[&left, &right])? { out.write(a, &p)?; }
// … then video.flush() / audio.flush() into `out`, and out.finish()cargo test -p mkff-codecs --test encode round-trips every encoder through MediaFile.
C (libmkff_swcodecs): build with cargo build -p mkff-codecs-capi --release (→ target/release/libmkff_swcodecs.{so,dylib,a} /
mkff_swcodecs.dll), include mkff/codecs.h. It is
independent of libmkff; link either or both.
MKFF_SwMedia *m;
mkff_sw_media_open_path("clip.webm", &m);
MKFF_SwFrame *f;
mkff_sw_media_read_video_frame(m, 0, &f);
MKFF_SwFrameInfo fi; MKFF_INIT_STRUCT_HEADER(&fi);
mkff_sw_frame_get_info(f, &fi); /* planes, depth, chroma, colour */
mkff_sw_frame_destroy(f);
mkff_sw_media_destroy(m);Packet decoders (mkff_sw_video_decoder_*, mkff_sw_audio_decoder_*) follow
the same submit / receive / flush contract as mkff_video_decoder_*.
MKFF_VideoCodec gains VP8, MPEG1, MPEG2, PRORES, DNXHD, APV and
MJPEG (software-only; libmkff's hardware path rejects them as before).
| Codec | Profiles | Output | HW | SW |
|---|---|---|---|---|
| H.264 | Baseline/Main (existing) | NV12 | Linux/Windows/macOS | — |
| HEVC | Main (8-bit 4:2:0), Main10 (10-bit 4:2:0) | NV12 / P010 | VA-API / D3D11 DXVA / VideoToolbox | libhevc Main→NV12 (optional) |
Everything else (and software H.264 / HEVC Main10) is in
mkff-codecs.
Software fallback uses Ittiam libhevc, which is 8-bit only in the
pinned tree (IHEVCD_UNSUPPORTED_BIT_DEPTH for Main10). Main10 decode
and P010 output are hardware-backed (VA-API / D3D11 / VideoToolbox when
the device supports them). SOFTWARE_ONLY on a Main10 stream returns
MKFF_RESULT_ERROR_CODEC_UNAVAILABLE.
Rejected: 4:2:2 / 4:4:4, non-8/10 bit depth, tiles/WPP on HW paths this milestone.
Linux dma-buf → VkImage via VK_EXT_image_drm_format_modifier. NV12
today; P010 drm fourcc is exported when Main10 surfaces are available.
Progressive (non-fragmented) MP4/MOV with moov + mdat. First vide
track only; sample entries avc1 (H.264) and hvc1/hev1 (HEVC).
Samples are converted to Annex-B (length-prefixed NALs → start codes;
avcC/hvcC parameter sets prepended on the first / sync samples).
C API: mkff_mp4_demux_open_path / open_memory, get_video_track,
read_access_unit, seek_sample. Rust: mkff::Mp4Demux.
Not supported: audio tracks, fragmented MP4 (moof/mdat segments),
encryption (encv), edit-list reordering beyond basic ctts.
Fixtures: testdata/tiny_baseline_64x64.mp4 (avc1),
testdata/tiny_main_256x144.mp4 (hvc1).
Portable demos: decode → map_cpu_planes (NV12) → upload / egui.
Fullscreen WGSL viewer (R8 + RG8 upload → YUV→RGB; HEVC Annex-B SW):
cargo run -p mkff-wgpu --example view
cargo run -p mkff-wgpu --example view -- path/to/clip.hevcSimple player (egui on wgpu — play/pause, frame step, loop, FPS). Plays
any container / codec: MP4 and Annex-B go to libmkff's hardware decoders
first; everything else, and anything libmkff can't decode on this machine,
falls back to mkff-codecs:
cargo run -p mkff-wgpu --example player
cargo run -p mkff-wgpu --example player -- testdata/tiny_main_256x144.mp4
cargo run -p mkff-wgpu --example player -- testdata/tiny_baseline_64x64.mp4
cargo run -p mkff-wgpu --example player -- path/to/clip.hevc
cargo run -p mkff-wgpu --example player -- testdata/codecs/vp9_opus.webm
cargo run -p mkff-wgpu --example player -- testdata/codecs/prores_hq.movDefaults to testdata/tiny_main_256x144.mp4. Progressive MP4 uses demux +
AUTO decode (H.264 HW on Windows when available; HEVC may use HW or
libhevc SW for Main). Annex-B .hevc still uses SOFTWARE_ONLY + libhevc.
Frames are decoded up front; no audio. Hardware zero-copy into wgpu is
not wired yet. Needs a GPU/display; not part of default CI.
A desktop media player for everything mkff-codecs decodes, in pure Rust
(no FFmpeg, no CMake): egui on wgpu (Vulkan / Metal / D3D12 / GL), audio
through cpal (ALSA / CoreAudio / WASAPI).
cargo run -p mkff-player --release -- path/to/clip.mp4
cargo run -p mkff-player --release -- --helpTested with Dolby's DD+ test signal
Audio_ID_720p_50fps_h264_514ch_448kbps_ddp.mp4 (H.264 720p50 + E-AC-3 5.1):
32 s in 32.0 s wall time, decode ≈ 1.2 ms / frame, A/V within one frame, all six
channels decoded and downmixed for stereo output.
- Playback engine (
mkff_player, no UI dependency): a video decode thread (bounded queue, skips ahead when decoding falls behind), an audio decode thread feeding a lock-free ring buffer, and an audio-master clock from the device callback's frame counter and reported latency (system clock without audio). Seeks start an epoch: the callback drops stale samples without blocking, the clock waits for the first picture (preroll) and one audio chunk. Decoder panics and errors are caught and reported; a dead audio device falls back to the system clock. - Video: Y'CbCr planes uploaded as textures and converted in a WGSL shader (BT.601 / 709 / 2020 matrices, limited / full range, any chroma subsampling, sRGB or linear targets); pixel aspect respected. 10 / 12-bit is shown at 8 bits.
- Audio: resampled to the device rate; 5.1 / 7.1 downmixed to stereo (ITU-R BS.775, LFE dropped) or played discretely on a surround device; click-free volume ramps.
- UI: auto-hiding controls, seek bar with time preview and scrubbing, volume / mute, speed 0.25–2× (resampled: pitch follows), loop, frame stepping, full screen, PNG snapshot, statistics overlay (I), drag & drop, recent files, remembered volume / window, keyboard shortcuts (H lists them).
- Headless:
mkff-player --audio null --headless 30 clip.mp4plays without a window on a simulated audio device and prints frame / drop / A-V statistics;cargo test -p mkff-playerruns the engine againsttestdata/the same way.
Linux builds need libasound2-dev; the file dialog uses xdg-desktop-portal or
zenity (without either, drop files onto the window or pass them on the command
line). Not yet: libmkff hardware decode / zero-copy upload, Dolby Atmos (JOC)
objects (the 5.1 bed plays), HDR tone mapping, subtitles, playlists.
Fragmented MP4 in libmkff's own demuxer, bitstream seeking as a product feature, hardware VP9/AV1, mid-stream resolution change, long-term reference picture edge cases beyond the supported Main/Main10 subset.
MIT — see LICENSE. Third-party libhevc is Apache-2.0; the
FilmCraft codec crates used by mkff-codecs are MIT OR Apache-2.0 (used
under MIT), and their audio bootstrap decoders come from Symphonia
(MPL-2.0, unmodified); see THIRD_PARTY_NOTICES.
