web-demuxer
Version:
Demux media files in the browser using WebAssembly, designed for WebCodecs
322 lines (244 loc) • 9.81 kB
Markdown
<h4 align="right"><strong>English</strong> | <a href="https://github.com/ForeverSc/web-demuxer/blob/main/README_CN.md">简体中文</a></h4>
<h1 align="center">Web-Demuxer</h1>
<p align="center">Demux media files in the browser using WebAssembly, designed for WebCodecs.</p>
<div align="center">
<a href="https://www.npmjs.com/package/web-demuxer"><img src="https://img.shields.io/npm/v/web-demuxer" alt="version"></a>
<a href="https://www.npmjs.com/package/web-demuxer"><img src="https://img.shields.io/npm/dm/web-demuxer" alt="downloads"></a>
<a href="https://www.jsdelivr.com/package/npm/web-demuxer"><img src="https://data.jsdelivr.com/v1/package/npm/web-demuxer/badge" alt="hits"></a>
</div>
WebCodecs provides decoding capabilities but lacks demuxing functionality. While mp4box.js is excellent for MP4 files, it only supports MP4 format. **Web-Demuxer** aims to support a wide range of multimedia formats in one package, specifically designed for seamless WebCodecs integration.
- 🪄 **WebCodecs-First Design** - API optimized for WebCodecs development with intuitive methods
- 📦 **Multi-Format Support** - Handle mov/mp4/mkv/webm/flv/m4v/wmv/avi/ts and more formats
- 🧩 **Customizable Build** - Configure and build demuxers for specific formats only
- 🔧 **Rich Media Info** - Extract detailed metadata similar to ffprobe output
```bash
npm install web-demuxer
```
```typescript
import { WebDemuxer } from "web-demuxer";
const demuxer = new WebDemuxer();
// Example: Get video frame at specific time
async function seek(file, time) {
// 1. Load video file
await demuxer.load(file);
// 2. Demux video file and generate VideoDecoderConfig and EncodedVideoChunk required by WebCodecs
const videoDecoderConfig = await demuxer.getDecoderConfig('video');
const videoEncodedChunk = await demuxer.seek('video', time);
// 3. Decode video frame through WebCodecs
const decoder = new VideoDecoder({
output: (frame) => {
// Render frame, e.g., using canvas drawImage
frame.close();
},
error: (e) => {
console.error('video decoder error:', e);
}
});
decoder.configure(videoDecoderConfig);
decoder.decode(videoEncodedChunk);
decoder.flush();
}
```
```bash
npm install web-demuxer
```
```html
<script type="module">
import { WebDemuxer } from 'https://cdn.jsdelivr.net/npm/web-demuxer/+esm';
</script>
```
**‼️ Important:** Place the WASM file in your static directory (e.g., `public/`) for proper loading.
```typescript
const demuxer = new WebDemuxer({
// Option 1: Use CDN
wasmFilePath: "https://cdn.jsdelivr.net/npm/web-demuxer@latest/dist/wasm-files/web-demuxer.wasm",
// Option 2: Use local file
// Copy dist/wasm-files/web-demuxer.wasm from npm package to public directory
// You can use plugins like vite-plugin-static-copy to sync automatically
// If JS and WASM are in the same public directory, wasmFilePath can be omitted
// wasmFilePath: "/path/to/your/public/web-demuxer.wasm"
});
```
- [Seek Video Frame](https://foreversc.github.io/web-demuxer/#example-seek) | [Source Code](https://github.com/bilibili/web-demuxer/blob/main/index.html#L131-L157)
- [Play Video](https://foreversc.github.io/web-demuxer/#example-play) | [Source Code](https://github.com/bilibili/web-demuxer/blob/main/index.html#L159-L197)
Creates a new WebDemuxer instance.
**Parameters:**
- `options.wasmFilePath` (optional): Custom WASM file path. Defaults to looking for `web-demuxer.wasm` in the script directory.
Loads a media file and initializes the WASM worker.
**Parameters:**
- `source`: File object or URL string
**Note:** All subsequent methods require successful `load()` execution.
Gets WebCodecs decoder configuration.
**Parameters:**
- `type`: `'video'` or `'audio'`
**Returns:** `VideoDecoderConfig` or `AudioDecoderConfig`
Seeks to specific time and returns encoded chunk.
**Parameters:**
- `type`: `'video'` or `'audio'`
- `time`: Time in seconds
- `seekFlag`: Seek direction (default: backward)
**Returns:** `EncodedVideoChunk` or `EncodedAudioChunk`
#### `read(type: MediaType, start?: number, end?: number, seekFlag?: AVSeekFlag): ReadableStream<EncodedVideoChunk | EncodedAudioChunk>`
Creates a stream of encoded chunks.
**Parameters:**
- `type`: `'video'` or `'audio'`
- `start`: Start time in seconds (default: 0)
- `end`: End time in seconds (default: end of file)
- `seekFlag`: Seek direction (default: backward)
**Returns:** `ReadableStream` of encoded chunks
### Media Information
#### `getMediaInfo(): Promise<WebMediaInfo>`
Extracts comprehensive media metadata (similar to ffprobe output).
**Returns:**
<details>
<summary>📋 Example Response (Click to expand)</summary>
```json
{
"format_name": "mov,mp4,m4a,3gp,3g2,mj2",
"duration": 263.383946,
"bit_rate": "6515500",
"start_time": 0,
"nb_streams": 2,
"streams": [
{
"id": 1,
"index": 0,
"codec_type": 0,
"codec_type_string": "video",
"codec_name": "h264",
"codec_string": "avc1.640032",
"color_primaries": "bt2020",
"color_range": "tv",
"color_space": "bt2020nc",
"color_transfer": "arib-std-b67",
"profile": "High",
"pix_fmt": "yuv420p",
"level": 50,
"width": 1080,
"height": 2336,
"channels": 0,
"sample_rate": 0,
"sample_fmt": "u8",
"bit_rate": "6385079",
"extradata_size": 36,
"extradata": "Uint8Array",
"r_frame_rate": "30/1",
"avg_frame_rate": "30/1",
"sample_aspect_ratio": "N/A",
"display_aspect_ratio": "N/A",
"start_time": 0,
"duration": 263.33333333333337,
"rotation": 0,
"nb_frames": "7900",
"tags": {
"creation_time": "2023-12-10T15:50:56.000000Z",
"language": "und",
"handler_name": "VideoHandler",
"vendor_id": "[0][0][0][0]"
}
},
{
"id": 2,
"index": 1,
"codec_type": 1,
"codec_type_string": "audio",
"codec_name": "aac",
"codec_string": "mp4a.40.2",
"profile": "",
"pix_fmt": "",
"level": -99,
"width": 0,
"height": 0,
"channels": 2,
"sample_rate": 44100,
"sample_fmt": "",
"bit_rate": "124878",
"extradata_size": 2,
"extradata": "Uint8Array",
"r_frame_rate": "0/0",
"avg_frame_rate": "0/0",
"sample_aspect_ratio": "N/A",
"display_aspect_ratio": "N/A",
"start_time": 0,
"duration": 263.3839455782313,
"rotation": 0,
"nb_frames": "11343",
"tags": {
"creation_time": "2023-12-10T15:50:56.000000Z",
"language": "und",
"handler_name": "SoundHandler",
"vendor_id": "[0][0][0][0]"
}
}
]
}
```
</details>
Gets information about a specific media stream.
**Parameters:**
- `type`: `'video'`, `'audio'` or `'subtitle'`
- `streamIndex`: Stream index (optional)
### Low-Level Packet Access
#### `seekMediaPacket(type: MediaType, time: number, seekFlag?: AVSeekFlag): Promise<WebAVPacket>`
Gets raw media packet at specific time.
**Parameters:**
- `type`: Media type (`'video'`, `'audio'` or `'subtitle'`)
- `time`: Time in seconds
- `seekFlag`: Seek direction (default: backward seek)
#### `readMediaPacket(type: MediaType, start?: number, end?: number, seekFlag?: AVSeekFlag): ReadableStream<WebAVPacket>`
Returns a `ReadableStream` for streaming raw media packet data.
**Parameters:**
- `type`: Media type (`'video'`, `'audio'` or `'subtitle'`)
- `start`: Start time in seconds (default: 0)
- `end`: End time in seconds (default: 0, read till end)
- `seekFlag`: Seek direction (default: backward seek)
### Utility Methods
#### `setLogLevel(level: AVLogLevel): void`
Sets logging verbosity level for debugging purposes.
**Parameters:**
- `level`: Log level (see `AVLogLevel` for available options)
#### `destroy(): void`
Cleans up resources and terminates worker.
## Custom Demuxer
Web-Demuxer provides two pre-built versions:
| Version | Size (gzipped) | Supported Formats |
|---------|----------------|-------------------|
| **Full** (`web-demuxer.wasm`) | 1131 kB | mov, mp4, avi, flv, mkv, webm, mpeg, asf, mpegts, etc. |
| **Mini** (`web-demuxer-mini.wasm`) | 493 kB | mov, mp4, mkv, webm, m4v |
### Building Custom Version
For specific format support, customize the build:
1. **Configure formats** in `Makefile`:
```makefile
DEMUX_ARGS = \
--enable-demuxer=mov,mp4,m4a,3gp,3g2,mj2
```
2. **Start Docker environment**:
```bash
npm run dev:docker:arm64
npm run dev:docker:x86_64
```
3. **Build custom WASM**:
```bash
npm run build:wasm
```
This project is licensed under the MIT License for the main codebase.
The `lib/` directory contains FFmpeg-derived code under the LGPL License.