node-av 5.0.4 → 5.2.0-beta.1
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/BENCHMARK.md +113 -0
- package/README.md +42 -0
- package/dist/api/bitstream-filter.d.ts +190 -74
- package/dist/api/bitstream-filter.js +276 -222
- package/dist/api/bitstream-filter.js.map +1 -1
- package/dist/api/decoder.d.ts +23 -29
- package/dist/api/decoder.js +37 -47
- package/dist/api/decoder.js.map +1 -1
- package/dist/api/encoder.d.ts +4 -4
- package/dist/api/encoder.js +16 -20
- package/dist/api/encoder.js.map +1 -1
- package/dist/api/filter-complex.js +7 -3
- package/dist/api/filter-complex.js.map +1 -1
- package/dist/api/filter.d.ts +4 -4
- package/dist/api/filter.js +18 -16
- package/dist/api/filter.js.map +1 -1
- package/dist/api/hardware.d.ts +17 -0
- package/dist/api/hardware.js +70 -23
- package/dist/api/hardware.js.map +1 -1
- package/dist/api/muxer.js +8 -4
- package/dist/api/muxer.js.map +1 -1
- package/dist/api/rtp-stream.js +0 -6
- package/dist/api/rtp-stream.js.map +1 -1
- package/dist/api/types.d.ts +29 -9
- package/dist/constants/constants.d.ts +6 -3
- package/dist/constants/constants.js +5 -5
- package/dist/constants/constants.js.map +1 -1
- package/dist/lib/codec-context.d.ts +5 -3
- package/dist/lib/codec-context.js +2 -0
- package/dist/lib/codec-context.js.map +1 -1
- package/dist/lib/native-types.d.ts +2 -2
- package/package.json +18 -13
- package/binding.gyp +0 -166
package/BENCHMARK.md
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# node-av Benchmark Results
|
|
2
|
+
|
|
3
|
+
> Generated: 2026-01-27T18:12:31.045Z
|
|
4
|
+
|
|
5
|
+
## System Information
|
|
6
|
+
|
|
7
|
+
| Property | Value |
|
|
8
|
+
|----------|-------|
|
|
9
|
+
| **OS** | darwin 25.1.0 |
|
|
10
|
+
| **Architecture** | arm64 |
|
|
11
|
+
| **CPU** | Apple M3 Max |
|
|
12
|
+
| **CPU Cores** | 16 |
|
|
13
|
+
| **RAM** | 48.0 GB |
|
|
14
|
+
| **GPU** | Apple M3 Max |
|
|
15
|
+
| **Node.js** | v24.8.0 |
|
|
16
|
+
| **FFmpeg** | 8.0-Jellyfin |
|
|
17
|
+
| **node-av** | 5.0.4 |
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
## Test Inputs
|
|
21
|
+
|
|
22
|
+
| File | Codec | Resolution | FPS | Duration |
|
|
23
|
+
|------|-------|------------|-----|----------|
|
|
24
|
+
| bbb-4k-av1.mp4 | av1 | 3840x2160 | 60 | 30.0s |
|
|
25
|
+
| bbb-4k-h264.mp4 | h264 | 3840x2160 | 60 | 30.0s |
|
|
26
|
+
| bbb-4k-hevc.mp4 | hevc | 3840x2160 | 60 | 30.0s |
|
|
27
|
+
| bbb-4k-vp9.webm | vp9 | 3840x2160 | 60 | 30.0s |
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
## Transcode Speed
|
|
31
|
+
|
|
32
|
+
### Input: bbb-4k-av1.mp4
|
|
33
|
+
|
|
34
|
+
| Test | FFmpeg CLI (FPS) | node-av (FPS) | FFmpeg CLI (Time) | node-av (Time) | Diff |
|
|
35
|
+
|------|------------------|---------------|-------------------|----------------|------|
|
|
36
|
+
| SW H.264 Transcode | 95.1 fps | 94.5 fps | 18.93s | 19.06s | -0.6% |
|
|
37
|
+
| SW H.265 Transcode | 38.9 fps | 40.1 fps | 46.31s | 44.93s | +3.2% |
|
|
38
|
+
| HW H.264 Transcode | 54.6 fps | 54.9 fps | 32.98s | 32.79s | +0.6% |
|
|
39
|
+
| Stream Copy (Remux) | 50307.7 fps | 29472.5 fps | 36ms | 109ms | -41.4% |
|
|
40
|
+
|
|
41
|
+
### Input: bbb-4k-h264.mp4
|
|
42
|
+
|
|
43
|
+
| Test | FFmpeg CLI (FPS) | node-av (FPS) | FFmpeg CLI (Time) | node-av (Time) | Diff |
|
|
44
|
+
|------|------------------|---------------|-------------------|----------------|------|
|
|
45
|
+
| SW H.264 Transcode | 96.5 fps | 97.2 fps | 18.65s | 18.52s | +0.7% |
|
|
46
|
+
| SW H.265 Transcode | 40.0 fps | 39.9 fps | 45.00s | 45.12s | -0.2% |
|
|
47
|
+
| HW H.264 Transcode | 54.6 fps | 54.9 fps | 32.98s | 32.83s | +0.5% |
|
|
48
|
+
| Stream Copy (Remux) | 38235.1 fps | 30884.8 fps | 48ms | 104ms | -19.2% |
|
|
49
|
+
|
|
50
|
+
### Input: bbb-4k-hevc.mp4
|
|
51
|
+
|
|
52
|
+
| Test | FFmpeg CLI (FPS) | node-av (FPS) | FFmpeg CLI (Time) | node-av (Time) | Diff |
|
|
53
|
+
|------|------------------|---------------|-------------------|----------------|------|
|
|
54
|
+
| SW H.264 Transcode | 96.3 fps | 95.9 fps | 18.70s | 18.78s | -0.4% |
|
|
55
|
+
| SW H.265 Transcode | 41.4 fps | 41.8 fps | 43.49s | 43.06s | +1.0% |
|
|
56
|
+
| HW H.264 Transcode | 54.5 fps | 54.9 fps | 33.00s | 32.82s | +0.6% |
|
|
57
|
+
| Stream Copy (Remux) | 55110.3 fps | 30395.4 fps | 33ms | 106ms | -44.8% |
|
|
58
|
+
|
|
59
|
+
### Input: bbb-4k-vp9.webm
|
|
60
|
+
|
|
61
|
+
| Test | FFmpeg CLI (FPS) | node-av (FPS) | FFmpeg CLI (Time) | node-av (Time) | Diff |
|
|
62
|
+
|------|------------------|---------------|-------------------|----------------|------|
|
|
63
|
+
| SW H.264 Transcode | 96.5 fps | 96.1 fps | 18.66s | 18.75s | -0.4% |
|
|
64
|
+
| SW H.265 Transcode | 41.6 fps | 42.0 fps | 43.23s | 42.90s | +0.8% |
|
|
65
|
+
| HW H.264 Transcode | 54.6 fps | 54.8 fps | 32.98s | 32.85s | +0.4% |
|
|
66
|
+
| Stream Copy (Remux) | 48635.3 fps | 31617.3 fps | 37ms | 105ms | -35.0% |
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
## Memory Usage
|
|
70
|
+
|
|
71
|
+
### Input: bbb-4k-av1.mp4
|
|
72
|
+
|
|
73
|
+
| Test | FFmpeg CLI Peak | node-av Peak | Difference |
|
|
74
|
+
|------|----------------|--------------|------------|
|
|
75
|
+
| Memory: H.264 Transcode | 3.5 GB | 3.5 GB | -2.0% |
|
|
76
|
+
| Memory: Stream Copy | 19.9 MB | 1.1 MB | -94.6% |
|
|
77
|
+
|
|
78
|
+
### Input: bbb-4k-h264.mp4
|
|
79
|
+
|
|
80
|
+
| Test | FFmpeg CLI Peak | node-av Peak | Difference |
|
|
81
|
+
|------|----------------|--------------|------------|
|
|
82
|
+
| Memory: H.264 Transcode | 3.7 GB | 3.4 GB | -6.0% |
|
|
83
|
+
| Memory: Stream Copy | 40.7 MB | 1.9 MB | -95.2% |
|
|
84
|
+
|
|
85
|
+
### Input: bbb-4k-hevc.mp4
|
|
86
|
+
|
|
87
|
+
| Test | FFmpeg CLI Peak | node-av Peak | Difference |
|
|
88
|
+
|------|----------------|--------------|------------|
|
|
89
|
+
| Memory: H.264 Transcode | 3.8 GB | 3.5 GB | -5.4% |
|
|
90
|
+
| Memory: Stream Copy | 20.5 MB | 320.0 KB | -98.5% |
|
|
91
|
+
|
|
92
|
+
### Input: bbb-4k-vp9.webm
|
|
93
|
+
|
|
94
|
+
| Test | FFmpeg CLI Peak | node-av Peak | Difference |
|
|
95
|
+
|------|----------------|--------------|------------|
|
|
96
|
+
| Memory: H.264 Transcode | 3.5 GB | 3.3 GB | -4.7% |
|
|
97
|
+
| Memory: Stream Copy | 30.6 MB | 378.7 KB | -98.8% |
|
|
98
|
+
|
|
99
|
+
*Note: FFmpeg CLI memory is measured via `/usr/bin/time` (macOS: `-l`, Linux: `-v`).
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
## Latency
|
|
103
|
+
|
|
104
|
+
| Metric | Mean | Min | Max | StdDev |
|
|
105
|
+
|--------|------|-----|-----|--------|
|
|
106
|
+
| Demuxer Open | 466µs | 430µs | 561µs | 41µs |
|
|
107
|
+
| First Packet | 530µs | 491µs | 575µs | 30µs |
|
|
108
|
+
| First Frame | 11.7ms | 7.2ms | 15.2ms | 2.7ms |
|
|
109
|
+
| First Encoded Packet | 25.2ms | 23.9ms | 26.9ms | 856µs |
|
|
110
|
+
| Pipeline Total | 25.8ms | 22.5ms | 27.3ms | 1.4ms |
|
|
111
|
+
|
|
112
|
+
*Note: Each metric is measured independently. "First Encoded Packet" uses default encoder settings while "Pipeline Total" uses `tune=zerolatency` for low-latency output.*
|
|
113
|
+
|
package/README.md
CHANGED
|
@@ -35,6 +35,7 @@ Native Node.js bindings for FFmpeg with full TypeScript support. Provides direct
|
|
|
35
35
|
- [Resource Management](#resource-management)
|
|
36
36
|
- [FFmpeg Binary Access](#ffmpeg-binary-access)
|
|
37
37
|
- [Performance](#performance)
|
|
38
|
+
- [Benchmarks](#benchmarks)
|
|
38
39
|
- [Sync vs Async Operations](#sync-vs-async-operations)
|
|
39
40
|
- [Memory Safety Considerations](#memory-safety-considerations)
|
|
40
41
|
- [Examples](#examples)
|
|
@@ -426,6 +427,25 @@ The FFmpeg binary is automatically downloaded during installation from GitHub re
|
|
|
426
427
|
|
|
427
428
|
NodeAV executes all media operations directly through FFmpeg's native C libraries. The Node.js bindings add minimal overhead - mostly just the JavaScript-to-C boundary crossings. During typical operations like transcoding or filtering, most processing time is spent in FFmpeg's optimized C code.
|
|
428
429
|
|
|
430
|
+
### Benchmarks
|
|
431
|
+
|
|
432
|
+
Performance comparison with FFmpeg CLI (4K 60fps, 30s test files on Apple M3 Max):
|
|
433
|
+
|
|
434
|
+
| Operation | FFmpeg CLI (FPS) | node-av (FPS) | FFmpeg CLI (Time) | node-av (Time) | Diff |
|
|
435
|
+
|-----------|------------------|---------------|-------------------|----------------|------|
|
|
436
|
+
| SW H.264 Transcode | 96 fps | 96 fps | 18.7s | 18.7s | ≈0% |
|
|
437
|
+
| SW H.265 Transcode | 40 fps | 41 fps | 44.5s | 43.7s | **+1.5%** |
|
|
438
|
+
| HW H.264 Transcode | 55 fps | 55 fps | 33.0s | 32.8s | **+0.5%** |
|
|
439
|
+
| Stream Copy (Remux) | 48k fps | 31k fps | 38ms | 106ms | -35% |
|
|
440
|
+
|
|
441
|
+
**Memory Usage:**
|
|
442
|
+
| Operation | FFmpeg CLI | node-av | Difference |
|
|
443
|
+
|-----------|-----------|---------|------------|
|
|
444
|
+
| H.264 Transcode (4K) | 3.6 GB | 3.4 GB | **-5%** |
|
|
445
|
+
| Stream Copy | 28 MB | 1 MB | **-96%** |
|
|
446
|
+
|
|
447
|
+
📊 **[Full benchmark results](https://github.com/seydx/node-av/tree/main/BENCHMARK.md)**
|
|
448
|
+
|
|
429
449
|
### Sync vs Async Operations
|
|
430
450
|
|
|
431
451
|
Every async method in NodeAV has a corresponding synchronous variant with the `Sync` suffix:
|
|
@@ -473,6 +493,7 @@ NodeAV provides direct bindings to FFmpeg's C APIs, which work with raw memory p
|
|
|
473
493
|
| `api-whisper-transcribe` | | | [✓](https://github.com/seydx/node-av/tree/main/examples/api-whisper-transcribe.ts) |
|
|
474
494
|
| `frame-utils` | | [✓](https://github.com/seydx/node-av/tree/main/examples/frame-utils.ts) | |
|
|
475
495
|
| `avio-read-callback` | [✓](https://github.com/FFmpeg/FFmpeg/tree/master/doc/examples/avio_read_callback.c) | [✓](https://github.com/seydx/node-av/tree/main/examples/avio-read-callback.ts) | |
|
|
496
|
+
| `avio-async-read-callback` | | [✓](https://github.com/seydx/node-av/tree/main/examples/avio-async-read-callback.ts) | |
|
|
476
497
|
| `decode-audio` | [✓](https://github.com/FFmpeg/FFmpeg/tree/master/doc/examples/decode_audio.c) | [✓](https://github.com/seydx/node-av/tree/main/examples/decode-audio.ts) | |
|
|
477
498
|
| `decode-filter-audio` | [✓](https://github.com/FFmpeg/FFmpeg/tree/master/doc/examples/decode_filter_audio.c) | [✓](https://github.com/seydx/node-av/tree/main/examples/decode-filter-audio.ts) | |
|
|
478
499
|
| `decode-filter-video` | [✓](https://github.com/FFmpeg/FFmpeg/tree/master/doc/examples/decode_filter_video.c) | [✓](https://github.com/seydx/node-av/tree/main/examples/decode-filter-video.ts) | |
|
|
@@ -562,3 +583,24 @@ For issues and questions, please use the GitHub issue tracker.
|
|
|
562
583
|
- [FFmpeg Doxygen](https://ffmpeg.org/doxygen/trunk/)
|
|
563
584
|
- [Jellyfin FFmpeg](https://github.com/seydx/jellyfin-ffmpeg)
|
|
564
585
|
- [FFmpeg MSVC](https://github.com/seydx/ffmpeg-msvc-prebuilt)
|
|
586
|
+
|
|
587
|
+
## Star History
|
|
588
|
+
|
|
589
|
+
<picture>
|
|
590
|
+
<source
|
|
591
|
+
media="(prefers-color-scheme: dark)"
|
|
592
|
+
srcset="
|
|
593
|
+
https://api.star-history.com/svg?repos=seydx/node-av&type=Date&theme=dark
|
|
594
|
+
"
|
|
595
|
+
/>
|
|
596
|
+
<source
|
|
597
|
+
media="(prefers-color-scheme: light)"
|
|
598
|
+
srcset="
|
|
599
|
+
https://api.star-history.com/svg?repos=seydx/node-av&type=Date
|
|
600
|
+
"
|
|
601
|
+
/>
|
|
602
|
+
<img
|
|
603
|
+
alt="Star History Chart"
|
|
604
|
+
src="https://api.star-history.com/svg?repos=seydx/node-av&type=Date"
|
|
605
|
+
/>
|
|
606
|
+
</picture>
|
|
@@ -2,6 +2,7 @@ import { Packet } from '../lib/packet.js';
|
|
|
2
2
|
import { Muxer } from './muxer.js';
|
|
3
3
|
import { Scheduler, SchedulerControl } from './utilities/scheduler.js';
|
|
4
4
|
import type { Stream } from '../lib/stream.js';
|
|
5
|
+
import type { BitstreamFilterOptions } from './types.js';
|
|
5
6
|
/**
|
|
6
7
|
* High-level bitstream filter for packet processing.
|
|
7
8
|
*
|
|
@@ -74,6 +75,8 @@ export declare class BitStreamFilterAPI implements Disposable {
|
|
|
74
75
|
*
|
|
75
76
|
* @param stream - Stream to apply filter to
|
|
76
77
|
*
|
|
78
|
+
* @param filterOptions - Optional filter-specific options
|
|
79
|
+
*
|
|
77
80
|
* @returns Configured bitstream filter
|
|
78
81
|
*
|
|
79
82
|
* @throws {Error} If initialization fails
|
|
@@ -94,13 +97,24 @@ export declare class BitStreamFilterAPI implements Disposable {
|
|
|
94
97
|
*
|
|
95
98
|
* @example
|
|
96
99
|
* ```typescript
|
|
97
|
-
* // Remove
|
|
98
|
-
* const filter = BitStreamFilterAPI.create('
|
|
100
|
+
* // Remove AUDs from H.264 stream
|
|
101
|
+
* const filter = BitStreamFilterAPI.create('h264_metadata', stream, {
|
|
102
|
+
* options: { aud: 'remove' }
|
|
103
|
+
* });
|
|
104
|
+
* ```
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```typescript
|
|
108
|
+
* // Set H.264 level
|
|
109
|
+
* const filter = BitStreamFilterAPI.create('h264_metadata', stream, {
|
|
110
|
+
* options: { level: 51 }
|
|
111
|
+
* });
|
|
99
112
|
* ```
|
|
100
113
|
*
|
|
101
114
|
* @see {@link BitStreamFilter.getByName} For filter discovery
|
|
115
|
+
* @see {@link BitstreamFilterOptions} For available options
|
|
102
116
|
*/
|
|
103
|
-
static create(filterName: string, stream: Stream): BitStreamFilterAPI;
|
|
117
|
+
static create(filterName: string, stream: Stream, filterOptions?: BitstreamFilterOptions): BitStreamFilterAPI;
|
|
104
118
|
/**
|
|
105
119
|
* Get filter name.
|
|
106
120
|
*
|
|
@@ -147,74 +161,112 @@ export declare class BitStreamFilterAPI implements Disposable {
|
|
|
147
161
|
*/
|
|
148
162
|
get isBitstreamFilterOpen(): boolean;
|
|
149
163
|
/**
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
* Sends a packet to the filter and attempts to receive a filtered packet.
|
|
153
|
-
* Handles internal buffering - may return null if more packets needed.
|
|
164
|
+
* Send a packet to the filter.
|
|
154
165
|
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
166
|
+
* Sends a packet to the filter for processing.
|
|
167
|
+
* Does not return filtered packets - use {@link receive} to retrieve packets.
|
|
168
|
+
* A single packet can produce zero, one, or multiple packets depending on filter.
|
|
158
169
|
*
|
|
159
|
-
*
|
|
170
|
+
* **Important**: This method only SENDS the packet to the filter.
|
|
171
|
+
* You must call {@link receive} separately (potentially multiple times) to get filtered packets.
|
|
160
172
|
*
|
|
161
|
-
*
|
|
173
|
+
* Direct mapping to av_bsf_send_packet().
|
|
162
174
|
*
|
|
163
|
-
* @
|
|
175
|
+
* @param packet - Packet to send to filter, or null to flush
|
|
164
176
|
*
|
|
165
|
-
* @throws {FFmpegError} If
|
|
177
|
+
* @throws {FFmpegError} If sending fails
|
|
166
178
|
*
|
|
167
179
|
* @example
|
|
168
180
|
* ```typescript
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
*
|
|
181
|
+
* // Send packet and receive filtered packets
|
|
182
|
+
* await filter.filter(inputPacket);
|
|
183
|
+
*
|
|
184
|
+
* // Receive all available filtered packets
|
|
185
|
+
* while (true) {
|
|
186
|
+
* const outPacket = await filter.receive();
|
|
187
|
+
* if (!outPacket) break;
|
|
188
|
+
* console.log(`Filtered packet with PTS: ${outPacket.pts}`);
|
|
172
189
|
* await output.writePacket(outPacket);
|
|
173
190
|
* outPacket.free();
|
|
174
191
|
* }
|
|
175
192
|
* ```
|
|
176
193
|
*
|
|
177
|
-
* @
|
|
178
|
-
*
|
|
194
|
+
* @example
|
|
195
|
+
* ```typescript
|
|
196
|
+
* for await (const packet of input.packets()) {
|
|
197
|
+
* // packet is null at end of stream - automatically flushes filter
|
|
198
|
+
* await filter.filter(packet);
|
|
199
|
+
*
|
|
200
|
+
* // Receive available filtered packets
|
|
201
|
+
* let outPacket;
|
|
202
|
+
* while ((outPacket = await filter.receive())) {
|
|
203
|
+
* await output.writePacket(outPacket);
|
|
204
|
+
* outPacket.free();
|
|
205
|
+
* }
|
|
206
|
+
* }
|
|
207
|
+
* ```
|
|
208
|
+
*
|
|
209
|
+
* @see {@link receive} For receiving filtered packets
|
|
210
|
+
* @see {@link filterAll} For combined send+receive operation
|
|
211
|
+
* @see {@link packets} For automatic packet iteration
|
|
179
212
|
* @see {@link flush} For end-of-stream handling
|
|
180
213
|
* @see {@link filterSync} For synchronous version
|
|
181
214
|
*/
|
|
182
|
-
filter(packet: Packet): Promise<
|
|
215
|
+
filter(packet: Packet | null): Promise<void>;
|
|
183
216
|
/**
|
|
184
|
-
*
|
|
217
|
+
* Send a packet to the filter synchronously.
|
|
185
218
|
* Synchronous version of filter.
|
|
186
219
|
*
|
|
187
|
-
* Sends a packet to the filter
|
|
188
|
-
*
|
|
220
|
+
* Sends a packet to the filter for processing.
|
|
221
|
+
* Does not return filtered packets - use {@link receiveSync} to retrieve packets.
|
|
222
|
+
* A single packet can produce zero, one, or multiple packets depending on filter.
|
|
189
223
|
*
|
|
190
|
-
* **
|
|
191
|
-
*
|
|
192
|
-
* To receive all packets from a packet, use {@link filterAllSync} or {@link packetsSync} instead.
|
|
224
|
+
* **Important**: This method only SENDS the packet to the filter.
|
|
225
|
+
* You must call {@link receiveSync} separately (potentially multiple times) to get filtered packets.
|
|
193
226
|
*
|
|
194
|
-
* Direct mapping to av_bsf_send_packet()
|
|
227
|
+
* Direct mapping to av_bsf_send_packet().
|
|
195
228
|
*
|
|
196
|
-
* @param packet - Packet to filter
|
|
229
|
+
* @param packet - Packet to send to filter, or null to flush
|
|
197
230
|
*
|
|
198
|
-
* @
|
|
199
|
-
*
|
|
200
|
-
* @throws {FFmpegError} If filtering fails
|
|
231
|
+
* @throws {FFmpegError} If sending fails
|
|
201
232
|
*
|
|
202
233
|
* @example
|
|
203
234
|
* ```typescript
|
|
204
|
-
*
|
|
205
|
-
*
|
|
206
|
-
*
|
|
235
|
+
* // Send packet and receive filtered packets
|
|
236
|
+
* filter.filterSync(inputPacket);
|
|
237
|
+
*
|
|
238
|
+
* // Receive all available filtered packets
|
|
239
|
+
* while (true) {
|
|
240
|
+
* const outPacket = filter.receiveSync();
|
|
241
|
+
* if (!outPacket) break;
|
|
242
|
+
* console.log(`Filtered packet with PTS: ${outPacket.pts}`);
|
|
207
243
|
* output.writePacketSync(outPacket);
|
|
208
244
|
* outPacket.free();
|
|
209
245
|
* }
|
|
210
246
|
* ```
|
|
211
247
|
*
|
|
212
|
-
* @
|
|
213
|
-
*
|
|
248
|
+
* @example
|
|
249
|
+
* ```typescript
|
|
250
|
+
* for (const packet of packets) {
|
|
251
|
+
* // packet is null at end of stream - automatically flushes filter
|
|
252
|
+
* filter.filterSync(packet);
|
|
253
|
+
*
|
|
254
|
+
* // Receive available filtered packets
|
|
255
|
+
* let outPacket;
|
|
256
|
+
* while ((outPacket = filter.receiveSync())) {
|
|
257
|
+
* output.writePacketSync(outPacket);
|
|
258
|
+
* outPacket.free();
|
|
259
|
+
* }
|
|
260
|
+
* }
|
|
261
|
+
* ```
|
|
262
|
+
*
|
|
263
|
+
* @see {@link receiveSync} For receiving filtered packets
|
|
264
|
+
* @see {@link filterAllSync} For combined send+receive operation
|
|
265
|
+
* @see {@link packetsSync} For automatic packet iteration
|
|
214
266
|
* @see {@link flushSync} For end-of-stream handling
|
|
215
267
|
* @see {@link filter} For async version
|
|
216
268
|
*/
|
|
217
|
-
filterSync(packet: Packet
|
|
269
|
+
filterSync(packet: Packet | null): void;
|
|
218
270
|
/**
|
|
219
271
|
* Filter a packet to packets.
|
|
220
272
|
*
|
|
@@ -224,7 +276,7 @@ export declare class BitStreamFilterAPI implements Disposable {
|
|
|
224
276
|
*
|
|
225
277
|
* Direct mapping to av_bsf_send_packet() and av_bsf_receive_packet().
|
|
226
278
|
*
|
|
227
|
-
* @param packet - Packet to filter
|
|
279
|
+
* @param packet - Packet to filter, or null to flush
|
|
228
280
|
*
|
|
229
281
|
* @returns Array of filtered packets (empty if more data needed or filter is closed)
|
|
230
282
|
*
|
|
@@ -240,12 +292,22 @@ export declare class BitStreamFilterAPI implements Disposable {
|
|
|
240
292
|
* }
|
|
241
293
|
* ```
|
|
242
294
|
*
|
|
295
|
+
* @example
|
|
296
|
+
* ```typescript
|
|
297
|
+
* // Flush remaining packets at end of stream
|
|
298
|
+
* const remaining = await filter.filterAll(null);
|
|
299
|
+
* for (const packet of remaining) {
|
|
300
|
+
* await output.writePacket(packet);
|
|
301
|
+
* packet.free();
|
|
302
|
+
* }
|
|
303
|
+
* ```
|
|
304
|
+
*
|
|
243
305
|
* @see {@link filter} For single packet filtering
|
|
244
306
|
* @see {@link packets} For stream processing
|
|
245
307
|
* @see {@link flush} For end-of-stream handling
|
|
246
308
|
* @see {@link filterAllSync} For synchronous version
|
|
247
309
|
*/
|
|
248
|
-
filterAll(packet: Packet): Promise<Packet[]>;
|
|
310
|
+
filterAll(packet: Packet | null): Promise<Packet[]>;
|
|
249
311
|
/**
|
|
250
312
|
* Filter a packet to packets synchronously.
|
|
251
313
|
* Synchronous version of filterAll.
|
|
@@ -256,7 +318,7 @@ export declare class BitStreamFilterAPI implements Disposable {
|
|
|
256
318
|
*
|
|
257
319
|
* Direct mapping to av_bsf_send_packet() and av_bsf_receive_packet().
|
|
258
320
|
*
|
|
259
|
-
* @param packet - Packet to filter
|
|
321
|
+
* @param packet - Packet to filter, or null to flush
|
|
260
322
|
*
|
|
261
323
|
* @returns Array of filtered packets (empty if more data needed or filter is closed)
|
|
262
324
|
*
|
|
@@ -272,88 +334,142 @@ export declare class BitStreamFilterAPI implements Disposable {
|
|
|
272
334
|
* }
|
|
273
335
|
* ```
|
|
274
336
|
*
|
|
337
|
+
* @example
|
|
338
|
+
* ```typescript
|
|
339
|
+
* // Flush remaining packets at end of stream
|
|
340
|
+
* const remaining = filter.filterAllSync(null);
|
|
341
|
+
* for (const packet of remaining) {
|
|
342
|
+
* output.writePacketSync(packet);
|
|
343
|
+
* packet.free();
|
|
344
|
+
* }
|
|
345
|
+
* ```
|
|
346
|
+
*
|
|
275
347
|
* @see {@link filterSync} For single packet filtering
|
|
276
348
|
* @see {@link packetsSync} For stream processing
|
|
277
349
|
* @see {@link flushSync} For end-of-stream handling
|
|
278
350
|
* @see {@link filterAll} For async version
|
|
279
351
|
*/
|
|
280
|
-
filterAllSync(packet: Packet): Packet[];
|
|
352
|
+
filterAllSync(packet: Packet | null): Packet[];
|
|
281
353
|
/**
|
|
282
|
-
*
|
|
354
|
+
* Filter packet stream to filtered packet stream.
|
|
283
355
|
*
|
|
284
|
-
* High-level async generator for filtering
|
|
285
|
-
*
|
|
286
|
-
*
|
|
356
|
+
* High-level async generator for complete filtering pipeline.
|
|
357
|
+
* Filter is only flushed when EOF (null) signal is explicitly received.
|
|
358
|
+
* Primary interface for stream-based filtering.
|
|
287
359
|
*
|
|
288
|
-
*
|
|
360
|
+
* **EOF Handling:**
|
|
361
|
+
* - Send null to flush filter and get remaining buffered packets
|
|
362
|
+
* - Generator yields null after flushing when null is received
|
|
363
|
+
* - No automatic flushing - filter stays open until EOF or close()
|
|
289
364
|
*
|
|
290
|
-
* @
|
|
365
|
+
* @param packets - Async iterable of packets, single packet, or null to flush
|
|
366
|
+
*
|
|
367
|
+
* @yields {Packet | null} Filtered packets, followed by null when explicitly flushed
|
|
291
368
|
*
|
|
292
369
|
* @throws {FFmpegError} If filtering fails
|
|
293
370
|
*
|
|
294
371
|
* @example
|
|
295
372
|
* ```typescript
|
|
296
|
-
* //
|
|
373
|
+
* // Stream of packets with automatic EOF propagation
|
|
297
374
|
* for await (const packet of filter.packets(input.packets())) {
|
|
375
|
+
* if (packet === null) {
|
|
376
|
+
* console.log('Filter flushed');
|
|
377
|
+
* break;
|
|
378
|
+
* }
|
|
298
379
|
* await output.writePacket(packet);
|
|
299
|
-
* packet.free();
|
|
380
|
+
* packet.free(); // Must free output packets
|
|
300
381
|
* }
|
|
301
382
|
* ```
|
|
302
383
|
*
|
|
303
384
|
* @example
|
|
304
385
|
* ```typescript
|
|
305
|
-
* //
|
|
306
|
-
* const
|
|
307
|
-
*
|
|
386
|
+
* // Single packet - no automatic flush
|
|
387
|
+
* for await (const packet of filter.packets(singlePacket)) {
|
|
388
|
+
* await output.writePacket(packet);
|
|
389
|
+
* packet.free();
|
|
390
|
+
* }
|
|
391
|
+
* // Filter remains open, buffered packets not flushed
|
|
392
|
+
* ```
|
|
308
393
|
*
|
|
309
|
-
*
|
|
310
|
-
*
|
|
311
|
-
*
|
|
394
|
+
* @example
|
|
395
|
+
* ```typescript
|
|
396
|
+
* // Explicit flush with EOF
|
|
397
|
+
* for await (const packet of filter.packets(null)) {
|
|
398
|
+
* if (packet === null) {
|
|
399
|
+
* console.log('All buffered packets flushed');
|
|
400
|
+
* break;
|
|
401
|
+
* }
|
|
402
|
+
* console.log('Buffered packet:', packet.pts);
|
|
403
|
+
* await output.writePacket(packet);
|
|
404
|
+
* packet.free();
|
|
312
405
|
* }
|
|
313
406
|
* ```
|
|
314
407
|
*
|
|
315
|
-
* @see {@link
|
|
316
|
-
* @see {@link
|
|
408
|
+
* @see {@link filter} For single packet filtering
|
|
409
|
+
* @see {@link Demuxer.packets} For packet source
|
|
410
|
+
* @see {@link packetsSync} For sync version
|
|
317
411
|
*/
|
|
318
|
-
packets(packets: AsyncIterable<Packet | null>): AsyncGenerator<Packet | null>;
|
|
412
|
+
packets(packets: AsyncIterable<Packet | null> | Packet | null): AsyncGenerator<Packet | null>;
|
|
319
413
|
/**
|
|
320
|
-
*
|
|
414
|
+
* Filter packet stream to filtered packet stream synchronously.
|
|
321
415
|
* Synchronous version of packets.
|
|
322
416
|
*
|
|
323
|
-
* High-level sync generator for filtering
|
|
324
|
-
*
|
|
325
|
-
*
|
|
417
|
+
* High-level sync generator for complete filtering pipeline.
|
|
418
|
+
* Filter is only flushed when EOF (null) signal is explicitly received.
|
|
419
|
+
* Primary interface for stream-based filtering.
|
|
420
|
+
*
|
|
421
|
+
* **EOF Handling:**
|
|
422
|
+
* - Send null to flush filter and get remaining buffered packets
|
|
423
|
+
* - Generator yields null after flushing when null is received
|
|
424
|
+
* - No automatic flushing - filter stays open until EOF or close()
|
|
326
425
|
*
|
|
327
|
-
* @param packets - Iterable of packets
|
|
426
|
+
* @param packets - Iterable of packets, single packet, or null to flush
|
|
328
427
|
*
|
|
329
|
-
* @yields {Packet} Filtered packets
|
|
428
|
+
* @yields {Packet | null} Filtered packets, followed by null when explicitly flushed
|
|
330
429
|
*
|
|
331
430
|
* @throws {FFmpegError} If filtering fails
|
|
332
431
|
*
|
|
333
432
|
* @example
|
|
334
433
|
* ```typescript
|
|
335
|
-
* //
|
|
336
|
-
* for (const packet of filter.packetsSync(
|
|
434
|
+
* // Stream of packets with automatic EOF propagation
|
|
435
|
+
* for (const packet of filter.packetsSync(inputPackets)) {
|
|
436
|
+
* if (packet === null) {
|
|
437
|
+
* console.log('Filter flushed');
|
|
438
|
+
* break;
|
|
439
|
+
* }
|
|
337
440
|
* output.writePacketSync(packet);
|
|
338
|
-
* packet.free();
|
|
441
|
+
* packet.free(); // Must free output packets
|
|
339
442
|
* }
|
|
340
443
|
* ```
|
|
341
444
|
*
|
|
342
445
|
* @example
|
|
343
446
|
* ```typescript
|
|
344
|
-
* //
|
|
345
|
-
* const
|
|
346
|
-
*
|
|
447
|
+
* // Single packet - no automatic flush
|
|
448
|
+
* for (const packet of filter.packetsSync(singlePacket)) {
|
|
449
|
+
* output.writePacketSync(packet);
|
|
450
|
+
* packet.free();
|
|
451
|
+
* }
|
|
452
|
+
* // Filter remains open, buffered packets not flushed
|
|
453
|
+
* ```
|
|
347
454
|
*
|
|
348
|
-
*
|
|
349
|
-
*
|
|
350
|
-
*
|
|
455
|
+
* @example
|
|
456
|
+
* ```typescript
|
|
457
|
+
* // Explicit flush with EOF
|
|
458
|
+
* for (const packet of filter.packetsSync(null)) {
|
|
459
|
+
* if (packet === null) {
|
|
460
|
+
* console.log('All buffered packets flushed');
|
|
461
|
+
* break;
|
|
462
|
+
* }
|
|
463
|
+
* console.log('Buffered packet:', packet.pts);
|
|
464
|
+
* output.writePacketSync(packet);
|
|
465
|
+
* packet.free();
|
|
351
466
|
* }
|
|
352
467
|
* ```
|
|
353
468
|
*
|
|
469
|
+
* @see {@link filterSync} For single packet filtering
|
|
354
470
|
* @see {@link packets} For async version
|
|
355
471
|
*/
|
|
356
|
-
packetsSync(packets: Iterable<Packet | null>): Generator<Packet | null>;
|
|
472
|
+
packetsSync(packets: Iterable<Packet | null> | Packet | null): Generator<Packet | null>;
|
|
357
473
|
/**
|
|
358
474
|
* Flush filter and signal end-of-stream.
|
|
359
475
|
*
|