Experimental DNxHD/DNxHR (VC-3) decoding and MXF demuxing for modern browsers, with a Mediabunny extension entry point.
Warning
This is a 0.x project. The supported codec scope is intentional, but the API and browser integration may change
before 1.0. Validate it against your own media before using it in production.
GitHub Packages requires the @jhodges10 scope to use its npm registry. Add this line to your user or project
.npmrc:
@jhodges10:registry=https://npm.pkg.github.comAuthenticate with a GitHub personal access token that has read:packages, then install the package:
npm login --scope=@jhodges10 --auth-type=legacy --registry=https://npm.pkg.github.com
npm install @jhodges10/turbovc3 mediabunnyThe first package version will be published when its matching GitHub Release is published. npmjs publication is not configured yet.
Register the extension once before creating a video sink:
import { registerDnxDecoder } from "@jhodges10/turbovc3";
import { BlobSource, Input, QuickTimeInputFormat, VideoSampleSink } from "mediabunny";
registerDnxDecoder();
const input = new Input({
formats: [new QuickTimeInputFormat()],
source: new BlobSource(file)
});
const track = await input.getPrimaryVideoTrack();
if (!track) throw new Error("No video track found.");
const sink = new VideoSampleSink(track);
const sample = await sink.getSample(0);registerDnxDecoder() is idempotent. It handles AVdn and AVdh, preserves timing, dimensions, and color metadata,
and emits I422, I422P10, I422P12, I444P10, or I444P12 samples.
Mediabunny handles MOV/QuickTime demuxing. The separate MXF entry point handles OP1a and OPAtom track metadata, index tables, essence packets, and random packet reads:
import { MxfDemuxer } from "@jhodges10/turbovc3/mxf";
const demuxer = await MxfDemuxer.open(file);
const videoTrack = demuxer.tracks.find((track) => track.kind === "video");
if (!videoTrack) throw new Error("No MXF video track found.");
const firstPacket = demuxer.packetsForTrack(videoTrack)[0];
const encodedFrame = await demuxer.readPacket(firstPacket);For a one-call DNx adapter, use demuxDnxMxf() from the root module.
| Area | Current support |
|---|---|
| Sample entries | AVdn (DNxHD), AVdh (DNxHR) |
| Frames | Progressive through 4096×2160 |
| Native output | 8/10/12-bit 4:2:2; 10/12-bit 4:4:4 YUV/RGB |
| Conversion | 4:2:2 to 4:2:0/4:4:4; planar DNx RGB to 4:4:4 YUV |
| MOV/QuickTime | Through Mediabunny |
| MXF | OP1a and OPAtom DNx essence; PCM track metadata and packet extraction |
| Deferred | Interlaced/MBAFF, alpha, and a dedicated 12-bit 4:4:4 fixture |
CI performs real FFmpeg-oracle comparisons for DNxHD 8-bit, DNxHR HQX 10-bit, and DNxHR 444 10-bit, plus OP1a and OPAtom demuxing. The extended local suite covers additional profiles and the external FFmpeg 12-bit FATE sample.
Release packages include two WASM binaries. Decoder creation chooses the fastest available path and falls back safely:
- Cross-origin-isolated pages use shared-memory Zig/WASM row workers.
- Other worker-capable pages use a bounded packet-worker pool.
- Environments without usable workers use synchronous Zig/WASM and C/WASM IDCT.
- If release assets cannot load, decoding continues through the TypeScript implementation.
Shared-memory decoding requires Worker, SharedArrayBuffer, and crossOriginIsolated === true, which normally means
serving suitable COOP/COEP headers. The package does not require cross-origin isolation for ordinary decoding.
Mediabunny 1.50.8 does not yet classify DNx as a native VideoCodec. Registration therefore installs a guarded
compatibility shim that disables itself when a future Mediabunny release provides that support.
The supported root surface contains:
registerDnxDecoder()and container inspection helpersDecoder,Frame, their options, results, and typed decoder errors- DNx frame-header inspection helpers and types
DnxAudioPlayback,DnxRandomAccessDecoder, andDnxWebGpuRendererdemuxDnxMxf(),isMxfFile(), and MXF adapter types
Low-level bit reading, coefficient reconstruction, IDCT, worker coordination, and native backend modules are internal.
The full general-purpose MXF surface is exported from @jhodges10/turbovc3/mxf.
Requirements for the ordinary workflow are Node.js 22+ and npm:
npm ci
npm run check
npm run build
npm test
npm run test:packageNative development additionally requires Zig 0.16.0 and Emscripten 6.0.2:
npm run build:wasm
npm run test:native
REQUIRE_WASM_ASSETS=1 npm run test:packageFFmpeg 8.x is only required to regenerate committed fixtures or run the full local oracle corpus. See CONTRIBUTING.md for the workflow and research/README.md for codec notes.
turbovc3 is available under the Mozilla Public License 2.0. Please report vulnerabilities through GitHub private vulnerability reporting, not a public issue. See SECURITY.md for details.