webcodecs-node 0.5.1 → 0.5.2
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 +64 -184
- package/docs/api.md +1 -1
- package/docs/configuration.md +6 -17
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# webcodecs-node
|
|
2
2
|
|
|
3
|
-
WebCodecs API implementation for Node.js using
|
|
3
|
+
WebCodecs API implementation for Node.js using node-av.
|
|
4
4
|
|
|
5
5
|
This package provides a Node.js-compatible implementation of the [WebCodecs API](https://developer.mozilla.org/en-US/docs/Web/API/WebCodecs_API), enabling video and audio encoding/decoding in server-side JavaScript applications.
|
|
6
6
|
|
|
@@ -16,7 +16,7 @@ This package provides a Node.js-compatible implementation of the [WebCodecs API]
|
|
|
16
16
|
- **Latency Modes** - Configure for real-time streaming vs maximum compression
|
|
17
17
|
- **Bitrate Modes** - Constant, variable, and quantizer (CRF) encoding modes
|
|
18
18
|
- **Alpha Channel** - Preserve transparency with VP9 and AV1 codecs
|
|
19
|
-
- **
|
|
19
|
+
- **Container Support** - MP4, WebM demuxing/muxing utilities
|
|
20
20
|
|
|
21
21
|
## Documentation
|
|
22
22
|
|
|
@@ -28,17 +28,11 @@ This package provides a Node.js-compatible implementation of the [WebCodecs API]
|
|
|
28
28
|
## Requirements
|
|
29
29
|
|
|
30
30
|
- Node.js 18+
|
|
31
|
-
-
|
|
31
|
+
- The `node-av` package (automatically installed as a dependency)
|
|
32
32
|
|
|
33
33
|
```bash
|
|
34
|
-
#
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
# macOS
|
|
38
|
-
brew install ffmpeg
|
|
39
|
-
|
|
40
|
-
# Check installation
|
|
41
|
-
ffmpeg -version
|
|
34
|
+
# node-av provides native FFmpeg bindings - no separate FFmpeg installation required
|
|
35
|
+
npm install webcodecs-node
|
|
42
36
|
```
|
|
43
37
|
|
|
44
38
|
## Installation
|
|
@@ -67,7 +61,7 @@ const encoder = new VideoEncoder({
|
|
|
67
61
|
error: (e) => console.error(e),
|
|
68
62
|
});
|
|
69
63
|
|
|
70
|
-
|
|
64
|
+
encoder.configure({
|
|
71
65
|
codec: 'avc1.42001E', // H.264 Baseline
|
|
72
66
|
width: 1280,
|
|
73
67
|
height: 720,
|
|
@@ -100,12 +94,12 @@ Encodes raw video frames to compressed video.
|
|
|
100
94
|
const encoder = new VideoEncoder({
|
|
101
95
|
output: (chunk, metadata) => {
|
|
102
96
|
// chunk is EncodedVideoChunk
|
|
103
|
-
// metadata contains
|
|
97
|
+
// metadata contains decoder config info
|
|
104
98
|
},
|
|
105
99
|
error: (e) => console.error(e),
|
|
106
100
|
});
|
|
107
101
|
|
|
108
|
-
|
|
102
|
+
encoder.configure({
|
|
109
103
|
codec: 'avc1.42001E', // H.264
|
|
110
104
|
width: 1920,
|
|
111
105
|
height: 1080,
|
|
@@ -114,7 +108,6 @@ await encoder.configure({
|
|
|
114
108
|
bitrateMode: 'variable', // Optional: 'constant', 'variable', or 'quantizer'
|
|
115
109
|
latencyMode: 'realtime', // Optional: 'realtime' for streaming, 'quality' for best compression
|
|
116
110
|
hardwareAcceleration: 'prefer-hardware', // Optional: use GPU encoding
|
|
117
|
-
format: 'mp4', // Optional: 'annexb' (default) or 'mp4'
|
|
118
111
|
});
|
|
119
112
|
|
|
120
113
|
// Create a frame from raw RGBA data
|
|
@@ -153,7 +146,7 @@ const decoder = new VideoDecoder({
|
|
|
153
146
|
error: (e) => console.error(e),
|
|
154
147
|
});
|
|
155
148
|
|
|
156
|
-
|
|
149
|
+
decoder.configure({
|
|
157
150
|
codec: 'avc1.42001E',
|
|
158
151
|
codedWidth: 1920,
|
|
159
152
|
codedHeight: 1080,
|
|
@@ -177,12 +170,11 @@ const encoder = new AudioEncoder({
|
|
|
177
170
|
error: (e) => console.error(e),
|
|
178
171
|
});
|
|
179
172
|
|
|
180
|
-
|
|
173
|
+
encoder.configure({
|
|
181
174
|
codec: 'opus',
|
|
182
175
|
sampleRate: 48000,
|
|
183
176
|
numberOfChannels: 2,
|
|
184
177
|
bitrate: 128000,
|
|
185
|
-
format: 'aac', // Optional: 'adts' (default for AAC) or 'aac'
|
|
186
178
|
});
|
|
187
179
|
|
|
188
180
|
// Create audio data from raw samples
|
|
@@ -221,8 +213,6 @@ const imageData = readFileSync('animation.gif');
|
|
|
221
213
|
const decoder = new ImageDecoder({
|
|
222
214
|
type: 'image/gif',
|
|
223
215
|
data: imageData,
|
|
224
|
-
// Optional: transfer ownership for zero-copy
|
|
225
|
-
// transfer: [imageData.buffer],
|
|
226
216
|
});
|
|
227
217
|
|
|
228
218
|
// Wait for parsing to complete
|
|
@@ -247,21 +237,6 @@ for (let i = 0; i < track.frameCount; i++) {
|
|
|
247
237
|
decoder.close();
|
|
248
238
|
```
|
|
249
239
|
|
|
250
|
-
**Constructor options:**
|
|
251
|
-
- `type` - MIME type (required)
|
|
252
|
-
- `data` - ArrayBuffer, TypedArray, or ReadableStream (required)
|
|
253
|
-
- `transfer` - ArrayBuffer[] for zero-copy ownership
|
|
254
|
-
- `colorSpaceConversion` - 'none' | 'default'
|
|
255
|
-
- `desiredWidth` / `desiredHeight` - Target dimensions
|
|
256
|
-
- `preferAnimation` - Prefer animated track if available
|
|
257
|
-
- `premultiplyAlpha` - 'none' | 'premultiply' | 'default'
|
|
258
|
-
|
|
259
|
-
**Properties:**
|
|
260
|
-
- `type` - MIME type string
|
|
261
|
-
- `complete` - Boolean, true when data is buffered
|
|
262
|
-
- `completed` - Promise that resolves when ready
|
|
263
|
-
- `tracks` - ImageTrackList with track information
|
|
264
|
-
|
|
265
240
|
**Supported formats:**
|
|
266
241
|
- `image/png`, `image/apng`
|
|
267
242
|
- `image/jpeg`
|
|
@@ -317,35 +292,6 @@ if (encodeInfo.supported && encodeInfo.powerEfficient) {
|
|
|
317
292
|
}
|
|
318
293
|
```
|
|
319
294
|
|
|
320
|
-
**Supported containers & codecs:**
|
|
321
|
-
| Container | Video Codecs | Audio Codecs |
|
|
322
|
-
|-----------|-------------|--------------|
|
|
323
|
-
| video/mp4 | H.264, HEVC, AV1 | AAC |
|
|
324
|
-
| video/webm | VP8, VP9, AV1 | Opus, Vorbis |
|
|
325
|
-
| audio/mp4 | - | AAC |
|
|
326
|
-
| audio/webm | - | Opus, Vorbis |
|
|
327
|
-
| audio/ogg | - | Opus, Vorbis, FLAC |
|
|
328
|
-
| audio/mpeg | - | MP3 |
|
|
329
|
-
|
|
330
|
-
**Result properties:**
|
|
331
|
-
- `supported` - Whether the configuration can be decoded/encoded
|
|
332
|
-
- `smooth` - Whether playback/encoding will be smooth (no dropped frames)
|
|
333
|
-
- `powerEfficient` - Whether hardware acceleration is available
|
|
334
|
-
|
|
335
|
-
### MediaCapabilities Profiles
|
|
336
|
-
|
|
337
|
-
By default, capability queries use heuristics (resolution, bitrate, detected hardware). You can provide a detailed profile generated from the local FFmpeg installation:
|
|
338
|
-
|
|
339
|
-
```bash
|
|
340
|
-
# Generate a JSON profile alongside the repo (builds first)
|
|
341
|
-
npm run capabilities:generate -- ./webcodecs-capabilities.json
|
|
342
|
-
|
|
343
|
-
# Point WebCodecs at the profile
|
|
344
|
-
export WEBCODECS_CAPABILITIES_PROFILE=$(pwd)/webcodecs-capabilities.json
|
|
345
|
-
```
|
|
346
|
-
|
|
347
|
-
`decodingInfo` / `encodingInfo` will load that JSON (schema: `{ video: CapabilityProfileEntry[]; audio: CapabilityProfileEntry[] }`) and match codec/profile/level against those entries for precise limits. Without the env var the library falls back to its built-in heuristics.
|
|
348
|
-
|
|
349
295
|
### Hardware Acceleration
|
|
350
296
|
|
|
351
297
|
Detect and use hardware encoding/decoding:
|
|
@@ -372,7 +318,7 @@ const best = await getBestEncoder('h264', 'prefer-hardware');
|
|
|
372
318
|
console.log(`Using: ${best.encoder} (hardware: ${best.isHardware})`);
|
|
373
319
|
|
|
374
320
|
// Use in VideoEncoder config
|
|
375
|
-
|
|
321
|
+
encoder.configure({
|
|
376
322
|
codec: 'avc1.42001E',
|
|
377
323
|
width: 1920,
|
|
378
324
|
height: 1080,
|
|
@@ -385,23 +331,38 @@ await encoder.configure({
|
|
|
385
331
|
- **VAAPI** - Intel/AMD on Linux
|
|
386
332
|
- **NVENC/NVDEC** - NVIDIA GPUs
|
|
387
333
|
- **QSV** - Intel Quick Sync Video
|
|
388
|
-
- **VideoToolbox** - macOS
|
|
334
|
+
- **VideoToolbox** - macOS
|
|
389
335
|
|
|
390
|
-
###
|
|
336
|
+
### Container Utilities
|
|
391
337
|
|
|
392
|
-
|
|
338
|
+
Import container demuxing/muxing utilities for working with MP4 and WebM files:
|
|
393
339
|
|
|
394
340
|
```typescript
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
341
|
+
import { Mp4Demuxer, WebmMuxer } from 'webcodecs-node/containers';
|
|
342
|
+
|
|
343
|
+
// Demux an MP4 file
|
|
344
|
+
const demuxer = new Mp4Demuxer(mp4Data);
|
|
345
|
+
await demuxer.initialize();
|
|
346
|
+
|
|
347
|
+
for await (const sample of demuxer.videoSamples()) {
|
|
348
|
+
// sample contains encoded video chunks
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// Mux encoded chunks to WebM
|
|
352
|
+
const muxer = new WebmMuxer({
|
|
353
|
+
video: { codec: 'vp9', width: 1920, height: 1080 },
|
|
402
354
|
});
|
|
403
355
|
|
|
404
|
-
|
|
356
|
+
muxer.addVideoChunk(encodedChunk, metadata);
|
|
357
|
+
const webmData = muxer.finalize();
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### Streaming & Latency Modes
|
|
361
|
+
|
|
362
|
+
For real-time streaming applications, use `latencyMode: 'realtime'` to minimize encoding latency:
|
|
363
|
+
|
|
364
|
+
```typescript
|
|
365
|
+
encoder.configure({
|
|
405
366
|
codec: 'avc1.42001E',
|
|
406
367
|
width: 1280,
|
|
407
368
|
height: 720,
|
|
@@ -409,40 +370,18 @@ await encoder.configure({
|
|
|
409
370
|
framerate: 30,
|
|
410
371
|
latencyMode: 'realtime', // Prioritize low latency
|
|
411
372
|
});
|
|
412
|
-
|
|
413
|
-
// Process frames as they arrive
|
|
414
|
-
camera.on('frame', (frameData) => {
|
|
415
|
-
const frame = new VideoFrame(frameData, {
|
|
416
|
-
format: 'RGBA',
|
|
417
|
-
codedWidth: 1280,
|
|
418
|
-
codedHeight: 720,
|
|
419
|
-
timestamp: Date.now() * 1000,
|
|
420
|
-
});
|
|
421
|
-
|
|
422
|
-
encoder.encode(frame);
|
|
423
|
-
frame.close();
|
|
424
|
-
});
|
|
425
373
|
```
|
|
426
374
|
|
|
427
375
|
**Latency mode options:**
|
|
428
376
|
- `'quality'` (default) - Best compression, higher latency (uses B-frames, lookahead)
|
|
429
377
|
- `'realtime'` - Minimum latency for live streaming (no B-frames, zero-delay)
|
|
430
378
|
|
|
431
|
-
**Codec-specific optimizations in realtime mode:**
|
|
432
|
-
| Codec | Quality Mode | Realtime Mode |
|
|
433
|
-
|-------|-------------|---------------|
|
|
434
|
-
| H.264 | B-frames, rc-lookahead | zerolatency tune, no B-frames |
|
|
435
|
-
| H.265 | B-frames, lookahead | zerolatency tune, no B-frames |
|
|
436
|
-
| VP8 | Default settings | deadline=realtime, cpu-used=8 |
|
|
437
|
-
| VP9 | row-mt, tile-columns | deadline=realtime, cpu-used=8 |
|
|
438
|
-
| AV1 | Default settings | usage=realtime, cpu-used=8 |
|
|
439
|
-
|
|
440
379
|
### Bitrate Modes
|
|
441
380
|
|
|
442
381
|
Control how bitrate is managed during encoding:
|
|
443
382
|
|
|
444
383
|
```typescript
|
|
445
|
-
|
|
384
|
+
encoder.configure({
|
|
446
385
|
codec: 'avc1.42001E',
|
|
447
386
|
width: 1920,
|
|
448
387
|
height: 1080,
|
|
@@ -451,7 +390,6 @@ await encoder.configure({
|
|
|
451
390
|
});
|
|
452
391
|
```
|
|
453
392
|
|
|
454
|
-
**Bitrate mode options:**
|
|
455
393
|
| Mode | Description | Use Case |
|
|
456
394
|
|------|-------------|----------|
|
|
457
395
|
| `'variable'` | VBR - varies bitrate for quality (default) | General purpose |
|
|
@@ -463,8 +401,7 @@ await encoder.configure({
|
|
|
463
401
|
Preserve transparency when encoding with VP9 or AV1:
|
|
464
402
|
|
|
465
403
|
```typescript
|
|
466
|
-
|
|
467
|
-
await encoder.configure({
|
|
404
|
+
encoder.configure({
|
|
468
405
|
codec: 'vp9',
|
|
469
406
|
width: 1920,
|
|
470
407
|
height: 1080,
|
|
@@ -482,72 +419,6 @@ const frame = new VideoFrame(rgbaWithAlpha, {
|
|
|
482
419
|
encoder.encode(frame);
|
|
483
420
|
```
|
|
484
421
|
|
|
485
|
-
**Alpha options:**
|
|
486
|
-
- `'discard'` (default) - Strip alpha channel (works with all codecs)
|
|
487
|
-
- `'keep'` - Preserve transparency (VP9 and AV1 only)
|
|
488
|
-
|
|
489
|
-
## Mediabunny Integration
|
|
490
|
-
|
|
491
|
-
For file-to-file conversion, use with [Mediabunny](https://mediabunny.dev):
|
|
492
|
-
|
|
493
|
-
```typescript
|
|
494
|
-
import { ReadableStream, WritableStream, TransformStream } from 'stream/web';
|
|
495
|
-
import { installWebCodecsPolyfill } from 'webcodecs-node';
|
|
496
|
-
|
|
497
|
-
// Polyfill Web Streams
|
|
498
|
-
if (typeof globalThis.WritableStream === 'undefined') {
|
|
499
|
-
globalThis.WritableStream = WritableStream;
|
|
500
|
-
}
|
|
501
|
-
if (typeof globalThis.ReadableStream === 'undefined') {
|
|
502
|
-
globalThis.ReadableStream = ReadableStream;
|
|
503
|
-
}
|
|
504
|
-
if (typeof globalThis.TransformStream === 'undefined') {
|
|
505
|
-
globalThis.TransformStream = TransformStream;
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
// Install WebCodecs
|
|
509
|
-
installWebCodecsPolyfill();
|
|
510
|
-
|
|
511
|
-
import {
|
|
512
|
-
Input,
|
|
513
|
-
Output,
|
|
514
|
-
Conversion,
|
|
515
|
-
FilePathSource,
|
|
516
|
-
FilePathTarget,
|
|
517
|
-
Mp4OutputFormat,
|
|
518
|
-
ALL_FORMATS,
|
|
519
|
-
registerEncoder,
|
|
520
|
-
registerDecoder,
|
|
521
|
-
} from 'mediabunny';
|
|
522
|
-
|
|
523
|
-
import { FFmpegVideoEncoder } from 'webcodecs-node/mediabunny/FFmpegVideoEncoder';
|
|
524
|
-
import { FFmpegVideoDecoder } from 'webcodecs-node/mediabunny/FFmpegVideoDecoder';
|
|
525
|
-
import { FFmpegAudioEncoder } from 'webcodecs-node/mediabunny/FFmpegAudioEncoder';
|
|
526
|
-
import { FFmpegAudioDecoder } from 'webcodecs-node/mediabunny/FFmpegAudioDecoder';
|
|
527
|
-
|
|
528
|
-
// Register FFmpeg-backed encoders/decoders
|
|
529
|
-
registerEncoder(FFmpegVideoEncoder);
|
|
530
|
-
registerEncoder(FFmpegAudioEncoder);
|
|
531
|
-
registerDecoder(FFmpegVideoDecoder);
|
|
532
|
-
registerDecoder(FFmpegAudioDecoder);
|
|
533
|
-
|
|
534
|
-
// Convert video
|
|
535
|
-
const input = new Input({
|
|
536
|
-
formats: ALL_FORMATS,
|
|
537
|
-
source: new FilePathSource('input.mkv'),
|
|
538
|
-
});
|
|
539
|
-
|
|
540
|
-
const output = new Output({
|
|
541
|
-
format: new Mp4OutputFormat(),
|
|
542
|
-
target: new FilePathTarget('output.mp4'),
|
|
543
|
-
});
|
|
544
|
-
|
|
545
|
-
const conversion = await Conversion.init({ input, output });
|
|
546
|
-
await conversion.execute();
|
|
547
|
-
|
|
548
|
-
console.log('Conversion complete!');
|
|
549
|
-
```
|
|
550
|
-
|
|
551
422
|
## Demos
|
|
552
423
|
|
|
553
424
|
Run the included demos to test functionality:
|
|
@@ -555,27 +426,32 @@ Run the included demos to test functionality:
|
|
|
555
426
|
```bash
|
|
556
427
|
npm run build
|
|
557
428
|
|
|
558
|
-
# Basic
|
|
429
|
+
# Basic demo
|
|
430
|
+
npm run demo
|
|
431
|
+
|
|
432
|
+
# WebCodecs API demo
|
|
559
433
|
npm run demo:webcodecs
|
|
560
434
|
|
|
561
435
|
# Image decoding demo (animated GIF/PNG/WebP with frame timing)
|
|
562
436
|
npm run demo:image
|
|
563
437
|
|
|
564
|
-
# Streaming demo (real-time encoding with latency comparison)
|
|
565
|
-
npm run demo:streaming
|
|
566
|
-
|
|
567
|
-
# File conversion with Mediabunny
|
|
568
|
-
npm run demo:conversion
|
|
569
|
-
|
|
570
438
|
# Hardware acceleration detection
|
|
571
439
|
npm run demo:hwaccel
|
|
572
440
|
|
|
573
|
-
#
|
|
574
|
-
npm run demo:
|
|
441
|
+
# Streaming demo (real-time encoding)
|
|
442
|
+
npm run demo:streaming
|
|
443
|
+
|
|
444
|
+
# Sample-based encoding demo
|
|
445
|
+
npm run demo:samples
|
|
446
|
+
|
|
447
|
+
# Container demuxing/muxing demo
|
|
448
|
+
npm run demo:containers
|
|
575
449
|
|
|
576
|
-
# Video quadrant compositor demo (
|
|
577
|
-
# Requires Node 20+; set hardwareAcceleration in src/demos/demo-four-corners.ts to 'prefer-hardware' if VAAPI/NVENC/QSV are available
|
|
450
|
+
# Video quadrant compositor demo (four-up render)
|
|
578
451
|
npm run demo:fourcorners
|
|
452
|
+
|
|
453
|
+
# 1080p transcoding demo
|
|
454
|
+
npm run demo:1080p
|
|
579
455
|
```
|
|
580
456
|
|
|
581
457
|
## API Compatibility
|
|
@@ -600,12 +476,16 @@ This implementation follows the [WebCodecs specification](https://www.w3.org/TR/
|
|
|
600
476
|
| bitrateMode | ✓ | ✓ |
|
|
601
477
|
| alpha (transparency) | ✓ | ✓ (VP9, AV1) |
|
|
602
478
|
| isConfigSupported() | ✓ | ✓ |
|
|
603
|
-
| isTypeSupported() | ✓ | ✓ |
|
|
604
479
|
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
-
|
|
480
|
+
## Architecture
|
|
481
|
+
|
|
482
|
+
This library uses **node-av** as its backend, which provides native bindings to FFmpeg's libav* libraries. This approach offers:
|
|
483
|
+
|
|
484
|
+
- **Native performance** - Direct library calls instead of subprocess spawning
|
|
485
|
+
- **Lower latency** - No IPC overhead between Node.js and FFmpeg
|
|
486
|
+
- **Better resource management** - Native memory handling and cleanup
|
|
487
|
+
- **Simplified deployment** - No need for separate FFmpeg installation
|
|
608
488
|
|
|
609
489
|
## License
|
|
610
490
|
|
|
611
|
-
webcodecs-node is distributed under the GNU Affero General Public License v3.0.
|
|
491
|
+
webcodecs-node is distributed under the GNU Affero General Public License v3.0. See `LICENSE` for full terms.
|
package/docs/api.md
CHANGED
|
@@ -496,7 +496,7 @@ const info = await mediaCapabilities.encodingInfo({
|
|
|
496
496
|
|
|
497
497
|
### Capability Profiles
|
|
498
498
|
|
|
499
|
-
You can generate a hardware-specific capability profile to make `mediaCapabilities` match your actual
|
|
499
|
+
You can generate a hardware-specific capability profile to make `mediaCapabilities` match your actual system capabilities. Use the provided CLI:
|
|
500
500
|
|
|
501
501
|
```bash
|
|
502
502
|
npm run capabilities:generate -- ./webcodecs-capabilities.json
|
package/docs/configuration.md
CHANGED
|
@@ -93,17 +93,6 @@ encoder.configure({
|
|
|
93
93
|
- Unpredictable file size
|
|
94
94
|
- Not suitable for streaming
|
|
95
95
|
|
|
96
|
-
### Codec-Specific Implementation
|
|
97
|
-
|
|
98
|
-
Different codecs use different parameters for each bitrate mode:
|
|
99
|
-
|
|
100
|
-
| Codec | CBR | VBR | Quantizer |
|
|
101
|
-
|-------|-----|-----|-----------|
|
|
102
|
-
| H.264 | `-b:v` + `maxrate`/`bufsize`, CBR mode | `-b:v` only | `-crf 23` |
|
|
103
|
-
| H.265 | `-b:v` + `maxrate`/`bufsize`, CBR mode | `-b:v` only | `-crf 28` |
|
|
104
|
-
| VP8/VP9 | `-b:v` + `minrate`/`maxrate` | `-b:v` only | `-crf 31` + `-b:v 0` |
|
|
105
|
-
| AV1 | `-b:v` + `maxrate`/`bufsize` | `-b:v` only | `-crf 30` |
|
|
106
|
-
|
|
107
96
|
---
|
|
108
97
|
|
|
109
98
|
## Alpha Channel Handling
|
|
@@ -131,7 +120,7 @@ The `alpha` option controls how transparent pixels are handled during encoding.
|
|
|
131
120
|
|
|
132
121
|
## Output Bitstream Format
|
|
133
122
|
|
|
134
|
-
By default the encoders emit Annex B (video) and ADTS/OGG (audio)
|
|
123
|
+
By default the encoders emit Annex B (video) and ADTS/OGG (audio) bitstreams. If you need MP4-style payloads (length-prefixed NAL units, raw AAC frames) you can opt-in via the `format` config field.
|
|
135
124
|
|
|
136
125
|
### VideoEncoder `format`
|
|
137
126
|
|
|
@@ -266,11 +255,11 @@ encoder.configure({
|
|
|
266
255
|
|
|
267
256
|
| Codec | Quality Mode | Realtime Mode |
|
|
268
257
|
|-------|--------------|---------------|
|
|
269
|
-
| H.264 |
|
|
270
|
-
| H.265 | Default settings |
|
|
271
|
-
| VP8 | Default |
|
|
272
|
-
| VP9 | Row multithreading, tile columns |
|
|
273
|
-
| AV1 | Default |
|
|
258
|
+
| H.264 | B-frames, lookahead enabled | Zero-latency tuning, no B-frames |
|
|
259
|
+
| H.265 | Default settings | Zero-latency tuning, no B-frames |
|
|
260
|
+
| VP8 | Default | Realtime deadline, fast encoding |
|
|
261
|
+
| VP9 | Row multithreading, tile columns | Realtime deadline, fast encoding |
|
|
262
|
+
| AV1 | Default | Realtime usage, fast encoding |
|
|
274
263
|
|
|
275
264
|
**Example for live streaming:**
|
|
276
265
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "webcodecs-node",
|
|
3
|
-
"version": "0.5.
|
|
4
|
-
"description": "WebCodecs API implementation for Node.js using
|
|
3
|
+
"version": "0.5.2",
|
|
4
|
+
"description": "WebCodecs API implementation for Node.js using node-av",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"type": "module",
|