@napi-rs/webcodecs 0.0.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -2
- package/index.d.ts +31 -3
- package/package.json +23 -10
- package/standard.d.ts +26 -0
package/README.md
CHANGED
|
@@ -10,6 +10,7 @@ WebCodecs API implementation for Node.js using FFmpeg, built with [NAPI-RS](http
|
|
|
10
10
|
- **Video encoding/decoding** - H.264, H.265, VP8, VP9, AV1
|
|
11
11
|
- **Audio encoding/decoding** - AAC, Opus, MP3, FLAC, Vorbis, PCM variants
|
|
12
12
|
- **Image decoding** - JPEG, PNG, WebP, GIF, BMP, AVIF
|
|
13
|
+
- **Canvas integration** - Create VideoFrames from `@napi-rs/canvas` for graphics and text rendering
|
|
13
14
|
- **Hardware acceleration** - Zero-copy GPU encoding with VideoToolbox (macOS), NVENC (NVIDIA), VAAPI (Linux), QSV (Intel)
|
|
14
15
|
- **Cross-platform** - macOS, Windows, Linux (glibc/musl, x64/arm64/armv7)
|
|
15
16
|
- **Structured logging** - FFmpeg logs redirected to Rust `tracing` crate for easy integration
|
|
@@ -24,6 +25,14 @@ pnpm add @napi-rs/webcodecs
|
|
|
24
25
|
yarn add @napi-rs/webcodecs
|
|
25
26
|
```
|
|
26
27
|
|
|
28
|
+
### Optional: Canvas Integration
|
|
29
|
+
|
|
30
|
+
For creating VideoFrames from canvas content, install `@napi-rs/canvas`:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npm install @napi-rs/canvas
|
|
34
|
+
```
|
|
35
|
+
|
|
27
36
|
## Quick Start
|
|
28
37
|
|
|
29
38
|
### Video Encoding
|
|
@@ -157,6 +166,39 @@ result.image.close()
|
|
|
157
166
|
decoder.close()
|
|
158
167
|
```
|
|
159
168
|
|
|
169
|
+
### VideoFrame from Canvas
|
|
170
|
+
|
|
171
|
+
Create VideoFrames from `@napi-rs/canvas` for graphics, text rendering, or image compositing:
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
import { VideoFrame } from '@napi-rs/webcodecs'
|
|
175
|
+
import { createCanvas } from '@napi-rs/canvas'
|
|
176
|
+
|
|
177
|
+
const canvas = createCanvas(1920, 1080)
|
|
178
|
+
const ctx = canvas.getContext('2d')
|
|
179
|
+
|
|
180
|
+
// Draw graphics
|
|
181
|
+
ctx.fillStyle = '#FF0000'
|
|
182
|
+
ctx.fillRect(0, 0, 1920, 1080)
|
|
183
|
+
ctx.fillStyle = '#FFFFFF'
|
|
184
|
+
ctx.font = '48px sans-serif'
|
|
185
|
+
ctx.fillText('Hello WebCodecs!', 100, 100)
|
|
186
|
+
|
|
187
|
+
// Create VideoFrame from canvas (timestamp required per W3C spec)
|
|
188
|
+
const frame = new VideoFrame(canvas, {
|
|
189
|
+
timestamp: 0,
|
|
190
|
+
duration: 33333, // optional: frame duration in microseconds
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
console.log(frame.format) // 'RGBA'
|
|
194
|
+
console.log(frame.codedWidth, frame.codedHeight) // 1920, 1080
|
|
195
|
+
|
|
196
|
+
// Use with VideoEncoder (see Video Encoding section)
|
|
197
|
+
frame.close()
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
**Note:** Canvas pixel data is copied as RGBA format with sRGB color space.
|
|
201
|
+
|
|
160
202
|
## Supported Codecs
|
|
161
203
|
|
|
162
204
|
### Video
|
|
@@ -213,7 +255,7 @@ This implementation is validated against the [W3C Web Platform Tests](https://gi
|
|
|
213
255
|
|
|
214
256
|
| Status | Count | Percentage |
|
|
215
257
|
| ----------- | ----- | ---------- |
|
|
216
|
-
| **Passing** |
|
|
258
|
+
| **Passing** | 573 | 99.1% |
|
|
217
259
|
| **Skipped** | 5 | 0.9% |
|
|
218
260
|
| **Failing** | 0 | 0% |
|
|
219
261
|
|
|
@@ -296,6 +338,40 @@ const encoder = new VideoEncoder({
|
|
|
296
338
|
})
|
|
297
339
|
```
|
|
298
340
|
|
|
341
|
+
### VideoFrame Format Conversion
|
|
342
|
+
|
|
343
|
+
`VideoFrame.copyTo()` and `VideoFrame.allocationSize()` support format conversion per W3C WebCodecs spec:
|
|
344
|
+
|
|
345
|
+
```typescript
|
|
346
|
+
const frame = new VideoFrame(i420Data, {
|
|
347
|
+
format: 'I420',
|
|
348
|
+
codedWidth: 1920,
|
|
349
|
+
codedHeight: 1080,
|
|
350
|
+
timestamp: 0,
|
|
351
|
+
})
|
|
352
|
+
|
|
353
|
+
// Get allocation size for RGBA output
|
|
354
|
+
const rgbaSize = frame.allocationSize({ format: 'RGBA' })
|
|
355
|
+
|
|
356
|
+
// Copy with format conversion (I420 → RGBA)
|
|
357
|
+
const rgbaBuffer = new Uint8Array(rgbaSize)
|
|
358
|
+
const layout = await frame.copyTo(rgbaBuffer, { format: 'RGBA' })
|
|
359
|
+
|
|
360
|
+
frame.close()
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
**Supported conversions:**
|
|
364
|
+
|
|
365
|
+
| Source Format | Target Format | Status |
|
|
366
|
+
| ---------------------------- | ---------------------- | -------------------- |
|
|
367
|
+
| I420, I422, I444, NV12, NV21 | RGBA, RGBX, BGRA, BGRX | ✅ |
|
|
368
|
+
| RGBA, RGBX, BGRA, BGRX | RGBA, RGBX, BGRA, BGRX | ✅ |
|
|
369
|
+
| RGBA, RGBX, BGRA, BGRX | I420, I422, I444, NV12 | ❌ NotSupportedError |
|
|
370
|
+
|
|
371
|
+
Per WPT `videoFrame-copyTo-rgb.any.js`, RGB-to-YUV conversion throws `NotSupportedError`.
|
|
372
|
+
|
|
373
|
+
Custom layouts with overflow-inducing values (e.g., `offset: 2³²-2`) throw `TypeError` via checked arithmetic. Rect alignment is validated against the source format during conversion.
|
|
374
|
+
|
|
299
375
|
### ImageDecoder Options
|
|
300
376
|
|
|
301
377
|
ImageDecoder supports all W3C spec options:
|
|
@@ -355,7 +431,7 @@ This package implements the [W3C WebCodecs API](https://w3c.github.io/webcodecs/
|
|
|
355
431
|
|
|
356
432
|
- `VideoEncoder` / `VideoDecoder` - Video encoding and decoding with EventTarget support
|
|
357
433
|
- `AudioEncoder` / `AudioDecoder` - Audio encoding and decoding with EventTarget support
|
|
358
|
-
- `VideoFrame` - Raw video frame data (
|
|
434
|
+
- `VideoFrame` - Raw video frame data (supports buffer data, existing VideoFrame, or `@napi-rs/canvas` Canvas)
|
|
359
435
|
- `AudioData` - Raw audio sample data
|
|
360
436
|
- `EncodedVideoChunk` / `EncodedAudioChunk` - Encoded media data
|
|
361
437
|
- `ImageDecoder` - Static image decoding
|
package/index.d.ts
CHANGED
|
@@ -33,6 +33,33 @@ export {
|
|
|
33
33
|
AllowSharedBufferSource,
|
|
34
34
|
} from './standard'
|
|
35
35
|
|
|
36
|
+
export type TypedArray =
|
|
37
|
+
| Int8Array
|
|
38
|
+
| Uint8Array
|
|
39
|
+
| Uint8ClampedArray
|
|
40
|
+
| Int16Array
|
|
41
|
+
| Uint16Array
|
|
42
|
+
| Int32Array
|
|
43
|
+
| Uint32Array
|
|
44
|
+
| Float32Array
|
|
45
|
+
| Float64Array
|
|
46
|
+
| BigInt64Array
|
|
47
|
+
| BigUint64Array
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Interface for Canvas-like objects compatible with VideoFrame constructor.
|
|
51
|
+
* Compatible with @napi-rs/canvas Canvas class.
|
|
52
|
+
*
|
|
53
|
+
* @napi-rs/canvas is an optional peer dependency. If installed, Canvas objects
|
|
54
|
+
* can be used as VideoFrame sources. The Canvas pixel data is copied (RGBA format).
|
|
55
|
+
*/
|
|
56
|
+
export interface CanvasLike {
|
|
57
|
+
readonly width: number
|
|
58
|
+
readonly height: number
|
|
59
|
+
/** Returns raw RGBA pixel data as a Buffer */
|
|
60
|
+
data(): Uint8Array
|
|
61
|
+
}
|
|
62
|
+
|
|
36
63
|
export type TypedArray =
|
|
37
64
|
| Int8Array
|
|
38
65
|
| Uint8Array
|
|
@@ -668,13 +695,14 @@ export declare class VideoEncoder {
|
|
|
668
695
|
*/
|
|
669
696
|
export declare class VideoFrame {
|
|
670
697
|
/**
|
|
671
|
-
* Create a new VideoFrame from buffer data
|
|
698
|
+
* Create a new VideoFrame from buffer data, another VideoFrame, or a Canvas (W3C WebCodecs spec)
|
|
672
699
|
*
|
|
673
|
-
*
|
|
700
|
+
* Constructor forms per W3C spec:
|
|
674
701
|
* 1. `new VideoFrame(data, init)` - from BufferSource with VideoFrameBufferInit
|
|
675
702
|
* 2. `new VideoFrame(source, init?)` - from another VideoFrame with optional VideoFrameInit
|
|
703
|
+
* 3. `new VideoFrame(canvas, init)` - from @napi-rs/canvas Canvas (requires timestamp in init)
|
|
676
704
|
*/
|
|
677
|
-
constructor(source: VideoFrame | Uint8Array, init?: VideoFrameBufferInit | VideoFrameInit)
|
|
705
|
+
constructor(source: VideoFrame | Uint8Array | CanvasLike, init?: VideoFrameBufferInit | VideoFrameInit)
|
|
678
706
|
/** Get the pixel format */
|
|
679
707
|
get format(): VideoPixelFormat | null
|
|
680
708
|
/** Get the coded width in pixels (returns 0 when closed per W3C spec) */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@napi-rs/webcodecs",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "WebCodecs API implementation for Node.js using FFmpeg",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"N-API",
|
|
@@ -14,6 +14,10 @@
|
|
|
14
14
|
"type": "git",
|
|
15
15
|
"url": "git+ssh://git@github.com/Brooooooklyn/webcodecs-node.git"
|
|
16
16
|
},
|
|
17
|
+
"funding": {
|
|
18
|
+
"type": "github",
|
|
19
|
+
"url": "https://github.com/sponsors/Brooooooklyn"
|
|
20
|
+
},
|
|
17
21
|
"license": "MIT",
|
|
18
22
|
"main": "index.js",
|
|
19
23
|
"exports": {
|
|
@@ -68,6 +72,7 @@
|
|
|
68
72
|
"devDependencies": {
|
|
69
73
|
"@emnapi/core": "^1.7.1",
|
|
70
74
|
"@emnapi/runtime": "^1.7.1",
|
|
75
|
+
"@napi-rs/canvas": "^0.1.84",
|
|
71
76
|
"@napi-rs/cli": "^3.5.0",
|
|
72
77
|
"@napi-rs/wasm-runtime": "^1.1.0",
|
|
73
78
|
"@oxc-node/core": "^0.0.35",
|
|
@@ -88,6 +93,14 @@
|
|
|
88
93
|
"tinybench": "^6.0.0",
|
|
89
94
|
"typescript": "^5.9.3"
|
|
90
95
|
},
|
|
96
|
+
"peerDependencies": {
|
|
97
|
+
"@napi-rs/canvas": ">=0.1.0"
|
|
98
|
+
},
|
|
99
|
+
"peerDependenciesMeta": {
|
|
100
|
+
"@napi-rs/canvas": {
|
|
101
|
+
"optional": true
|
|
102
|
+
}
|
|
103
|
+
},
|
|
91
104
|
"napi": {
|
|
92
105
|
"binaryName": "webcodecs",
|
|
93
106
|
"constEnum": false,
|
|
@@ -137,14 +150,14 @@
|
|
|
137
150
|
"registry": "https://registry.npmjs.org/"
|
|
138
151
|
},
|
|
139
152
|
"optionalDependencies": {
|
|
140
|
-
"@napi-rs/webcodecs-darwin-x64": "
|
|
141
|
-
"@napi-rs/webcodecs-darwin-arm64": "
|
|
142
|
-
"@napi-rs/webcodecs-linux-x64-gnu": "
|
|
143
|
-
"@napi-rs/webcodecs-linux-x64-musl": "
|
|
144
|
-
"@napi-rs/webcodecs-win32-x64-msvc": "
|
|
145
|
-
"@napi-rs/webcodecs-linux-arm64-gnu": "
|
|
146
|
-
"@napi-rs/webcodecs-linux-arm64-musl": "
|
|
147
|
-
"@napi-rs/webcodecs-win32-arm64-msvc": "
|
|
148
|
-
"@napi-rs/webcodecs-linux-arm-gnueabihf": "
|
|
153
|
+
"@napi-rs/webcodecs-darwin-x64": "1.0.0",
|
|
154
|
+
"@napi-rs/webcodecs-darwin-arm64": "1.0.0",
|
|
155
|
+
"@napi-rs/webcodecs-linux-x64-gnu": "1.0.0",
|
|
156
|
+
"@napi-rs/webcodecs-linux-x64-musl": "1.0.0",
|
|
157
|
+
"@napi-rs/webcodecs-win32-x64-msvc": "1.0.0",
|
|
158
|
+
"@napi-rs/webcodecs-linux-arm64-gnu": "1.0.0",
|
|
159
|
+
"@napi-rs/webcodecs-linux-arm64-musl": "1.0.0",
|
|
160
|
+
"@napi-rs/webcodecs-win32-arm64-msvc": "1.0.0",
|
|
161
|
+
"@napi-rs/webcodecs-linux-arm-gnueabihf": "1.0.0"
|
|
149
162
|
}
|
|
150
163
|
}
|
package/standard.d.ts
CHANGED
|
@@ -296,6 +296,28 @@ export type VideoPixelFormat =
|
|
|
296
296
|
| 'BGRA'
|
|
297
297
|
| 'BGRX'
|
|
298
298
|
|
|
299
|
+
/**
|
|
300
|
+
* Layout information for a single plane
|
|
301
|
+
* @see https://w3c.github.io/webcodecs/#dictdef-planelayout
|
|
302
|
+
*/
|
|
303
|
+
export interface PlaneLayout {
|
|
304
|
+
/** Byte offset from the start of the buffer to the start of the plane */
|
|
305
|
+
offset: number
|
|
306
|
+
/** Number of bytes per row (stride) */
|
|
307
|
+
stride: number
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* DOMRectInit for specifying regions
|
|
312
|
+
* @see https://drafts.fxtf.org/geometry/#dictdef-domrectinit
|
|
313
|
+
*/
|
|
314
|
+
export interface DOMRectInit {
|
|
315
|
+
x?: number
|
|
316
|
+
y?: number
|
|
317
|
+
width?: number
|
|
318
|
+
height?: number
|
|
319
|
+
}
|
|
320
|
+
|
|
299
321
|
/**
|
|
300
322
|
* VideoFrame buffer init
|
|
301
323
|
* @see https://w3c.github.io/webcodecs/#dictdef-videoframebufferinit
|
|
@@ -311,6 +333,10 @@ export interface VideoFrameBufferInit {
|
|
|
311
333
|
timestamp: number
|
|
312
334
|
/** Duration in microseconds */
|
|
313
335
|
duration?: number
|
|
336
|
+
/** Layout for input planes (offset and stride per plane) */
|
|
337
|
+
layout?: PlaneLayout[]
|
|
338
|
+
/** Visible rect within the coded frame */
|
|
339
|
+
visibleRect?: DOMRectInit
|
|
314
340
|
/** Display width */
|
|
315
341
|
displayWidth?: number
|
|
316
342
|
/** Display height */
|