@revizly/node-av 5.2.2-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/BUILD_LINUX.md +61 -0
- package/LICENSE.md +22 -0
- package/README.md +662 -0
- package/build_mac_local.sh +69 -0
- package/dist/api/audio-frame-buffer.d.ts +205 -0
- package/dist/api/audio-frame-buffer.js +287 -0
- package/dist/api/audio-frame-buffer.js.map +1 -0
- package/dist/api/bitstream-filter.d.ts +820 -0
- package/dist/api/bitstream-filter.js +1242 -0
- package/dist/api/bitstream-filter.js.map +1 -0
- package/dist/api/constants.d.ts +44 -0
- package/dist/api/constants.js +45 -0
- package/dist/api/constants.js.map +1 -0
- package/dist/api/data/test_av1.ivf +0 -0
- package/dist/api/data/test_h264.h264 +0 -0
- package/dist/api/data/test_hevc.h265 +0 -0
- package/dist/api/data/test_mjpeg.mjpeg +0 -0
- package/dist/api/data/test_vp8.ivf +0 -0
- package/dist/api/data/test_vp9.ivf +0 -0
- package/dist/api/decoder.d.ts +1088 -0
- package/dist/api/decoder.js +1775 -0
- package/dist/api/decoder.js.map +1 -0
- package/dist/api/demuxer.d.ts +1219 -0
- package/dist/api/demuxer.js +2081 -0
- package/dist/api/demuxer.js.map +1 -0
- package/dist/api/device.d.ts +586 -0
- package/dist/api/device.js +961 -0
- package/dist/api/device.js.map +1 -0
- package/dist/api/encoder.d.ts +1132 -0
- package/dist/api/encoder.js +1988 -0
- package/dist/api/encoder.js.map +1 -0
- package/dist/api/filter-complex.d.ts +821 -0
- package/dist/api/filter-complex.js +1604 -0
- package/dist/api/filter-complex.js.map +1 -0
- package/dist/api/filter-presets.d.ts +1286 -0
- package/dist/api/filter-presets.js +2152 -0
- package/dist/api/filter-presets.js.map +1 -0
- package/dist/api/filter.d.ts +1234 -0
- package/dist/api/filter.js +1976 -0
- package/dist/api/filter.js.map +1 -0
- package/dist/api/fmp4-stream.d.ts +426 -0
- package/dist/api/fmp4-stream.js +739 -0
- package/dist/api/fmp4-stream.js.map +1 -0
- package/dist/api/hardware.d.ts +651 -0
- package/dist/api/hardware.js +1260 -0
- package/dist/api/hardware.js.map +1 -0
- package/dist/api/index.d.ts +17 -0
- package/dist/api/index.js +32 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/io-stream.d.ts +307 -0
- package/dist/api/io-stream.js +282 -0
- package/dist/api/io-stream.js.map +1 -0
- package/dist/api/muxer.d.ts +957 -0
- package/dist/api/muxer.js +2002 -0
- package/dist/api/muxer.js.map +1 -0
- package/dist/api/pipeline.d.ts +607 -0
- package/dist/api/pipeline.js +1145 -0
- package/dist/api/pipeline.js.map +1 -0
- package/dist/api/utilities/async-queue.d.ts +120 -0
- package/dist/api/utilities/async-queue.js +211 -0
- package/dist/api/utilities/async-queue.js.map +1 -0
- package/dist/api/utilities/audio-sample.d.ts +117 -0
- package/dist/api/utilities/audio-sample.js +112 -0
- package/dist/api/utilities/audio-sample.js.map +1 -0
- package/dist/api/utilities/channel-layout.d.ts +76 -0
- package/dist/api/utilities/channel-layout.js +80 -0
- package/dist/api/utilities/channel-layout.js.map +1 -0
- package/dist/api/utilities/electron-shared-texture.d.ts +328 -0
- package/dist/api/utilities/electron-shared-texture.js +503 -0
- package/dist/api/utilities/electron-shared-texture.js.map +1 -0
- package/dist/api/utilities/image.d.ts +207 -0
- package/dist/api/utilities/image.js +213 -0
- package/dist/api/utilities/image.js.map +1 -0
- package/dist/api/utilities/index.d.ts +12 -0
- package/dist/api/utilities/index.js +25 -0
- package/dist/api/utilities/index.js.map +1 -0
- package/dist/api/utilities/media-type.d.ts +49 -0
- package/dist/api/utilities/media-type.js +53 -0
- package/dist/api/utilities/media-type.js.map +1 -0
- package/dist/api/utilities/pixel-format.d.ts +89 -0
- package/dist/api/utilities/pixel-format.js +97 -0
- package/dist/api/utilities/pixel-format.js.map +1 -0
- package/dist/api/utilities/sample-format.d.ts +129 -0
- package/dist/api/utilities/sample-format.js +141 -0
- package/dist/api/utilities/sample-format.js.map +1 -0
- package/dist/api/utilities/scheduler.d.ts +138 -0
- package/dist/api/utilities/scheduler.js +98 -0
- package/dist/api/utilities/scheduler.js.map +1 -0
- package/dist/api/utilities/streaming.d.ts +186 -0
- package/dist/api/utilities/streaming.js +309 -0
- package/dist/api/utilities/streaming.js.map +1 -0
- package/dist/api/utilities/timestamp.d.ts +193 -0
- package/dist/api/utilities/timestamp.js +206 -0
- package/dist/api/utilities/timestamp.js.map +1 -0
- package/dist/api/utilities/whisper-model.d.ts +310 -0
- package/dist/api/utilities/whisper-model.js +528 -0
- package/dist/api/utilities/whisper-model.js.map +1 -0
- package/dist/api/utils.d.ts +19 -0
- package/dist/api/utils.js +39 -0
- package/dist/api/utils.js.map +1 -0
- package/dist/api/whisper.d.ts +324 -0
- package/dist/api/whisper.js +362 -0
- package/dist/api/whisper.js.map +1 -0
- package/dist/constants/channel-layouts.d.ts +53 -0
- package/dist/constants/channel-layouts.js +57 -0
- package/dist/constants/channel-layouts.js.map +1 -0
- package/dist/constants/constants.d.ts +2325 -0
- package/dist/constants/constants.js +1887 -0
- package/dist/constants/constants.js.map +1 -0
- package/dist/constants/decoders.d.ts +633 -0
- package/dist/constants/decoders.js +641 -0
- package/dist/constants/decoders.js.map +1 -0
- package/dist/constants/encoders.d.ts +295 -0
- package/dist/constants/encoders.js +308 -0
- package/dist/constants/encoders.js.map +1 -0
- package/dist/constants/hardware.d.ts +26 -0
- package/dist/constants/hardware.js +27 -0
- package/dist/constants/hardware.js.map +1 -0
- package/dist/constants/index.d.ts +5 -0
- package/dist/constants/index.js +6 -0
- package/dist/constants/index.js.map +1 -0
- package/dist/ffmpeg/index.d.ts +99 -0
- package/dist/ffmpeg/index.js +115 -0
- package/dist/ffmpeg/index.js.map +1 -0
- package/dist/ffmpeg/utils.d.ts +31 -0
- package/dist/ffmpeg/utils.js +68 -0
- package/dist/ffmpeg/utils.js.map +1 -0
- package/dist/ffmpeg/version.d.ts +6 -0
- package/dist/ffmpeg/version.js +7 -0
- package/dist/ffmpeg/version.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/audio-fifo.d.ts +399 -0
- package/dist/lib/audio-fifo.js +431 -0
- package/dist/lib/audio-fifo.js.map +1 -0
- package/dist/lib/binding.d.ts +228 -0
- package/dist/lib/binding.js +60 -0
- package/dist/lib/binding.js.map +1 -0
- package/dist/lib/bitstream-filter-context.d.ts +379 -0
- package/dist/lib/bitstream-filter-context.js +441 -0
- package/dist/lib/bitstream-filter-context.js.map +1 -0
- package/dist/lib/bitstream-filter.d.ts +140 -0
- package/dist/lib/bitstream-filter.js +154 -0
- package/dist/lib/bitstream-filter.js.map +1 -0
- package/dist/lib/codec-context.d.ts +1071 -0
- package/dist/lib/codec-context.js +1354 -0
- package/dist/lib/codec-context.js.map +1 -0
- package/dist/lib/codec-parameters.d.ts +616 -0
- package/dist/lib/codec-parameters.js +761 -0
- package/dist/lib/codec-parameters.js.map +1 -0
- package/dist/lib/codec-parser.d.ts +201 -0
- package/dist/lib/codec-parser.js +213 -0
- package/dist/lib/codec-parser.js.map +1 -0
- package/dist/lib/codec.d.ts +586 -0
- package/dist/lib/codec.js +713 -0
- package/dist/lib/codec.js.map +1 -0
- package/dist/lib/device.d.ts +291 -0
- package/dist/lib/device.js +324 -0
- package/dist/lib/device.js.map +1 -0
- package/dist/lib/dictionary.d.ts +333 -0
- package/dist/lib/dictionary.js +372 -0
- package/dist/lib/dictionary.js.map +1 -0
- package/dist/lib/error.d.ts +242 -0
- package/dist/lib/error.js +303 -0
- package/dist/lib/error.js.map +1 -0
- package/dist/lib/fifo.d.ts +416 -0
- package/dist/lib/fifo.js +453 -0
- package/dist/lib/fifo.js.map +1 -0
- package/dist/lib/filter-context.d.ts +712 -0
- package/dist/lib/filter-context.js +789 -0
- package/dist/lib/filter-context.js.map +1 -0
- package/dist/lib/filter-graph-segment.d.ts +160 -0
- package/dist/lib/filter-graph-segment.js +171 -0
- package/dist/lib/filter-graph-segment.js.map +1 -0
- package/dist/lib/filter-graph.d.ts +641 -0
- package/dist/lib/filter-graph.js +704 -0
- package/dist/lib/filter-graph.js.map +1 -0
- package/dist/lib/filter-inout.d.ts +198 -0
- package/dist/lib/filter-inout.js +257 -0
- package/dist/lib/filter-inout.js.map +1 -0
- package/dist/lib/filter.d.ts +243 -0
- package/dist/lib/filter.js +272 -0
- package/dist/lib/filter.js.map +1 -0
- package/dist/lib/format-context.d.ts +1254 -0
- package/dist/lib/format-context.js +1379 -0
- package/dist/lib/format-context.js.map +1 -0
- package/dist/lib/frame-utils.d.ts +116 -0
- package/dist/lib/frame-utils.js +98 -0
- package/dist/lib/frame-utils.js.map +1 -0
- package/dist/lib/frame.d.ts +1222 -0
- package/dist/lib/frame.js +1435 -0
- package/dist/lib/frame.js.map +1 -0
- package/dist/lib/hardware-device-context.d.ts +362 -0
- package/dist/lib/hardware-device-context.js +383 -0
- package/dist/lib/hardware-device-context.js.map +1 -0
- package/dist/lib/hardware-frames-context.d.ts +419 -0
- package/dist/lib/hardware-frames-context.js +477 -0
- package/dist/lib/hardware-frames-context.js.map +1 -0
- package/dist/lib/index.d.ts +35 -0
- package/dist/lib/index.js +60 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/input-format.d.ts +249 -0
- package/dist/lib/input-format.js +306 -0
- package/dist/lib/input-format.js.map +1 -0
- package/dist/lib/io-context.d.ts +696 -0
- package/dist/lib/io-context.js +769 -0
- package/dist/lib/io-context.js.map +1 -0
- package/dist/lib/log.d.ts +174 -0
- package/dist/lib/log.js +184 -0
- package/dist/lib/log.js.map +1 -0
- package/dist/lib/native-types.d.ts +946 -0
- package/dist/lib/native-types.js +2 -0
- package/dist/lib/native-types.js.map +1 -0
- package/dist/lib/option.d.ts +927 -0
- package/dist/lib/option.js +1583 -0
- package/dist/lib/option.js.map +1 -0
- package/dist/lib/output-format.d.ts +180 -0
- package/dist/lib/output-format.js +213 -0
- package/dist/lib/output-format.js.map +1 -0
- package/dist/lib/packet.d.ts +501 -0
- package/dist/lib/packet.js +590 -0
- package/dist/lib/packet.js.map +1 -0
- package/dist/lib/rational.d.ts +251 -0
- package/dist/lib/rational.js +278 -0
- package/dist/lib/rational.js.map +1 -0
- package/dist/lib/software-resample-context.d.ts +552 -0
- package/dist/lib/software-resample-context.js +592 -0
- package/dist/lib/software-resample-context.js.map +1 -0
- package/dist/lib/software-scale-context.d.ts +344 -0
- package/dist/lib/software-scale-context.js +366 -0
- package/dist/lib/software-scale-context.js.map +1 -0
- package/dist/lib/stream.d.ts +379 -0
- package/dist/lib/stream.js +526 -0
- package/dist/lib/stream.js.map +1 -0
- package/dist/lib/sync-queue.d.ts +179 -0
- package/dist/lib/sync-queue.js +197 -0
- package/dist/lib/sync-queue.js.map +1 -0
- package/dist/lib/types.d.ts +34 -0
- package/dist/lib/types.js +2 -0
- package/dist/lib/types.js.map +1 -0
- package/dist/lib/utilities.d.ts +1127 -0
- package/dist/lib/utilities.js +1225 -0
- package/dist/lib/utilities.js.map +1 -0
- package/dist/utils/electron.d.ts +49 -0
- package/dist/utils/electron.js +63 -0
- package/dist/utils/electron.js.map +1 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.js +5 -0
- package/dist/utils/index.js.map +1 -0
- package/install/check.js +121 -0
- package/install/ffmpeg.js +66 -0
- package/jellyfin-ffmpeg.patch +181 -0
- package/package.json +129 -0
|
@@ -0,0 +1,1242 @@
|
|
|
1
|
+
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
|
|
2
|
+
if (value !== null && value !== void 0) {
|
|
3
|
+
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
|
4
|
+
var dispose, inner;
|
|
5
|
+
if (async) {
|
|
6
|
+
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
|
|
7
|
+
dispose = value[Symbol.asyncDispose];
|
|
8
|
+
}
|
|
9
|
+
if (dispose === void 0) {
|
|
10
|
+
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
|
|
11
|
+
dispose = value[Symbol.dispose];
|
|
12
|
+
if (async) inner = dispose;
|
|
13
|
+
}
|
|
14
|
+
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
|
|
15
|
+
if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
|
|
16
|
+
env.stack.push({ value: value, dispose: dispose, async: async });
|
|
17
|
+
}
|
|
18
|
+
else if (async) {
|
|
19
|
+
env.stack.push({ async: true });
|
|
20
|
+
}
|
|
21
|
+
return value;
|
|
22
|
+
};
|
|
23
|
+
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
|
|
24
|
+
return function (env) {
|
|
25
|
+
function fail(e) {
|
|
26
|
+
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
27
|
+
env.hasError = true;
|
|
28
|
+
}
|
|
29
|
+
var r, s = 0;
|
|
30
|
+
function next() {
|
|
31
|
+
while (r = env.stack.pop()) {
|
|
32
|
+
try {
|
|
33
|
+
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
|
|
34
|
+
if (r.dispose) {
|
|
35
|
+
var result = r.dispose.call(r.value);
|
|
36
|
+
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
|
|
37
|
+
}
|
|
38
|
+
else s |= 1;
|
|
39
|
+
}
|
|
40
|
+
catch (e) {
|
|
41
|
+
fail(e);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
|
|
45
|
+
if (env.hasError) throw env.error;
|
|
46
|
+
}
|
|
47
|
+
return next();
|
|
48
|
+
};
|
|
49
|
+
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
50
|
+
var e = new Error(message);
|
|
51
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
52
|
+
});
|
|
53
|
+
import { AVERROR_BSF_NOT_FOUND, AVERROR_EAGAIN, AVERROR_EOF } from '../constants/constants.js';
|
|
54
|
+
import { BitStreamFilterContext } from '../lib/bitstream-filter-context.js';
|
|
55
|
+
import { BitStreamFilter } from '../lib/bitstream-filter.js';
|
|
56
|
+
import { FFmpegError } from '../lib/error.js';
|
|
57
|
+
import { Packet } from '../lib/packet.js';
|
|
58
|
+
import { PACKET_THREAD_QUEUE_SIZE } from './constants.js';
|
|
59
|
+
import { Muxer } from './muxer.js';
|
|
60
|
+
import { AsyncQueue } from './utilities/async-queue.js';
|
|
61
|
+
import { Scheduler, SchedulerControl } from './utilities/scheduler.js';
|
|
62
|
+
/**
|
|
63
|
+
* High-level bitstream filter for packet processing.
|
|
64
|
+
*
|
|
65
|
+
* Provides simplified interface for applying bitstream filters to packets.
|
|
66
|
+
* Handles filter initialization, packet processing, and memory management.
|
|
67
|
+
* Supports both synchronous packet-by-packet filtering and async iteration over packets.
|
|
68
|
+
* Supports filters like h264_mp4toannexb, hevc_mp4toannexb, aac_adtstoasc.
|
|
69
|
+
* Essential for format conversion and stream compatibility in transcoding pipelines.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```typescript
|
|
73
|
+
* import { BitStreamFilterAPI } from 'node-av/api';
|
|
74
|
+
*
|
|
75
|
+
* // Create H.264 Annex B converter
|
|
76
|
+
* const filter = BitStreamFilterAPI.create('h264_mp4toannexb', stream);
|
|
77
|
+
*
|
|
78
|
+
* // Filter packet
|
|
79
|
+
* const outputPackets = await filter.filterAll(inputPacket);
|
|
80
|
+
* for (const packet of outputPackets) {
|
|
81
|
+
* await output.writePacket(packet);
|
|
82
|
+
* packet.free();
|
|
83
|
+
* }
|
|
84
|
+
* ```
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```typescript
|
|
88
|
+
* // Filter packet stream
|
|
89
|
+
* const filter = BitStreamFilterAPI.create('hevc_mp4toannexb', videoStream);
|
|
90
|
+
*
|
|
91
|
+
* for await (const packet of filter.packets(input.packets())) {
|
|
92
|
+
* await output.writePacket(packet);
|
|
93
|
+
* packet.free();
|
|
94
|
+
* }
|
|
95
|
+
* ```
|
|
96
|
+
*
|
|
97
|
+
* @see {@link BitStreamFilter} For available filters
|
|
98
|
+
* @see {@link BitStreamFilterContext} For low-level API
|
|
99
|
+
* @see {@link Muxer} For writing filtered packets
|
|
100
|
+
*/
|
|
101
|
+
export class BitStreamFilterAPI {
|
|
102
|
+
ctx;
|
|
103
|
+
bsf;
|
|
104
|
+
stream;
|
|
105
|
+
packet;
|
|
106
|
+
isClosed = false;
|
|
107
|
+
// Worker pattern for push-based processing
|
|
108
|
+
inputQueue;
|
|
109
|
+
outputQueue;
|
|
110
|
+
workerPromise = null;
|
|
111
|
+
nextComponent = null;
|
|
112
|
+
pipeToPromise = null;
|
|
113
|
+
signal;
|
|
114
|
+
/**
|
|
115
|
+
* @param bsf - Bitstream filter
|
|
116
|
+
*
|
|
117
|
+
* @param ctx - Filter context
|
|
118
|
+
*
|
|
119
|
+
* @param stream - Associated stream
|
|
120
|
+
*
|
|
121
|
+
* @internal
|
|
122
|
+
*/
|
|
123
|
+
constructor(bsf, ctx, stream) {
|
|
124
|
+
this.bsf = bsf;
|
|
125
|
+
this.ctx = ctx;
|
|
126
|
+
this.stream = stream;
|
|
127
|
+
this.packet = new Packet();
|
|
128
|
+
this.packet.alloc();
|
|
129
|
+
this.inputQueue = new AsyncQueue(PACKET_THREAD_QUEUE_SIZE);
|
|
130
|
+
this.outputQueue = new AsyncQueue(PACKET_THREAD_QUEUE_SIZE);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Create a bitstream filter for a stream.
|
|
134
|
+
*
|
|
135
|
+
* Initializes filter with stream codec parameters.
|
|
136
|
+
* Configures time base and prepares for packet processing.
|
|
137
|
+
*
|
|
138
|
+
* Direct mapping to av_bsf_get_by_name() and av_bsf_alloc().
|
|
139
|
+
*
|
|
140
|
+
* @param filterName - Name of the bitstream filter
|
|
141
|
+
*
|
|
142
|
+
* @param stream - Stream to apply filter to
|
|
143
|
+
*
|
|
144
|
+
* @param filterOptions - Optional filter-specific options
|
|
145
|
+
*
|
|
146
|
+
* @returns Configured bitstream filter
|
|
147
|
+
*
|
|
148
|
+
* @throws {Error} If initialization fails
|
|
149
|
+
*
|
|
150
|
+
* @throws {FFmpegError} If allocation or initialization fails
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* ```typescript
|
|
154
|
+
* // H.264 MP4 to Annex B conversion
|
|
155
|
+
* const filter = BitStreamFilterAPI.create('h264_mp4toannexb', videoStream);
|
|
156
|
+
* ```
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* ```typescript
|
|
160
|
+
* // AAC ADTS to ASC conversion
|
|
161
|
+
* const filter = BitStreamFilterAPI.create('aac_adtstoasc', audioStream);
|
|
162
|
+
* ```
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* ```typescript
|
|
166
|
+
* // Remove AUDs from H.264 stream
|
|
167
|
+
* const filter = BitStreamFilterAPI.create('h264_metadata', stream, {
|
|
168
|
+
* options: { aud: 'remove' }
|
|
169
|
+
* });
|
|
170
|
+
* ```
|
|
171
|
+
*
|
|
172
|
+
* @example
|
|
173
|
+
* ```typescript
|
|
174
|
+
* // Set H.264 level
|
|
175
|
+
* const filter = BitStreamFilterAPI.create('h264_metadata', stream, {
|
|
176
|
+
* options: { level: 51 }
|
|
177
|
+
* });
|
|
178
|
+
* ```
|
|
179
|
+
*
|
|
180
|
+
* @see {@link BitStreamFilter.getByName} For filter discovery
|
|
181
|
+
* @see {@link BitstreamFilterOptions} For available options
|
|
182
|
+
*/
|
|
183
|
+
static create(filterName, stream, filterOptions) {
|
|
184
|
+
if (!stream) {
|
|
185
|
+
throw new Error('Stream is required');
|
|
186
|
+
}
|
|
187
|
+
// Find the bitstream filter
|
|
188
|
+
const filter = BitStreamFilter.getByName(filterName);
|
|
189
|
+
if (!filter) {
|
|
190
|
+
throw new FFmpegError(AVERROR_BSF_NOT_FOUND);
|
|
191
|
+
}
|
|
192
|
+
// Create and allocate context
|
|
193
|
+
const ctx = new BitStreamFilterContext();
|
|
194
|
+
const allocRet = ctx.alloc(filter);
|
|
195
|
+
FFmpegError.throwIfError(allocRet, 'Failed to allocate bitstream filter context');
|
|
196
|
+
try {
|
|
197
|
+
// Copy codec parameters from stream
|
|
198
|
+
if (!ctx.inputCodecParameters) {
|
|
199
|
+
throw new Error('Failed to get input codec parameters from filter context');
|
|
200
|
+
}
|
|
201
|
+
stream.codecpar.copy(ctx.inputCodecParameters);
|
|
202
|
+
// Set time base
|
|
203
|
+
ctx.inputTimeBase = stream.timeBase;
|
|
204
|
+
// Apply filter-specific options before init
|
|
205
|
+
if (filterOptions?.options) {
|
|
206
|
+
for (const [key, value] of Object.entries(filterOptions.options)) {
|
|
207
|
+
const ret = ctx.setOption(key, value);
|
|
208
|
+
FFmpegError.throwIfError(ret, `Failed to set bitstream filter option '${key}'`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
// Initialize the filter
|
|
212
|
+
const initRet = ctx.init();
|
|
213
|
+
FFmpegError.throwIfError(initRet, 'Failed to initialize bitstream filter');
|
|
214
|
+
const bsfApi = new BitStreamFilterAPI(filter, ctx, stream);
|
|
215
|
+
if (filterOptions?.signal) {
|
|
216
|
+
filterOptions.signal.throwIfAborted();
|
|
217
|
+
bsfApi.signal = filterOptions.signal;
|
|
218
|
+
}
|
|
219
|
+
return bsfApi;
|
|
220
|
+
}
|
|
221
|
+
catch (error) {
|
|
222
|
+
// Clean up on error
|
|
223
|
+
ctx.free();
|
|
224
|
+
throw error;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Get filter name.
|
|
229
|
+
*
|
|
230
|
+
* @example
|
|
231
|
+
* ```typescript
|
|
232
|
+
* console.log(`Using filter: ${filter.name}`);
|
|
233
|
+
* ```
|
|
234
|
+
*/
|
|
235
|
+
get name() {
|
|
236
|
+
return this.bsf.name ?? 'unknown';
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Get output codec parameters.
|
|
240
|
+
*
|
|
241
|
+
* Parameters after filter processing.
|
|
242
|
+
* May differ from input parameters.
|
|
243
|
+
*
|
|
244
|
+
* @example
|
|
245
|
+
* ```typescript
|
|
246
|
+
* const outputParams = filter.outputCodecParameters;
|
|
247
|
+
* console.log(`Output codec: ${outputParams?.codecId}`);
|
|
248
|
+
* ```
|
|
249
|
+
*/
|
|
250
|
+
get outputCodecParameters() {
|
|
251
|
+
return this.ctx.outputCodecParameters;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Get output time base.
|
|
255
|
+
*
|
|
256
|
+
* Time base after filter processing.
|
|
257
|
+
*
|
|
258
|
+
* @example
|
|
259
|
+
* ```typescript
|
|
260
|
+
* const tb = filter.outputTimeBase;
|
|
261
|
+
* console.log(`Output timebase: ${tb?.num}/${tb?.den}`);
|
|
262
|
+
* ```
|
|
263
|
+
*/
|
|
264
|
+
get outputTimeBase() {
|
|
265
|
+
return this.ctx.outputTimeBase;
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Check if filter is open.
|
|
269
|
+
*
|
|
270
|
+
* @example
|
|
271
|
+
* ```typescript
|
|
272
|
+
* if (filter.isBitstreamFilterOpen) {
|
|
273
|
+
* const packet = await filter.process(frame);
|
|
274
|
+
* }
|
|
275
|
+
* ```
|
|
276
|
+
*/
|
|
277
|
+
get isBitstreamFilterOpen() {
|
|
278
|
+
return !this.isClosed;
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Send a packet to the filter.
|
|
282
|
+
*
|
|
283
|
+
* Sends a packet to the filter for processing.
|
|
284
|
+
* Does not return filtered packets - use {@link receive} to retrieve packets.
|
|
285
|
+
* A single packet can produce zero, one, or multiple packets depending on filter.
|
|
286
|
+
*
|
|
287
|
+
* **Important**: This method only SENDS the packet to the filter.
|
|
288
|
+
* You must call {@link receive} separately (potentially multiple times) to get filtered packets.
|
|
289
|
+
*
|
|
290
|
+
* Direct mapping to av_bsf_send_packet().
|
|
291
|
+
*
|
|
292
|
+
* @param packet - Packet to send to filter, or null to flush
|
|
293
|
+
*
|
|
294
|
+
* @throws {FFmpegError} If sending fails
|
|
295
|
+
*
|
|
296
|
+
* @example
|
|
297
|
+
* ```typescript
|
|
298
|
+
* // Send packet and receive filtered packets
|
|
299
|
+
* await filter.filter(inputPacket);
|
|
300
|
+
*
|
|
301
|
+
* // Receive all available filtered packets
|
|
302
|
+
* while (true) {
|
|
303
|
+
* const outPacket = await filter.receive();
|
|
304
|
+
* if (!outPacket) break;
|
|
305
|
+
* console.log(`Filtered packet with PTS: ${outPacket.pts}`);
|
|
306
|
+
* await output.writePacket(outPacket);
|
|
307
|
+
* outPacket.free();
|
|
308
|
+
* }
|
|
309
|
+
* ```
|
|
310
|
+
*
|
|
311
|
+
* @example
|
|
312
|
+
* ```typescript
|
|
313
|
+
* for await (const packet of input.packets()) {
|
|
314
|
+
* // packet is null at end of stream - automatically flushes filter
|
|
315
|
+
* await filter.filter(packet);
|
|
316
|
+
*
|
|
317
|
+
* // Receive available filtered packets
|
|
318
|
+
* let outPacket;
|
|
319
|
+
* while ((outPacket = await filter.receive())) {
|
|
320
|
+
* await output.writePacket(outPacket);
|
|
321
|
+
* outPacket.free();
|
|
322
|
+
* }
|
|
323
|
+
* }
|
|
324
|
+
* ```
|
|
325
|
+
*
|
|
326
|
+
* @see {@link receive} For receiving filtered packets
|
|
327
|
+
* @see {@link filterAll} For combined send+receive operation
|
|
328
|
+
* @see {@link packets} For automatic packet iteration
|
|
329
|
+
* @see {@link flush} For end-of-stream handling
|
|
330
|
+
* @see {@link filterSync} For synchronous version
|
|
331
|
+
*/
|
|
332
|
+
async filter(packet) {
|
|
333
|
+
this.signal?.throwIfAborted();
|
|
334
|
+
if (this.isClosed) {
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
// Send packet to filter (null signals EOF/flush)
|
|
338
|
+
const sendRet = await this.ctx.sendPacket(packet);
|
|
339
|
+
if (sendRet < 0 && sendRet !== AVERROR_EOF && sendRet !== AVERROR_EAGAIN) {
|
|
340
|
+
FFmpegError.throwIfError(sendRet, 'Failed to send packet to bitstream filter');
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Send a packet to the filter synchronously.
|
|
345
|
+
* Synchronous version of filter.
|
|
346
|
+
*
|
|
347
|
+
* Sends a packet to the filter for processing.
|
|
348
|
+
* Does not return filtered packets - use {@link receiveSync} to retrieve packets.
|
|
349
|
+
* A single packet can produce zero, one, or multiple packets depending on filter.
|
|
350
|
+
*
|
|
351
|
+
* **Important**: This method only SENDS the packet to the filter.
|
|
352
|
+
* You must call {@link receiveSync} separately (potentially multiple times) to get filtered packets.
|
|
353
|
+
*
|
|
354
|
+
* Direct mapping to av_bsf_send_packet().
|
|
355
|
+
*
|
|
356
|
+
* @param packet - Packet to send to filter, or null to flush
|
|
357
|
+
*
|
|
358
|
+
* @throws {FFmpegError} If sending fails
|
|
359
|
+
*
|
|
360
|
+
* @example
|
|
361
|
+
* ```typescript
|
|
362
|
+
* // Send packet and receive filtered packets
|
|
363
|
+
* filter.filterSync(inputPacket);
|
|
364
|
+
*
|
|
365
|
+
* // Receive all available filtered packets
|
|
366
|
+
* while (true) {
|
|
367
|
+
* const outPacket = filter.receiveSync();
|
|
368
|
+
* if (!outPacket) break;
|
|
369
|
+
* console.log(`Filtered packet with PTS: ${outPacket.pts}`);
|
|
370
|
+
* output.writePacketSync(outPacket);
|
|
371
|
+
* outPacket.free();
|
|
372
|
+
* }
|
|
373
|
+
* ```
|
|
374
|
+
*
|
|
375
|
+
* @example
|
|
376
|
+
* ```typescript
|
|
377
|
+
* for (const packet of packets) {
|
|
378
|
+
* // packet is null at end of stream - automatically flushes filter
|
|
379
|
+
* filter.filterSync(packet);
|
|
380
|
+
*
|
|
381
|
+
* // Receive available filtered packets
|
|
382
|
+
* let outPacket;
|
|
383
|
+
* while ((outPacket = filter.receiveSync())) {
|
|
384
|
+
* output.writePacketSync(outPacket);
|
|
385
|
+
* outPacket.free();
|
|
386
|
+
* }
|
|
387
|
+
* }
|
|
388
|
+
* ```
|
|
389
|
+
*
|
|
390
|
+
* @see {@link receiveSync} For receiving filtered packets
|
|
391
|
+
* @see {@link filterAllSync} For combined send+receive operation
|
|
392
|
+
* @see {@link packetsSync} For automatic packet iteration
|
|
393
|
+
* @see {@link flushSync} For end-of-stream handling
|
|
394
|
+
* @see {@link filter} For async version
|
|
395
|
+
*/
|
|
396
|
+
filterSync(packet) {
|
|
397
|
+
if (this.isClosed) {
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
// Send packet to filter (null signals EOF/flush)
|
|
401
|
+
const sendRet = this.ctx.sendPacketSync(packet);
|
|
402
|
+
if (sendRet < 0 && sendRet !== AVERROR_EOF && sendRet !== AVERROR_EAGAIN) {
|
|
403
|
+
FFmpegError.throwIfError(sendRet, 'Failed to send packet to bitstream filter');
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Filter a packet to packets.
|
|
408
|
+
*
|
|
409
|
+
* Sends a packet to the filter and receives all available filtered packets.
|
|
410
|
+
* Returns array of packets - may be empty if filter needs more data.
|
|
411
|
+
* One packet can produce zero, one, or multiple packets depending on filter.
|
|
412
|
+
*
|
|
413
|
+
* Direct mapping to av_bsf_send_packet() and av_bsf_receive_packet().
|
|
414
|
+
*
|
|
415
|
+
* @param packet - Packet to filter, or null to flush
|
|
416
|
+
*
|
|
417
|
+
* @returns Array of filtered packets (empty if more data needed or filter is closed)
|
|
418
|
+
*
|
|
419
|
+
* @throws {FFmpegError} If filtering fails
|
|
420
|
+
*
|
|
421
|
+
* @example
|
|
422
|
+
* ```typescript
|
|
423
|
+
* const outputPackets = await filter.filterAll(inputPacket);
|
|
424
|
+
* for (const packet of outputPackets) {
|
|
425
|
+
* console.log(`Filtered packet: pts=${packet.pts}`);
|
|
426
|
+
* await output.writePacket(packet);
|
|
427
|
+
* packet.free();
|
|
428
|
+
* }
|
|
429
|
+
* ```
|
|
430
|
+
*
|
|
431
|
+
* @example
|
|
432
|
+
* ```typescript
|
|
433
|
+
* // Flush remaining packets at end of stream
|
|
434
|
+
* const remaining = await filter.filterAll(null);
|
|
435
|
+
* for (const packet of remaining) {
|
|
436
|
+
* await output.writePacket(packet);
|
|
437
|
+
* packet.free();
|
|
438
|
+
* }
|
|
439
|
+
* ```
|
|
440
|
+
*
|
|
441
|
+
* @see {@link filter} For single packet filtering
|
|
442
|
+
* @see {@link packets} For stream processing
|
|
443
|
+
* @see {@link flush} For end-of-stream handling
|
|
444
|
+
* @see {@link filterAllSync} For synchronous version
|
|
445
|
+
*/
|
|
446
|
+
async filterAll(packet) {
|
|
447
|
+
this.signal?.throwIfAborted();
|
|
448
|
+
await this.filter(packet);
|
|
449
|
+
// Receive all output packets
|
|
450
|
+
const outputPackets = [];
|
|
451
|
+
while (true) {
|
|
452
|
+
const outPacket = await this.receive();
|
|
453
|
+
if (!outPacket)
|
|
454
|
+
break;
|
|
455
|
+
outputPackets.push(outPacket);
|
|
456
|
+
}
|
|
457
|
+
return outputPackets;
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Filter a packet to packets synchronously.
|
|
461
|
+
* Synchronous version of filterAll.
|
|
462
|
+
*
|
|
463
|
+
* Sends a packet to the filter and receives all available filtered packets.
|
|
464
|
+
* Returns array of packets - may be empty if filter needs more data.
|
|
465
|
+
* One packet can produce zero, one, or multiple packets depending on filter.
|
|
466
|
+
*
|
|
467
|
+
* Direct mapping to av_bsf_send_packet() and av_bsf_receive_packet().
|
|
468
|
+
*
|
|
469
|
+
* @param packet - Packet to filter, or null to flush
|
|
470
|
+
*
|
|
471
|
+
* @returns Array of filtered packets (empty if more data needed or filter is closed)
|
|
472
|
+
*
|
|
473
|
+
* @throws {FFmpegError} If filtering fails
|
|
474
|
+
*
|
|
475
|
+
* @example
|
|
476
|
+
* ```typescript
|
|
477
|
+
* const outputPackets = filter.filterAllSync(inputPacket);
|
|
478
|
+
* for (const packet of outputPackets) {
|
|
479
|
+
* console.log(`Filtered packet: pts=${packet.pts}`);
|
|
480
|
+
* output.writePacketSync(packet);
|
|
481
|
+
* packet.free();
|
|
482
|
+
* }
|
|
483
|
+
* ```
|
|
484
|
+
*
|
|
485
|
+
* @example
|
|
486
|
+
* ```typescript
|
|
487
|
+
* // Flush remaining packets at end of stream
|
|
488
|
+
* const remaining = filter.filterAllSync(null);
|
|
489
|
+
* for (const packet of remaining) {
|
|
490
|
+
* output.writePacketSync(packet);
|
|
491
|
+
* packet.free();
|
|
492
|
+
* }
|
|
493
|
+
* ```
|
|
494
|
+
*
|
|
495
|
+
* @see {@link filterSync} For single packet filtering
|
|
496
|
+
* @see {@link packetsSync} For stream processing
|
|
497
|
+
* @see {@link flushSync} For end-of-stream handling
|
|
498
|
+
* @see {@link filterAll} For async version
|
|
499
|
+
*/
|
|
500
|
+
filterAllSync(packet) {
|
|
501
|
+
this.filterSync(packet);
|
|
502
|
+
// Receive all output packets
|
|
503
|
+
const outputPackets = [];
|
|
504
|
+
while (true) {
|
|
505
|
+
const outPacket = this.receiveSync();
|
|
506
|
+
if (!outPacket)
|
|
507
|
+
break;
|
|
508
|
+
outputPackets.push(outPacket);
|
|
509
|
+
}
|
|
510
|
+
return outputPackets;
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* Filter packet stream to filtered packet stream.
|
|
514
|
+
*
|
|
515
|
+
* High-level async generator for complete filtering pipeline.
|
|
516
|
+
* Filter is only flushed when EOF (null) signal is explicitly received.
|
|
517
|
+
* Primary interface for stream-based filtering.
|
|
518
|
+
*
|
|
519
|
+
* **EOF Handling:**
|
|
520
|
+
* - Send null to flush filter and get remaining buffered packets
|
|
521
|
+
* - Generator yields null after flushing when null is received
|
|
522
|
+
* - No automatic flushing - filter stays open until EOF or close()
|
|
523
|
+
*
|
|
524
|
+
* @param packets - Async iterable of packets, single packet, or null to flush
|
|
525
|
+
*
|
|
526
|
+
* @yields {Packet | null} Filtered packets, followed by null when explicitly flushed
|
|
527
|
+
*
|
|
528
|
+
* @throws {FFmpegError} If filtering fails
|
|
529
|
+
*
|
|
530
|
+
* @example
|
|
531
|
+
* ```typescript
|
|
532
|
+
* // Stream of packets with automatic EOF propagation
|
|
533
|
+
* for await (const packet of filter.packets(input.packets())) {
|
|
534
|
+
* if (packet === null) {
|
|
535
|
+
* console.log('Filter flushed');
|
|
536
|
+
* break;
|
|
537
|
+
* }
|
|
538
|
+
* await output.writePacket(packet);
|
|
539
|
+
* packet.free(); // Must free output packets
|
|
540
|
+
* }
|
|
541
|
+
* ```
|
|
542
|
+
*
|
|
543
|
+
* @example
|
|
544
|
+
* ```typescript
|
|
545
|
+
* // Single packet - no automatic flush
|
|
546
|
+
* for await (const packet of filter.packets(singlePacket)) {
|
|
547
|
+
* await output.writePacket(packet);
|
|
548
|
+
* packet.free();
|
|
549
|
+
* }
|
|
550
|
+
* // Filter remains open, buffered packets not flushed
|
|
551
|
+
* ```
|
|
552
|
+
*
|
|
553
|
+
* @example
|
|
554
|
+
* ```typescript
|
|
555
|
+
* // Explicit flush with EOF
|
|
556
|
+
* for await (const packet of filter.packets(null)) {
|
|
557
|
+
* if (packet === null) {
|
|
558
|
+
* console.log('All buffered packets flushed');
|
|
559
|
+
* break;
|
|
560
|
+
* }
|
|
561
|
+
* console.log('Buffered packet:', packet.pts);
|
|
562
|
+
* await output.writePacket(packet);
|
|
563
|
+
* packet.free();
|
|
564
|
+
* }
|
|
565
|
+
* ```
|
|
566
|
+
*
|
|
567
|
+
* @see {@link filter} For single packet filtering
|
|
568
|
+
* @see {@link Demuxer.packets} For packet source
|
|
569
|
+
* @see {@link packetsSync} For sync version
|
|
570
|
+
*/
|
|
571
|
+
async *packets(packets) {
|
|
572
|
+
const self = this;
|
|
573
|
+
const processPacket = async function* (packet) {
|
|
574
|
+
await self.filter(packet);
|
|
575
|
+
while (true) {
|
|
576
|
+
const outPacket = await self.receive();
|
|
577
|
+
if (!outPacket)
|
|
578
|
+
break;
|
|
579
|
+
yield outPacket;
|
|
580
|
+
}
|
|
581
|
+
}.bind(this);
|
|
582
|
+
const finalize = async function* () {
|
|
583
|
+
for await (const remaining of self.flushPackets()) {
|
|
584
|
+
yield remaining;
|
|
585
|
+
}
|
|
586
|
+
yield null;
|
|
587
|
+
}.bind(this);
|
|
588
|
+
if (packets === null) {
|
|
589
|
+
yield* finalize();
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
592
|
+
if (packets instanceof Packet) {
|
|
593
|
+
yield* processPacket(packets);
|
|
594
|
+
return;
|
|
595
|
+
}
|
|
596
|
+
for await (const packet_1 of packets) {
|
|
597
|
+
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
598
|
+
try {
|
|
599
|
+
const packet = __addDisposableResource(env_1, packet_1, false);
|
|
600
|
+
this.signal?.throwIfAborted();
|
|
601
|
+
if (packet === null) {
|
|
602
|
+
yield* finalize();
|
|
603
|
+
return;
|
|
604
|
+
}
|
|
605
|
+
yield* processPacket(packet);
|
|
606
|
+
}
|
|
607
|
+
catch (e_1) {
|
|
608
|
+
env_1.error = e_1;
|
|
609
|
+
env_1.hasError = true;
|
|
610
|
+
}
|
|
611
|
+
finally {
|
|
612
|
+
__disposeResources(env_1);
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
/**
|
|
617
|
+
* Filter packet stream to filtered packet stream synchronously.
|
|
618
|
+
* Synchronous version of packets.
|
|
619
|
+
*
|
|
620
|
+
* High-level sync generator for complete filtering pipeline.
|
|
621
|
+
* Filter is only flushed when EOF (null) signal is explicitly received.
|
|
622
|
+
* Primary interface for stream-based filtering.
|
|
623
|
+
*
|
|
624
|
+
* **EOF Handling:**
|
|
625
|
+
* - Send null to flush filter and get remaining buffered packets
|
|
626
|
+
* - Generator yields null after flushing when null is received
|
|
627
|
+
* - No automatic flushing - filter stays open until EOF or close()
|
|
628
|
+
*
|
|
629
|
+
* @param packets - Iterable of packets, single packet, or null to flush
|
|
630
|
+
*
|
|
631
|
+
* @yields {Packet | null} Filtered packets, followed by null when explicitly flushed
|
|
632
|
+
*
|
|
633
|
+
* @throws {FFmpegError} If filtering fails
|
|
634
|
+
*
|
|
635
|
+
* @example
|
|
636
|
+
* ```typescript
|
|
637
|
+
* // Stream of packets with automatic EOF propagation
|
|
638
|
+
* for (const packet of filter.packetsSync(inputPackets)) {
|
|
639
|
+
* if (packet === null) {
|
|
640
|
+
* console.log('Filter flushed');
|
|
641
|
+
* break;
|
|
642
|
+
* }
|
|
643
|
+
* output.writePacketSync(packet);
|
|
644
|
+
* packet.free(); // Must free output packets
|
|
645
|
+
* }
|
|
646
|
+
* ```
|
|
647
|
+
*
|
|
648
|
+
* @example
|
|
649
|
+
* ```typescript
|
|
650
|
+
* // Single packet - no automatic flush
|
|
651
|
+
* for (const packet of filter.packetsSync(singlePacket)) {
|
|
652
|
+
* output.writePacketSync(packet);
|
|
653
|
+
* packet.free();
|
|
654
|
+
* }
|
|
655
|
+
* // Filter remains open, buffered packets not flushed
|
|
656
|
+
* ```
|
|
657
|
+
*
|
|
658
|
+
* @example
|
|
659
|
+
* ```typescript
|
|
660
|
+
* // Explicit flush with EOF
|
|
661
|
+
* for (const packet of filter.packetsSync(null)) {
|
|
662
|
+
* if (packet === null) {
|
|
663
|
+
* console.log('All buffered packets flushed');
|
|
664
|
+
* break;
|
|
665
|
+
* }
|
|
666
|
+
* console.log('Buffered packet:', packet.pts);
|
|
667
|
+
* output.writePacketSync(packet);
|
|
668
|
+
* packet.free();
|
|
669
|
+
* }
|
|
670
|
+
* ```
|
|
671
|
+
*
|
|
672
|
+
* @see {@link filterSync} For single packet filtering
|
|
673
|
+
* @see {@link packets} For async version
|
|
674
|
+
*/
|
|
675
|
+
*packetsSync(packets) {
|
|
676
|
+
const self = this;
|
|
677
|
+
const processPacket = function* (packet) {
|
|
678
|
+
self.filterSync(packet);
|
|
679
|
+
while (true) {
|
|
680
|
+
const outPacket = self.receiveSync();
|
|
681
|
+
if (!outPacket)
|
|
682
|
+
break;
|
|
683
|
+
yield outPacket;
|
|
684
|
+
}
|
|
685
|
+
}.bind(this);
|
|
686
|
+
const finalize = function* () {
|
|
687
|
+
for (const remaining of self.flushPacketsSync()) {
|
|
688
|
+
yield remaining;
|
|
689
|
+
}
|
|
690
|
+
yield null;
|
|
691
|
+
}.bind(this);
|
|
692
|
+
if (packets === null) {
|
|
693
|
+
yield* finalize();
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
if (packets instanceof Packet) {
|
|
697
|
+
yield* processPacket(packets);
|
|
698
|
+
return;
|
|
699
|
+
}
|
|
700
|
+
for (const packet_2 of packets) {
|
|
701
|
+
const env_2 = { stack: [], error: void 0, hasError: false };
|
|
702
|
+
try {
|
|
703
|
+
const packet = __addDisposableResource(env_2, packet_2, false);
|
|
704
|
+
if (packet === null) {
|
|
705
|
+
yield* finalize();
|
|
706
|
+
return;
|
|
707
|
+
}
|
|
708
|
+
yield* processPacket(packet);
|
|
709
|
+
}
|
|
710
|
+
catch (e_2) {
|
|
711
|
+
env_2.error = e_2;
|
|
712
|
+
env_2.hasError = true;
|
|
713
|
+
}
|
|
714
|
+
finally {
|
|
715
|
+
__disposeResources(env_2);
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
/**
|
|
720
|
+
* Flush filter and signal end-of-stream.
|
|
721
|
+
*
|
|
722
|
+
* Sends null packet to filter to signal end-of-stream.
|
|
723
|
+
* Does nothing if filter is closed.
|
|
724
|
+
* Must call receive() or flushPackets() to get remaining buffered packets.
|
|
725
|
+
*
|
|
726
|
+
* Direct mapping to av_bsf_send_packet(NULL) and av_bsf_flush().
|
|
727
|
+
*
|
|
728
|
+
* @throws {FFmpegError} If flush fails
|
|
729
|
+
*
|
|
730
|
+
* @example
|
|
731
|
+
* ```typescript
|
|
732
|
+
* // Signal end of stream
|
|
733
|
+
* await filter.flush();
|
|
734
|
+
*
|
|
735
|
+
* // Then get remaining packets
|
|
736
|
+
* let packet;
|
|
737
|
+
* while ((packet = await filter.receive()) !== null) {
|
|
738
|
+
* console.log('Got buffered packet');
|
|
739
|
+
* await output.writePacket(packet);
|
|
740
|
+
* packet.free();
|
|
741
|
+
* }
|
|
742
|
+
* ```
|
|
743
|
+
*
|
|
744
|
+
* @see {@link flushPackets} For async iteration
|
|
745
|
+
* @see {@link receive} For getting buffered packets
|
|
746
|
+
* @see {@link reset} For state reset only
|
|
747
|
+
* @see {@link flushSync} For synchronous version
|
|
748
|
+
*/
|
|
749
|
+
async flush() {
|
|
750
|
+
this.signal?.throwIfAborted();
|
|
751
|
+
if (this.isClosed) {
|
|
752
|
+
return;
|
|
753
|
+
}
|
|
754
|
+
// Send EOF
|
|
755
|
+
const sendRet = await this.ctx.sendPacket(null);
|
|
756
|
+
if (sendRet < 0 && sendRet !== AVERROR_EOF && sendRet !== AVERROR_EAGAIN) {
|
|
757
|
+
FFmpegError.throwIfError(sendRet, 'Failed to flush bitstream filter');
|
|
758
|
+
}
|
|
759
|
+
// Also flush the context to reset internal state
|
|
760
|
+
this.ctx.flush();
|
|
761
|
+
}
|
|
762
|
+
/**
|
|
763
|
+
* Flush filter and signal end-of-stream synchronously.
|
|
764
|
+
* Synchronous version of flush.
|
|
765
|
+
*
|
|
766
|
+
* Sends null packet to filter to signal end-of-stream.
|
|
767
|
+
* Does nothing if filter is closed.
|
|
768
|
+
* Must call receiveSync() or flushPacketsSync() to get remaining buffered packets.
|
|
769
|
+
*
|
|
770
|
+
* Direct mapping to av_bsf_send_packet(NULL) and av_bsf_flush().
|
|
771
|
+
*
|
|
772
|
+
* @throws {FFmpegError} If flush fails
|
|
773
|
+
*
|
|
774
|
+
* @example
|
|
775
|
+
* ```typescript
|
|
776
|
+
* // Signal end of stream
|
|
777
|
+
* filter.flushSync();
|
|
778
|
+
*
|
|
779
|
+
* // Then get remaining packets
|
|
780
|
+
* let packet;
|
|
781
|
+
* while ((packet = filter.receiveSync()) !== null) {
|
|
782
|
+
* console.log('Got buffered packet');
|
|
783
|
+
* output.writePacketSync(packet);
|
|
784
|
+
* packet.free();
|
|
785
|
+
* }
|
|
786
|
+
* ```
|
|
787
|
+
*
|
|
788
|
+
* @see {@link flushPacketsSync} For sync iteration
|
|
789
|
+
* @see {@link receiveSync} For getting buffered packets
|
|
790
|
+
* @see {@link reset} For state reset only
|
|
791
|
+
* @see {@link flush} For async version
|
|
792
|
+
*/
|
|
793
|
+
flushSync() {
|
|
794
|
+
if (this.isClosed) {
|
|
795
|
+
return;
|
|
796
|
+
}
|
|
797
|
+
// Send EOF
|
|
798
|
+
const sendRet = this.ctx.sendPacketSync(null);
|
|
799
|
+
if (sendRet < 0 && sendRet !== AVERROR_EOF && sendRet !== AVERROR_EAGAIN) {
|
|
800
|
+
FFmpegError.throwIfError(sendRet, 'Failed to flush bitstream filter');
|
|
801
|
+
}
|
|
802
|
+
// Also flush the context to reset internal state
|
|
803
|
+
this.ctx.flush();
|
|
804
|
+
}
|
|
805
|
+
/**
|
|
806
|
+
* Receive packet from filter.
|
|
807
|
+
*
|
|
808
|
+
* Gets filtered packets from the filter's internal buffer.
|
|
809
|
+
* Handles packet allocation and error checking.
|
|
810
|
+
* Returns null if filter is closed or no packets available.
|
|
811
|
+
* Call repeatedly until null to drain all buffered packets.
|
|
812
|
+
*
|
|
813
|
+
* Direct mapping to av_bsf_receive_packet().
|
|
814
|
+
*
|
|
815
|
+
* @returns Cloned packet or null if no packets available
|
|
816
|
+
*
|
|
817
|
+
* @throws {FFmpegError} If receive fails with error other than AVERROR_EAGAIN or AVERROR_EOF
|
|
818
|
+
*
|
|
819
|
+
* @throws {Error} If packet cloning fails (out of memory)
|
|
820
|
+
*
|
|
821
|
+
* @example
|
|
822
|
+
* ```typescript
|
|
823
|
+
* const packet = await filter.receive();
|
|
824
|
+
* if (packet) {
|
|
825
|
+
* console.log('Got filtered packet');
|
|
826
|
+
* await output.writePacket(packet);
|
|
827
|
+
* packet.free();
|
|
828
|
+
* }
|
|
829
|
+
* ```
|
|
830
|
+
*
|
|
831
|
+
* @example
|
|
832
|
+
* ```typescript
|
|
833
|
+
* // Drain all buffered packets
|
|
834
|
+
* let packet;
|
|
835
|
+
* while ((packet = await filter.receive()) !== null) {
|
|
836
|
+
* console.log(`Packet PTS: ${packet.pts}`);
|
|
837
|
+
* await output.writePacket(packet);
|
|
838
|
+
* packet.free();
|
|
839
|
+
* }
|
|
840
|
+
* ```
|
|
841
|
+
*
|
|
842
|
+
* @see {@link filter} For filtering packets
|
|
843
|
+
* @see {@link flush} For signaling end-of-stream
|
|
844
|
+
* @see {@link receiveSync} For synchronous version
|
|
845
|
+
*/
|
|
846
|
+
async receive() {
|
|
847
|
+
if (this.isClosed) {
|
|
848
|
+
return null;
|
|
849
|
+
}
|
|
850
|
+
// Clear previous packet data
|
|
851
|
+
this.packet.unref();
|
|
852
|
+
const recvRet = await this.ctx.receivePacket(this.packet);
|
|
853
|
+
if (recvRet === 0) {
|
|
854
|
+
// Got a packet, clone it for the user
|
|
855
|
+
const cloned = this.packet.clone();
|
|
856
|
+
if (!cloned) {
|
|
857
|
+
throw new Error('Failed to clone packet (out of memory)');
|
|
858
|
+
}
|
|
859
|
+
return cloned;
|
|
860
|
+
}
|
|
861
|
+
else if (recvRet === AVERROR_EAGAIN || recvRet === AVERROR_EOF) {
|
|
862
|
+
// Need more data or end of stream
|
|
863
|
+
return null;
|
|
864
|
+
}
|
|
865
|
+
else {
|
|
866
|
+
// Error
|
|
867
|
+
FFmpegError.throwIfError(recvRet, 'Failed to receive packet from bitstream filter');
|
|
868
|
+
return null;
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
/**
|
|
872
|
+
* Receive packet from filter synchronously.
|
|
873
|
+
* Synchronous version of receive.
|
|
874
|
+
*
|
|
875
|
+
* Gets filtered packets from the filter's internal buffer.
|
|
876
|
+
* Handles packet allocation and error checking.
|
|
877
|
+
* Returns null if filter is closed or no packets available.
|
|
878
|
+
* Call repeatedly until null to drain all buffered packets.
|
|
879
|
+
*
|
|
880
|
+
* Direct mapping to av_bsf_receive_packet().
|
|
881
|
+
*
|
|
882
|
+
* @returns Cloned packet or null if no packets available
|
|
883
|
+
*
|
|
884
|
+
* @throws {FFmpegError} If receive fails with error other than AVERROR_EAGAIN or AVERROR_EOF
|
|
885
|
+
*
|
|
886
|
+
* @throws {Error} If packet cloning fails (out of memory)
|
|
887
|
+
*
|
|
888
|
+
* @example
|
|
889
|
+
* ```typescript
|
|
890
|
+
* const packet = filter.receiveSync();
|
|
891
|
+
* if (packet) {
|
|
892
|
+
* console.log('Got filtered packet');
|
|
893
|
+
* output.writePacketSync(packet);
|
|
894
|
+
* packet.free();
|
|
895
|
+
* }
|
|
896
|
+
* ```
|
|
897
|
+
*
|
|
898
|
+
* @example
|
|
899
|
+
* ```typescript
|
|
900
|
+
* // Drain all buffered packets
|
|
901
|
+
* let packet;
|
|
902
|
+
* while ((packet = filter.receiveSync()) !== null) {
|
|
903
|
+
* console.log(`Packet PTS: ${packet.pts}`);
|
|
904
|
+
* output.writePacketSync(packet);
|
|
905
|
+
* packet.free();
|
|
906
|
+
* }
|
|
907
|
+
* ```
|
|
908
|
+
*
|
|
909
|
+
* @see {@link filterSync} For filtering packets
|
|
910
|
+
* @see {@link flushSync} For signaling end-of-stream
|
|
911
|
+
* @see {@link receive} For async version
|
|
912
|
+
*/
|
|
913
|
+
receiveSync() {
|
|
914
|
+
if (this.isClosed) {
|
|
915
|
+
return null;
|
|
916
|
+
}
|
|
917
|
+
// Clear previous packet data
|
|
918
|
+
this.packet.unref();
|
|
919
|
+
const recvRet = this.ctx.receivePacketSync(this.packet);
|
|
920
|
+
if (recvRet === 0) {
|
|
921
|
+
// Got a packet, clone it for the user
|
|
922
|
+
const cloned = this.packet.clone();
|
|
923
|
+
if (!cloned) {
|
|
924
|
+
throw new Error('Failed to clone packet (out of memory)');
|
|
925
|
+
}
|
|
926
|
+
return cloned;
|
|
927
|
+
}
|
|
928
|
+
else if (recvRet === AVERROR_EAGAIN || recvRet === AVERROR_EOF) {
|
|
929
|
+
// Need more data or end of stream
|
|
930
|
+
return null;
|
|
931
|
+
}
|
|
932
|
+
else {
|
|
933
|
+
// Error
|
|
934
|
+
FFmpegError.throwIfError(recvRet, 'Failed to receive packet from bitstream filter');
|
|
935
|
+
return null;
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
/**
|
|
939
|
+
* Flush all buffered packets as async generator.
|
|
940
|
+
*
|
|
941
|
+
* Convenient async iteration over remaining packets.
|
|
942
|
+
* Automatically sends flush signal and retrieves buffered packets.
|
|
943
|
+
* Useful for end-of-stream processing.
|
|
944
|
+
*
|
|
945
|
+
* @yields {Packet} Buffered packets
|
|
946
|
+
*
|
|
947
|
+
* @example
|
|
948
|
+
* ```typescript
|
|
949
|
+
* // Flush at end of filtering
|
|
950
|
+
* for await (const packet of filter.flushPackets()) {
|
|
951
|
+
* console.log('Processing buffered packet');
|
|
952
|
+
* await output.writePacket(packet);
|
|
953
|
+
* packet.free();
|
|
954
|
+
* }
|
|
955
|
+
* ```
|
|
956
|
+
*
|
|
957
|
+
* @see {@link filter} For filtering packets
|
|
958
|
+
* @see {@link flush} For signaling end-of-stream
|
|
959
|
+
* @see {@link flushPacketsSync} For synchronous version
|
|
960
|
+
*/
|
|
961
|
+
async *flushPackets() {
|
|
962
|
+
while (true) {
|
|
963
|
+
const packet = await this.receive();
|
|
964
|
+
if (!packet)
|
|
965
|
+
break;
|
|
966
|
+
yield packet;
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
/**
|
|
970
|
+
* Flush all buffered packets as generator synchronously.
|
|
971
|
+
* Synchronous version of flushPackets.
|
|
972
|
+
*
|
|
973
|
+
* Convenient sync iteration over remaining packets.
|
|
974
|
+
* Automatically retrieves buffered packets after flush.
|
|
975
|
+
* Useful for end-of-stream processing.
|
|
976
|
+
*
|
|
977
|
+
* @yields {Packet} Buffered packets
|
|
978
|
+
*
|
|
979
|
+
* @example
|
|
980
|
+
* ```typescript
|
|
981
|
+
* // Flush at end of filtering
|
|
982
|
+
* for (const packet of filter.flushPacketsSync()) {
|
|
983
|
+
* console.log('Processing buffered packet');
|
|
984
|
+
* output.writePacketSync(packet);
|
|
985
|
+
* packet.free();
|
|
986
|
+
* }
|
|
987
|
+
* ```
|
|
988
|
+
*
|
|
989
|
+
* @see {@link filterSync} For filtering packets
|
|
990
|
+
* @see {@link flushSync} For signaling end-of-stream
|
|
991
|
+
* @see {@link flushPackets} For async version
|
|
992
|
+
*/
|
|
993
|
+
*flushPacketsSync() {
|
|
994
|
+
while (true) {
|
|
995
|
+
const packet = this.receiveSync();
|
|
996
|
+
if (!packet)
|
|
997
|
+
break;
|
|
998
|
+
yield packet;
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
/**
|
|
1002
|
+
* Get associated stream.
|
|
1003
|
+
*
|
|
1004
|
+
* Returns the stream this filter was created for.
|
|
1005
|
+
*
|
|
1006
|
+
* @returns Associated stream
|
|
1007
|
+
*
|
|
1008
|
+
* @example
|
|
1009
|
+
* ```typescript
|
|
1010
|
+
* const stream = filter.getStream();
|
|
1011
|
+
* console.log(`Filtering stream ${stream.index}`);
|
|
1012
|
+
* ```
|
|
1013
|
+
*/
|
|
1014
|
+
getStream() {
|
|
1015
|
+
return this.stream;
|
|
1016
|
+
}
|
|
1017
|
+
/**
|
|
1018
|
+
* Reset filter state.
|
|
1019
|
+
*
|
|
1020
|
+
* Clears internal buffers and resets filter.
|
|
1021
|
+
* Does not dispose resources.
|
|
1022
|
+
*
|
|
1023
|
+
* Direct mapping to av_bsf_flush().
|
|
1024
|
+
*
|
|
1025
|
+
* @example
|
|
1026
|
+
* ```typescript
|
|
1027
|
+
* // Reset for new segment
|
|
1028
|
+
* filter.reset();
|
|
1029
|
+
* ```
|
|
1030
|
+
*
|
|
1031
|
+
* @see {@link flush} For reset with packet retrieval
|
|
1032
|
+
*/
|
|
1033
|
+
reset() {
|
|
1034
|
+
if (this.isClosed) {
|
|
1035
|
+
return;
|
|
1036
|
+
}
|
|
1037
|
+
this.ctx.flush();
|
|
1038
|
+
}
|
|
1039
|
+
/**
|
|
1040
|
+
* Close filter and free resources.
|
|
1041
|
+
*
|
|
1042
|
+
* Releases filter context and marks as closed.
|
|
1043
|
+
* Safe to call multiple times.
|
|
1044
|
+
*
|
|
1045
|
+
* @example
|
|
1046
|
+
* ```typescript
|
|
1047
|
+
* filter.close();
|
|
1048
|
+
* ```
|
|
1049
|
+
*
|
|
1050
|
+
* @see {@link Symbol.dispose} For automatic cleanup
|
|
1051
|
+
*/
|
|
1052
|
+
close() {
|
|
1053
|
+
if (this.isClosed) {
|
|
1054
|
+
return;
|
|
1055
|
+
}
|
|
1056
|
+
this.isClosed = true;
|
|
1057
|
+
// Close queues
|
|
1058
|
+
this.inputQueue.close();
|
|
1059
|
+
this.outputQueue.close();
|
|
1060
|
+
this.packet.free();
|
|
1061
|
+
this.ctx.free();
|
|
1062
|
+
}
|
|
1063
|
+
/**
|
|
1064
|
+
* Dispose of filter.
|
|
1065
|
+
*
|
|
1066
|
+
* Implements Disposable interface for automatic cleanup.
|
|
1067
|
+
* Equivalent to calling dispose().
|
|
1068
|
+
*
|
|
1069
|
+
* @example
|
|
1070
|
+
* ```typescript
|
|
1071
|
+
* {
|
|
1072
|
+
* using filter = BitStreamFilterAPI.create('h264_mp4toannexb', stream);
|
|
1073
|
+
* // Use filter...
|
|
1074
|
+
* } // Automatically disposed
|
|
1075
|
+
* ```
|
|
1076
|
+
*
|
|
1077
|
+
* @see {@link close} For manual cleanup
|
|
1078
|
+
*/
|
|
1079
|
+
[Symbol.dispose]() {
|
|
1080
|
+
this.close();
|
|
1081
|
+
}
|
|
1082
|
+
/**
|
|
1083
|
+
* Send packet to input queue or flush the pipeline.
|
|
1084
|
+
*
|
|
1085
|
+
* When packet is provided, queues it for filtering.
|
|
1086
|
+
* When null is provided, triggers flush sequence:
|
|
1087
|
+
* - Closes input queue
|
|
1088
|
+
* - Waits for worker completion
|
|
1089
|
+
* - Closes output queue (no buffering, bitstream filters are stateless)
|
|
1090
|
+
* - Waits for pipeTo task completion
|
|
1091
|
+
* - Propagates flush to next component (if any)
|
|
1092
|
+
*
|
|
1093
|
+
* Used by scheduler system for pipeline control.
|
|
1094
|
+
*
|
|
1095
|
+
* @param packet - Packet to send, or null to flush
|
|
1096
|
+
*
|
|
1097
|
+
* @internal
|
|
1098
|
+
*/
|
|
1099
|
+
async sendToQueue(packet) {
|
|
1100
|
+
if (packet) {
|
|
1101
|
+
await this.inputQueue.send(packet);
|
|
1102
|
+
}
|
|
1103
|
+
else {
|
|
1104
|
+
// Close input queue to signal end of stream to worker
|
|
1105
|
+
this.inputQueue.close();
|
|
1106
|
+
// Wait for worker to finish processing all packets
|
|
1107
|
+
if (this.workerPromise) {
|
|
1108
|
+
await this.workerPromise;
|
|
1109
|
+
}
|
|
1110
|
+
// Close output queue to signal end of stream to pipeTo() task
|
|
1111
|
+
this.outputQueue.close();
|
|
1112
|
+
// Wait for pipeTo() task to finish processing all packets (if exists)
|
|
1113
|
+
if (this.pipeToPromise) {
|
|
1114
|
+
await this.pipeToPromise;
|
|
1115
|
+
}
|
|
1116
|
+
// Then propagate flush to next component
|
|
1117
|
+
if (this.nextComponent) {
|
|
1118
|
+
await this.nextComponent.sendToQueue(null);
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
/**
|
|
1123
|
+
* Receive packet from output queue.
|
|
1124
|
+
*
|
|
1125
|
+
* @returns Packet from queue or null if closed
|
|
1126
|
+
*
|
|
1127
|
+
* @internal
|
|
1128
|
+
*/
|
|
1129
|
+
async receiveFromQueue() {
|
|
1130
|
+
return await this.outputQueue.receive();
|
|
1131
|
+
}
|
|
1132
|
+
/**
|
|
1133
|
+
* Worker loop for push-based processing.
|
|
1134
|
+
*
|
|
1135
|
+
* @internal
|
|
1136
|
+
*/
|
|
1137
|
+
async runWorker() {
|
|
1138
|
+
try {
|
|
1139
|
+
// Outer loop - receive packets
|
|
1140
|
+
while (!this.inputQueue.isClosed) {
|
|
1141
|
+
const env_3 = { stack: [], error: void 0, hasError: false };
|
|
1142
|
+
try {
|
|
1143
|
+
const packet = __addDisposableResource(env_3, await this.inputQueue.receive(), false);
|
|
1144
|
+
if (!packet)
|
|
1145
|
+
break;
|
|
1146
|
+
if (this.isClosed) {
|
|
1147
|
+
break;
|
|
1148
|
+
}
|
|
1149
|
+
// Send packet to filter
|
|
1150
|
+
const sendRet = await this.ctx.sendPacket(packet);
|
|
1151
|
+
// Handle EAGAIN
|
|
1152
|
+
if (sendRet === AVERROR_EAGAIN) {
|
|
1153
|
+
// Filter buffer full, receive packets first
|
|
1154
|
+
while (!this.outputQueue.isClosed) {
|
|
1155
|
+
const outPacket = await this.receive();
|
|
1156
|
+
if (!outPacket)
|
|
1157
|
+
break;
|
|
1158
|
+
await this.outputQueue.send(outPacket);
|
|
1159
|
+
}
|
|
1160
|
+
// Retry sending
|
|
1161
|
+
const retryRet = await this.ctx.sendPacket(packet);
|
|
1162
|
+
if (retryRet < 0 && retryRet !== AVERROR_EOF && retryRet !== AVERROR_EAGAIN) {
|
|
1163
|
+
FFmpegError.throwIfError(retryRet, 'Failed to send packet to bitstream filter');
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
else if (sendRet < 0 && sendRet !== AVERROR_EOF) {
|
|
1167
|
+
FFmpegError.throwIfError(sendRet, 'Failed to send packet to bitstream filter');
|
|
1168
|
+
}
|
|
1169
|
+
// Receive ALL available packets immediately
|
|
1170
|
+
while (!this.outputQueue.isClosed) {
|
|
1171
|
+
const outPacket = await this.receive();
|
|
1172
|
+
if (!outPacket)
|
|
1173
|
+
break;
|
|
1174
|
+
await this.outputQueue.send(outPacket);
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
catch (e_3) {
|
|
1178
|
+
env_3.error = e_3;
|
|
1179
|
+
env_3.hasError = true;
|
|
1180
|
+
}
|
|
1181
|
+
finally {
|
|
1182
|
+
__disposeResources(env_3);
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
// Flush filter at end
|
|
1186
|
+
await this.flush();
|
|
1187
|
+
while (!this.outputQueue.isClosed) {
|
|
1188
|
+
const outPacket = await this.receive();
|
|
1189
|
+
if (!outPacket)
|
|
1190
|
+
break;
|
|
1191
|
+
await this.outputQueue.send(outPacket);
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
catch (error) {
|
|
1195
|
+
// Propagate error to both queues so upstream and downstream know
|
|
1196
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
1197
|
+
this.inputQueue?.closeWithError(err);
|
|
1198
|
+
this.outputQueue?.closeWithError(err);
|
|
1199
|
+
}
|
|
1200
|
+
finally {
|
|
1201
|
+
// Close output queue when done (if not already closed with error)
|
|
1202
|
+
this.outputQueue?.close();
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
pipeTo(target, streamIndex) {
|
|
1206
|
+
if (target instanceof Muxer) {
|
|
1207
|
+
// Start worker if not already running
|
|
1208
|
+
this.workerPromise ??= this.runWorker();
|
|
1209
|
+
// Start pipe task: filter.outputQueue -> output
|
|
1210
|
+
this.pipeToPromise = (async () => {
|
|
1211
|
+
while (true) {
|
|
1212
|
+
const packet = await this.receiveFromQueue();
|
|
1213
|
+
if (!packet)
|
|
1214
|
+
break;
|
|
1215
|
+
await target.writePacket(packet, streamIndex);
|
|
1216
|
+
}
|
|
1217
|
+
})();
|
|
1218
|
+
// Return control without pipeTo (terminal stage)
|
|
1219
|
+
return new SchedulerControl(this);
|
|
1220
|
+
}
|
|
1221
|
+
else {
|
|
1222
|
+
// BitStreamFilterAPI
|
|
1223
|
+
const t = target;
|
|
1224
|
+
// Store reference to next component for flush propagation
|
|
1225
|
+
this.nextComponent = t;
|
|
1226
|
+
// Start worker if not already running
|
|
1227
|
+
this.workerPromise ??= this.runWorker();
|
|
1228
|
+
// Start pipe task: filter.outputQueue -> target.inputQueue (via target.send)
|
|
1229
|
+
this.pipeToPromise = (async () => {
|
|
1230
|
+
while (true) {
|
|
1231
|
+
const packet = await this.receiveFromQueue();
|
|
1232
|
+
if (!packet)
|
|
1233
|
+
break;
|
|
1234
|
+
await t.sendToQueue(packet);
|
|
1235
|
+
}
|
|
1236
|
+
})();
|
|
1237
|
+
// Return scheduler for chaining (target is now the last component)
|
|
1238
|
+
return new Scheduler(this, t);
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
//# sourceMappingURL=bitstream-filter.js.map
|