@cooljapan/oximedia
v0.1.1
Published
WebAssembly bindings for OxiMedia
Readme
OxiMedia WASM
WebAssembly bindings for OxiMedia - Patent-free multimedia processing in the browser.
Features
- Format Probing: Detect container formats (WebM, Matroska, Ogg, FLAC, WAV, MP4)
- Container Demuxing: Extract compressed packets from media files
- Zero-Copy: Efficient buffer management using JavaScript
ArrayBuffer - Patent-Free: Only supports royalty-free codecs (AV1, VP9, VP8, Opus, Vorbis, FLAC)
- Browser-Native: No file system dependencies, works entirely in-memory
Installation
From npm
npm install @cooljapan/oximediaAvailable as three packages:
@cooljapan/oximedia(bundler — for webpack, vite, rollup, etc.)@cooljapan/oximedia-web(browser —<script type="module">)@cooljapan/oximedia-node(Node.js —require())
From Source
Prerequisites
Install wasm-pack:
cargo install wasm-packBuilding
Build for different targets:
# Build for all targets (web, node, bundler)
./build.sh
# Build for web only (development mode with debug symbols)
./build-dev.sh
# Build for specific target
wasm-pack build --target web --out-dir pkgAvailable targets:
web: For use in browsers via<script type="module">nodejs: For use in Node.jsbundler: For use with webpack, rollup, parcel, etc.
Usage
In the Browser
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>OxiMedia WASM Demo</title>
</head>
<body>
<input type="file" id="fileInput" accept="video/*,audio/*">
<pre id="output"></pre>
<script type="module">
import init, * as oximedia from './pkg-web/oximedia_wasm.js';
async function run() {
// Initialize the WASM module
await init();
console.log('OxiMedia version:', oximedia.version());
// Handle file input
document.getElementById('fileInput').addEventListener('change', async (e) => {
const file = e.target.files[0];
const arrayBuffer = await file.arrayBuffer();
const data = new Uint8Array(arrayBuffer);
// Probe format
try {
const result = oximedia.probe_format(data);
console.log('Format:', result.format());
console.log('Confidence:', result.confidence());
console.log('Description:', result.description());
// Create demuxer
const demuxer = new oximedia.WasmDemuxer(data);
const probe = demuxer.probe();
// Get streams
const streams = demuxer.streams();
let output = `Format: ${probe.format()}\n`;
output += `Streams: ${streams.length}\n\n`;
for (const stream of streams) {
output += `Stream ${stream.index()}:\n`;
output += ` Codec: ${stream.codec()}\n`;
output += ` Type: ${stream.media_type()}\n`;
const params = stream.codec_params();
if (params.has_video_params()) {
output += ` Resolution: ${params.width()}x${params.height()}\n`;
}
if (params.has_audio_params()) {
output += ` Sample Rate: ${params.sample_rate()} Hz\n`;
output += ` Channels: ${params.channels()}\n`;
}
output += '\n';
}
// Read some packets
let packetCount = 0;
while (packetCount < 10) {
const packet = demuxer.read_packet();
if (!packet) break;
output += `Packet ${packetCount}: `;
output += `stream=${packet.stream_index()}, `;
output += `size=${packet.size()} bytes, `;
output += `keyframe=${packet.is_keyframe()}\n`;
packetCount++;
}
document.getElementById('output').textContent = output;
} catch (e) {
console.error('Error:', e);
document.getElementById('output').textContent = 'Error: ' + e;
}
});
}
run();
</script>
</body>
</html>With a Bundler (webpack, vite, etc.)
import init, * as oximedia from 'oximedia-wasm';
async function processMedia(data) {
// Initialize WASM module
await init();
// Probe format
const result = oximedia.probe_format(data);
console.log('Detected format:', result.format());
// Create demuxer
const demuxer = new oximedia.WasmDemuxer(data);
demuxer.probe();
// Get streams
const streams = demuxer.streams();
console.log('Found', streams.length, 'streams');
// Read packets
let packet;
while ((packet = demuxer.read_packet()) !== null) {
console.log('Packet:', packet.stream_index(), packet.size());
}
}In Node.js
const fs = require('fs');
const { probe_format, WasmDemuxer } = require('./pkg-node/oximedia_wasm');
// Read file
const data = fs.readFileSync('video.webm');
// Probe format
const result = probe_format(data);
console.log('Format:', result.format());
// Demux
const demuxer = new WasmDemuxer(data);
demuxer.probe();
const streams = demuxer.streams();
console.log('Streams:', streams.length);API Reference
Functions
probe_format(data: Uint8Array): WasmProbeResult
Detects the container format from raw bytes.
Parameters:
data: At least the first 12 bytes of the file
Returns: WasmProbeResult with format and confidence
Throws: Exception if format cannot be detected
Classes
WasmDemuxer
Synchronous demuxer for extracting packets from containers.
Constructor:
new WasmDemuxer(data: Uint8Array)
Methods:
probe(): WasmProbeResult- Detect format and parse headersstreams(): WasmStreamInfo[]- Get stream informationread_packet(): WasmPacket | null- Read next packet (null at EOF)size(): number- Total size in bytesposition(): number- Current position in bytesis_eof(): boolean- Check if all packets have been read
WasmProbeResult
Result of format probing.
Methods:
format(): string- Container format nameconfidence(): number- Confidence score (0.0 to 1.0)description(): string- Human-readable descriptionis_video_container(): boolean- Check if video containeris_audio_only(): boolean- Check if audio-only container
WasmStreamInfo
Information about a media stream.
Methods:
index(): number- Stream indexcodec(): string- Codec namemedia_type(): string- Media type ("Video", "Audio", "Subtitle")is_video(): boolean- Check if video streamis_audio(): boolean- Check if audio streamduration_seconds(): number | undefined- Duration in secondstimebase_num(): number- Timebase numeratortimebase_den(): number- Timebase denominatorcodec_params(): WasmCodecParams- Codec parametersmetadata(): WasmMetadata- Stream metadata
WasmPacket
Compressed media packet.
Methods:
stream_index(): number- Stream indexsize(): number- Packet size in bytesdata(): Uint8Array- Packet datais_keyframe(): boolean- Check if keyframeis_corrupt(): boolean- Check if potentially corruptpts(): number- Presentation timestampdts(): number | undefined- Decode timestampduration(): number | undefined- Packet duration
Supported Formats
Containers
- Matroska (.mkv)
- WebM (.webm)
- Ogg (.ogg, .opus, .oga)
- FLAC (.flac)
- WAV (.wav)
- MP4 (.mp4) - AV1/VP9 only
Video Codecs
- AV1
- VP9
- VP8
- Theora
Audio Codecs
- Opus
- Vorbis
- FLAC
- PCM
License
Apache-2.0
See Also
- OxiMedia - The main Rust library
- wasm-bindgen - Rust/WASM interop
- wasm-pack - WASM build tool
