node-av 3.1.3 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. package/README.md +88 -52
  2. package/binding.gyp +23 -11
  3. package/dist/api/audio-frame-buffer.d.ts +201 -0
  4. package/dist/api/audio-frame-buffer.js +275 -0
  5. package/dist/api/audio-frame-buffer.js.map +1 -0
  6. package/dist/api/bitstream-filter.d.ts +320 -78
  7. package/dist/api/bitstream-filter.js +684 -151
  8. package/dist/api/bitstream-filter.js.map +1 -1
  9. package/dist/api/constants.d.ts +44 -0
  10. package/dist/api/constants.js +45 -0
  11. package/dist/api/constants.js.map +1 -0
  12. package/dist/api/data/test_av1.ivf +0 -0
  13. package/dist/api/data/test_mjpeg.mjpeg +0 -0
  14. package/dist/api/data/test_vp8.ivf +0 -0
  15. package/dist/api/data/test_vp9.ivf +0 -0
  16. package/dist/api/decoder.d.ts +454 -77
  17. package/dist/api/decoder.js +1081 -271
  18. package/dist/api/decoder.js.map +1 -1
  19. package/dist/api/{media-input.d.ts → demuxer.d.ts} +295 -45
  20. package/dist/api/demuxer.js +1965 -0
  21. package/dist/api/demuxer.js.map +1 -0
  22. package/dist/api/encoder.d.ts +423 -132
  23. package/dist/api/encoder.js +1089 -240
  24. package/dist/api/encoder.js.map +1 -1
  25. package/dist/api/filter-complex.d.ts +769 -0
  26. package/dist/api/filter-complex.js +1596 -0
  27. package/dist/api/filter-complex.js.map +1 -0
  28. package/dist/api/filter-presets.d.ts +80 -5
  29. package/dist/api/filter-presets.js +117 -7
  30. package/dist/api/filter-presets.js.map +1 -1
  31. package/dist/api/filter.d.ts +561 -125
  32. package/dist/api/filter.js +1083 -274
  33. package/dist/api/filter.js.map +1 -1
  34. package/dist/api/{fmp4.d.ts → fmp4-stream.d.ts} +141 -140
  35. package/dist/api/fmp4-stream.js +539 -0
  36. package/dist/api/fmp4-stream.js.map +1 -0
  37. package/dist/api/hardware.d.ts +58 -6
  38. package/dist/api/hardware.js +127 -11
  39. package/dist/api/hardware.js.map +1 -1
  40. package/dist/api/index.d.ts +8 -4
  41. package/dist/api/index.js +17 -8
  42. package/dist/api/index.js.map +1 -1
  43. package/dist/api/io-stream.d.ts +6 -6
  44. package/dist/api/io-stream.js +5 -4
  45. package/dist/api/io-stream.js.map +1 -1
  46. package/dist/api/{media-output.d.ts → muxer.d.ts} +280 -66
  47. package/dist/api/muxer.js +1934 -0
  48. package/dist/api/muxer.js.map +1 -0
  49. package/dist/api/pipeline.d.ts +77 -29
  50. package/dist/api/pipeline.js +449 -439
  51. package/dist/api/pipeline.js.map +1 -1
  52. package/dist/api/rtp-stream.d.ts +312 -0
  53. package/dist/api/rtp-stream.js +630 -0
  54. package/dist/api/rtp-stream.js.map +1 -0
  55. package/dist/api/types.d.ts +533 -56
  56. package/dist/api/utilities/async-queue.d.ts +91 -0
  57. package/dist/api/utilities/async-queue.js +162 -0
  58. package/dist/api/utilities/async-queue.js.map +1 -0
  59. package/dist/api/utilities/audio-sample.d.ts +11 -1
  60. package/dist/api/utilities/audio-sample.js +10 -0
  61. package/dist/api/utilities/audio-sample.js.map +1 -1
  62. package/dist/api/utilities/channel-layout.d.ts +1 -0
  63. package/dist/api/utilities/channel-layout.js +1 -0
  64. package/dist/api/utilities/channel-layout.js.map +1 -1
  65. package/dist/api/utilities/image.d.ts +39 -1
  66. package/dist/api/utilities/image.js +38 -0
  67. package/dist/api/utilities/image.js.map +1 -1
  68. package/dist/api/utilities/index.d.ts +3 -0
  69. package/dist/api/utilities/index.js +6 -0
  70. package/dist/api/utilities/index.js.map +1 -1
  71. package/dist/api/utilities/media-type.d.ts +2 -1
  72. package/dist/api/utilities/media-type.js +1 -0
  73. package/dist/api/utilities/media-type.js.map +1 -1
  74. package/dist/api/utilities/pixel-format.d.ts +4 -1
  75. package/dist/api/utilities/pixel-format.js +3 -0
  76. package/dist/api/utilities/pixel-format.js.map +1 -1
  77. package/dist/api/utilities/sample-format.d.ts +6 -1
  78. package/dist/api/utilities/sample-format.js +5 -0
  79. package/dist/api/utilities/sample-format.js.map +1 -1
  80. package/dist/api/utilities/scheduler.d.ts +138 -0
  81. package/dist/api/utilities/scheduler.js +98 -0
  82. package/dist/api/utilities/scheduler.js.map +1 -0
  83. package/dist/api/utilities/streaming.d.ts +105 -15
  84. package/dist/api/utilities/streaming.js +201 -12
  85. package/dist/api/utilities/streaming.js.map +1 -1
  86. package/dist/api/utilities/timestamp.d.ts +15 -1
  87. package/dist/api/utilities/timestamp.js +14 -0
  88. package/dist/api/utilities/timestamp.js.map +1 -1
  89. package/dist/api/utilities/whisper-model.d.ts +310 -0
  90. package/dist/api/utilities/whisper-model.js +528 -0
  91. package/dist/api/utilities/whisper-model.js.map +1 -0
  92. package/dist/api/webrtc-stream.d.ts +288 -0
  93. package/dist/api/webrtc-stream.js +440 -0
  94. package/dist/api/webrtc-stream.js.map +1 -0
  95. package/dist/api/whisper.d.ts +324 -0
  96. package/dist/api/whisper.js +362 -0
  97. package/dist/api/whisper.js.map +1 -0
  98. package/dist/constants/constants.d.ts +54 -2
  99. package/dist/constants/constants.js +48 -1
  100. package/dist/constants/constants.js.map +1 -1
  101. package/dist/constants/encoders.d.ts +2 -1
  102. package/dist/constants/encoders.js +4 -3
  103. package/dist/constants/encoders.js.map +1 -1
  104. package/dist/constants/hardware.d.ts +26 -0
  105. package/dist/constants/hardware.js +27 -0
  106. package/dist/constants/hardware.js.map +1 -0
  107. package/dist/constants/index.d.ts +1 -0
  108. package/dist/constants/index.js +1 -0
  109. package/dist/constants/index.js.map +1 -1
  110. package/dist/ffmpeg/index.d.ts +3 -3
  111. package/dist/ffmpeg/index.js +3 -3
  112. package/dist/ffmpeg/utils.d.ts +27 -0
  113. package/dist/ffmpeg/utils.js +28 -16
  114. package/dist/ffmpeg/utils.js.map +1 -1
  115. package/dist/lib/binding.d.ts +22 -11
  116. package/dist/lib/binding.js.map +1 -1
  117. package/dist/lib/codec-context.d.ts +87 -0
  118. package/dist/lib/codec-context.js +125 -4
  119. package/dist/lib/codec-context.js.map +1 -1
  120. package/dist/lib/codec-parameters.d.ts +229 -1
  121. package/dist/lib/codec-parameters.js +264 -0
  122. package/dist/lib/codec-parameters.js.map +1 -1
  123. package/dist/lib/codec-parser.d.ts +23 -0
  124. package/dist/lib/codec-parser.js +25 -0
  125. package/dist/lib/codec-parser.js.map +1 -1
  126. package/dist/lib/codec.d.ts +26 -4
  127. package/dist/lib/codec.js +35 -0
  128. package/dist/lib/codec.js.map +1 -1
  129. package/dist/lib/dictionary.js +1 -0
  130. package/dist/lib/dictionary.js.map +1 -1
  131. package/dist/lib/error.js +1 -1
  132. package/dist/lib/error.js.map +1 -1
  133. package/dist/lib/fifo.d.ts +416 -0
  134. package/dist/lib/fifo.js +453 -0
  135. package/dist/lib/fifo.js.map +1 -0
  136. package/dist/lib/filter-context.d.ts +52 -11
  137. package/dist/lib/filter-context.js +56 -12
  138. package/dist/lib/filter-context.js.map +1 -1
  139. package/dist/lib/filter-graph.d.ts +9 -0
  140. package/dist/lib/filter-graph.js +13 -0
  141. package/dist/lib/filter-graph.js.map +1 -1
  142. package/dist/lib/filter.d.ts +21 -0
  143. package/dist/lib/filter.js +28 -0
  144. package/dist/lib/filter.js.map +1 -1
  145. package/dist/lib/format-context.d.ts +48 -14
  146. package/dist/lib/format-context.js +76 -7
  147. package/dist/lib/format-context.js.map +1 -1
  148. package/dist/lib/frame.d.ts +264 -1
  149. package/dist/lib/frame.js +351 -1
  150. package/dist/lib/frame.js.map +1 -1
  151. package/dist/lib/hardware-device-context.d.ts +3 -2
  152. package/dist/lib/hardware-device-context.js.map +1 -1
  153. package/dist/lib/index.d.ts +2 -0
  154. package/dist/lib/index.js +4 -0
  155. package/dist/lib/index.js.map +1 -1
  156. package/dist/lib/input-format.d.ts +21 -0
  157. package/dist/lib/input-format.js +42 -2
  158. package/dist/lib/input-format.js.map +1 -1
  159. package/dist/lib/native-types.d.ts +76 -27
  160. package/dist/lib/option.d.ts +25 -13
  161. package/dist/lib/option.js +28 -0
  162. package/dist/lib/option.js.map +1 -1
  163. package/dist/lib/output-format.d.ts +22 -1
  164. package/dist/lib/output-format.js +28 -0
  165. package/dist/lib/output-format.js.map +1 -1
  166. package/dist/lib/packet.d.ts +35 -0
  167. package/dist/lib/packet.js +52 -2
  168. package/dist/lib/packet.js.map +1 -1
  169. package/dist/lib/rational.d.ts +18 -0
  170. package/dist/lib/rational.js +19 -0
  171. package/dist/lib/rational.js.map +1 -1
  172. package/dist/lib/stream.d.ts +126 -0
  173. package/dist/lib/stream.js +188 -5
  174. package/dist/lib/stream.js.map +1 -1
  175. package/dist/lib/sync-queue.d.ts +179 -0
  176. package/dist/lib/sync-queue.js +197 -0
  177. package/dist/lib/sync-queue.js.map +1 -0
  178. package/dist/lib/types.d.ts +49 -1
  179. package/dist/lib/utilities.d.ts +281 -53
  180. package/dist/lib/utilities.js +298 -55
  181. package/dist/lib/utilities.js.map +1 -1
  182. package/install/check.js +2 -2
  183. package/package.json +37 -26
  184. package/dist/api/fmp4.js +0 -710
  185. package/dist/api/fmp4.js.map +0 -1
  186. package/dist/api/media-input.js +0 -1075
  187. package/dist/api/media-input.js.map +0 -1
  188. package/dist/api/media-output.js +0 -1040
  189. package/dist/api/media-output.js.map +0 -1
  190. package/dist/api/webrtc.d.ts +0 -664
  191. package/dist/api/webrtc.js +0 -1132
  192. package/dist/api/webrtc.js.map +0 -1
@@ -1,10 +1,70 @@
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
+ });
1
53
  import { AVERROR_EAGAIN, AVERROR_EOF } from '../constants/constants.js';
2
- import { BitStreamFilter, BitStreamFilterContext, FFmpegError, Packet } from '../lib/index.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';
3
62
  /**
4
63
  * High-level bitstream filter for packet processing.
5
64
  *
6
65
  * Provides simplified interface for applying bitstream filters to packets.
7
66
  * Handles filter initialization, packet processing, and memory management.
67
+ * Supports both synchronous packet-by-packet filtering and async iteration over packets.
8
68
  * Supports filters like h264_mp4toannexb, hevc_mp4toannexb, aac_adtstoasc.
9
69
  * Essential for format conversion and stream compatibility in transcoding pipelines.
10
70
  *
@@ -15,8 +75,8 @@ import { BitStreamFilter, BitStreamFilterContext, FFmpegError, Packet } from '..
15
75
  * // Create H.264 Annex B converter
16
76
  * const filter = BitStreamFilterAPI.create('h264_mp4toannexb', stream);
17
77
  *
18
- * // Process packet
19
- * const outputPackets = await filter.process(inputPacket);
78
+ * // Filter packet
79
+ * const outputPackets = await filter.filterAll(inputPacket);
20
80
  * for (const packet of outputPackets) {
21
81
  * await output.writePacket(packet);
22
82
  * packet.free();
@@ -25,7 +85,7 @@ import { BitStreamFilter, BitStreamFilterContext, FFmpegError, Packet } from '..
25
85
  *
26
86
  * @example
27
87
  * ```typescript
28
- * // Process packet stream
88
+ * // Filter packet stream
29
89
  * const filter = BitStreamFilterAPI.create('hevc_mp4toannexb', videoStream);
30
90
  *
31
91
  * for await (const packet of filter.packets(input.packets())) {
@@ -36,15 +96,22 @@ import { BitStreamFilter, BitStreamFilterContext, FFmpegError, Packet } from '..
36
96
  *
37
97
  * @see {@link BitStreamFilter} For available filters
38
98
  * @see {@link BitStreamFilterContext} For low-level API
39
- * @see {@link MediaOutput} For writing filtered packets
99
+ * @see {@link Muxer} For writing filtered packets
40
100
  */
41
101
  export class BitStreamFilterAPI {
42
102
  ctx;
43
- filter;
103
+ bsf;
44
104
  stream;
105
+ packet;
45
106
  isClosed = false;
107
+ // Worker pattern for push-based processing
108
+ inputQueue;
109
+ outputQueue;
110
+ workerPromise = null;
111
+ nextComponent = null;
112
+ pipeToPromise = null;
46
113
  /**
47
- * @param filter - Bitstream filter instance
114
+ * @param bsf - Bitstream filter
48
115
  *
49
116
  * @param ctx - Filter context
50
117
  *
@@ -52,10 +119,14 @@ export class BitStreamFilterAPI {
52
119
  *
53
120
  * @internal
54
121
  */
55
- constructor(filter, ctx, stream) {
56
- this.filter = filter;
122
+ constructor(bsf, ctx, stream) {
123
+ this.bsf = bsf;
57
124
  this.ctx = ctx;
58
125
  this.stream = stream;
126
+ this.packet = new Packet();
127
+ this.packet.alloc();
128
+ this.inputQueue = new AsyncQueue(PACKET_THREAD_QUEUE_SIZE);
129
+ this.outputQueue = new AsyncQueue(PACKET_THREAD_QUEUE_SIZE);
59
130
  }
60
131
  /**
61
132
  * Create a bitstream filter for a stream.
@@ -136,7 +207,7 @@ export class BitStreamFilterAPI {
136
207
  * ```
137
208
  */
138
209
  get name() {
139
- return this.filter.name ?? 'unknown';
210
+ return this.bsf.name ?? 'unknown';
140
211
  }
141
212
  /**
142
213
  * Get output codec parameters.
@@ -181,125 +252,211 @@ export class BitStreamFilterAPI {
181
252
  return !this.isClosed;
182
253
  }
183
254
  /**
184
- * Process a packet through the filter.
255
+ * Filter a packet.
185
256
  *
186
- * Applies bitstream filter to packet.
187
- * May produce zero, one, or multiple output packets.
188
- * Pass null to signal end-of-stream.
257
+ * Sends a packet to the filter and attempts to receive a filtered packet.
258
+ * Handles internal buffering - may return null if more packets needed.
259
+ *
260
+ * **Note**: This method receives only ONE packet per call.
261
+ * A single packet can produce multiple output packets (e.g., codec buffering).
262
+ * To receive all packets from a packet, use {@link filterAll} or {@link packets} instead.
189
263
  *
190
264
  * Direct mapping to av_bsf_send_packet() and av_bsf_receive_packet().
191
265
  *
192
- * @param packet - Packet to filter or null for EOF
266
+ * @param packet - Packet to filter
193
267
  *
194
- * @returns Array of filtered packets or null if filter is closed
268
+ * @returns Filtered packet, null if more data needed, or null if filter is closed
195
269
  *
196
270
  * @throws {FFmpegError} If filtering fails
197
271
  *
198
272
  * @example
199
273
  * ```typescript
200
- * const outputPackets = await filter.process(inputPacket);
201
- * if (outputPackets) {
202
- * for (const packet of outputPackets) {
203
- * console.log(`Filtered packet: pts=${packet.pts}`);
204
- * packet.free();
205
- * }
274
+ * const outPacket = await filter.filter(inputPacket);
275
+ * if (outPacket) {
276
+ * console.log(`Filtered packet: pts=${outPacket.pts}`);
277
+ * await output.writePacket(outPacket);
278
+ * outPacket.free();
206
279
  * }
207
280
  * ```
208
281
  *
282
+ * @see {@link filterAll} For multiple packet filtering
283
+ * @see {@link packets} For stream processing
284
+ * @see {@link flush} For end-of-stream handling
285
+ * @see {@link filterSync} For synchronous version
286
+ */
287
+ async filter(packet) {
288
+ if (this.isClosed) {
289
+ return null;
290
+ }
291
+ // Send packet to filter
292
+ const sendRet = await this.ctx.sendPacket(packet);
293
+ // Handle EAGAIN: filter buffer is full, need to read packets first
294
+ if (sendRet === AVERROR_EAGAIN) {
295
+ // Filter is full, receive a packet first
296
+ const outPacket = await this.receive();
297
+ if (outPacket) {
298
+ return outPacket;
299
+ }
300
+ // If receive() returned null, this is unexpected - treat as error
301
+ throw new Error('Filter returned EAGAIN but no packet available');
302
+ }
303
+ if (sendRet < 0 && sendRet !== AVERROR_EOF) {
304
+ FFmpegError.throwIfError(sendRet, 'Failed to send packet to bitstream filter');
305
+ }
306
+ // Try to receive packet
307
+ return await this.receive();
308
+ }
309
+ /**
310
+ * Filter a packet synchronously.
311
+ * Synchronous version of filter.
312
+ *
313
+ * Sends a packet to the filter and attempts to receive a filtered packet.
314
+ * Handles internal buffering - may return null if more packets needed.
315
+ *
316
+ * **Note**: This method receives only ONE packet per call.
317
+ * A single packet can produce multiple output packets (e.g., codec buffering).
318
+ * To receive all packets from a packet, use {@link filterAllSync} or {@link packetsSync} instead.
319
+ *
320
+ * Direct mapping to av_bsf_send_packet() and av_bsf_receive_packet().
321
+ *
322
+ * @param packet - Packet to filter
323
+ *
324
+ * @returns Filtered packet, null if more data needed, or null if filter is closed
325
+ *
326
+ * @throws {FFmpegError} If filtering fails
327
+ *
209
328
  * @example
210
329
  * ```typescript
211
- * // Flush filter
212
- * const remaining = await filter.process(null);
330
+ * const outPacket = filter.filterSync(inputPacket);
331
+ * if (outPacket) {
332
+ * console.log(`Filtered packet: pts=${outPacket.pts}`);
333
+ * output.writePacketSync(outPacket);
334
+ * outPacket.free();
335
+ * }
213
336
  * ```
214
337
  *
215
- * @see {@link flush} For explicit flushing
338
+ * @see {@link filterAllSync} For multiple packet filtering
339
+ * @see {@link packetsSync} For stream processing
340
+ * @see {@link flushSync} For end-of-stream handling
341
+ * @see {@link filter} For async version
342
+ */
343
+ filterSync(packet) {
344
+ if (this.isClosed) {
345
+ return null;
346
+ }
347
+ // Send packet to filter
348
+ const sendRet = this.ctx.sendPacketSync(packet);
349
+ // Handle EAGAIN: filter buffer is full, need to read packets first
350
+ if (sendRet === AVERROR_EAGAIN) {
351
+ // Filter is full, receive a packet first
352
+ const outPacket = this.receiveSync();
353
+ if (outPacket) {
354
+ return outPacket;
355
+ }
356
+ // If receive() returned null, this is unexpected - treat as error
357
+ throw new Error('Filter returned EAGAIN but no packet available');
358
+ }
359
+ if (sendRet < 0 && sendRet !== AVERROR_EOF) {
360
+ FFmpegError.throwIfError(sendRet, 'Failed to send packet to bitstream filter');
361
+ }
362
+ // Try to receive packet
363
+ return this.receiveSync();
364
+ }
365
+ /**
366
+ * Filter a packet to packets.
367
+ *
368
+ * Sends a packet to the filter and receives all available filtered packets.
369
+ * Returns array of packets - may be empty if filter needs more data.
370
+ * One packet can produce zero, one, or multiple packets depending on filter.
371
+ *
372
+ * Direct mapping to av_bsf_send_packet() and av_bsf_receive_packet().
373
+ *
374
+ * @param packet - Packet to filter
375
+ *
376
+ * @returns Array of filtered packets (empty if more data needed or filter is closed)
377
+ *
378
+ * @throws {FFmpegError} If filtering fails
379
+ *
380
+ * @example
381
+ * ```typescript
382
+ * const outputPackets = await filter.filterAll(inputPacket);
383
+ * for (const packet of outputPackets) {
384
+ * console.log(`Filtered packet: pts=${packet.pts}`);
385
+ * await output.writePacket(packet);
386
+ * packet.free();
387
+ * }
388
+ * ```
389
+ *
390
+ * @see {@link filter} For single packet filtering
216
391
  * @see {@link packets} For stream processing
392
+ * @see {@link flush} For end-of-stream handling
393
+ * @see {@link filterAllSync} For synchronous version
217
394
  */
218
- async process(packet) {
395
+ async filterAll(packet) {
219
396
  if (this.isClosed) {
220
397
  return [];
221
398
  }
222
399
  const outputPackets = [];
223
400
  // Send packet to filter
224
401
  const sendRet = await this.ctx.sendPacket(packet);
225
- if (sendRet < 0 && sendRet !== AVERROR_EAGAIN) {
402
+ if (sendRet < 0 && sendRet !== AVERROR_EOF) {
226
403
  FFmpegError.throwIfError(sendRet, 'Failed to send packet to bitstream filter');
227
404
  }
228
405
  // Receive all output packets
229
- while (!this.isClosed) {
230
- const outPacket = new Packet();
231
- outPacket.alloc();
232
- const recvRet = await this.ctx.receivePacket(outPacket);
233
- if (recvRet === AVERROR_EAGAIN || recvRet === AVERROR_EOF) {
234
- outPacket.unref();
406
+ while (true) {
407
+ const outPacket = await this.receive();
408
+ if (!outPacket)
235
409
  break;
236
- }
237
- if (recvRet < 0) {
238
- outPacket.unref();
239
- FFmpegError.throwIfError(recvRet, 'Failed to receive packet from bitstream filter');
240
- }
241
410
  outputPackets.push(outPacket);
242
411
  }
243
412
  return outputPackets;
244
413
  }
245
414
  /**
246
- * Process a packet through the filter synchronously.
247
- * Synchronous version of process.
415
+ * Filter a packet to packets synchronously.
416
+ * Synchronous version of filterAll.
248
417
  *
249
- * Applies bitstream filter to packet.
250
- * May produce zero, one, or multiple output packets.
251
- * Pass null to signal end-of-stream.
418
+ * Sends a packet to the filter and receives all available filtered packets.
419
+ * Returns array of packets - may be empty if filter needs more data.
420
+ * One packet can produce zero, one, or multiple packets depending on filter.
252
421
  *
253
422
  * Direct mapping to av_bsf_send_packet() and av_bsf_receive_packet().
254
423
  *
255
- * @param packet - Packet to filter or null for EOF
424
+ * @param packet - Packet to filter
256
425
  *
257
- * @returns Array of filtered packets or null if filter is closed
426
+ * @returns Array of filtered packets (empty if more data needed or filter is closed)
258
427
  *
259
428
  * @throws {FFmpegError} If filtering fails
260
429
  *
261
430
  * @example
262
431
  * ```typescript
263
- * const outputPackets = filter.processSync(inputPacket);
264
- * if (outputPackets) {
265
- * for (const packet of outputPackets) {
266
- * console.log(`Filtered packet: pts=${packet.pts}`);
267
- * packet.free();
268
- * }
432
+ * const outputPackets = filter.filterAllSync(inputPacket);
433
+ * for (const packet of outputPackets) {
434
+ * console.log(`Filtered packet: pts=${packet.pts}`);
435
+ * output.writePacketSync(packet);
436
+ * packet.free();
269
437
  * }
270
438
  * ```
271
439
  *
272
- * @example
273
- * ```typescript
274
- * // Flush filter
275
- * const remaining = filter.processSync(null);
276
- * ```
277
- *
278
- * @see {@link process} For async version
440
+ * @see {@link filterSync} For single packet filtering
441
+ * @see {@link packetsSync} For stream processing
442
+ * @see {@link flushSync} For end-of-stream handling
443
+ * @see {@link filterAll} For async version
279
444
  */
280
- processSync(packet) {
445
+ filterAllSync(packet) {
281
446
  if (this.isClosed) {
282
447
  return [];
283
448
  }
284
449
  const outputPackets = [];
285
450
  // Send packet to filter
286
451
  const sendRet = this.ctx.sendPacketSync(packet);
287
- if (sendRet < 0 && sendRet !== AVERROR_EAGAIN) {
452
+ if (sendRet < 0 && sendRet !== AVERROR_EOF) {
288
453
  FFmpegError.throwIfError(sendRet, 'Failed to send packet to bitstream filter');
289
454
  }
290
455
  // Receive all output packets
291
- while (!this.isClosed) {
292
- const outPacket = new Packet();
293
- outPacket.alloc();
294
- const recvRet = this.ctx.receivePacketSync(outPacket);
295
- if (recvRet === AVERROR_EAGAIN || recvRet === AVERROR_EOF) {
296
- outPacket.unref();
456
+ while (true) {
457
+ const outPacket = this.receiveSync();
458
+ if (!outPacket)
297
459
  break;
298
- }
299
- if (recvRet < 0) {
300
- outPacket.unref();
301
- FFmpegError.throwIfError(recvRet, 'Failed to receive packet from bitstream filter');
302
- }
303
460
  outputPackets.push(outPacket);
304
461
  }
305
462
  return outputPackets;
@@ -338,33 +495,67 @@ export class BitStreamFilterAPI {
338
495
  * }
339
496
  * ```
340
497
  *
341
- * @see {@link process} For single packet filtering
498
+ * @see {@link filterAll} For filtering single packets
342
499
  * @see {@link flush} For end-of-stream handling
343
500
  */
344
501
  async *packets(packets) {
345
- try {
346
- // Process all input packets
347
- for await (const packet of packets) {
348
- const filtered = await this.process(packet);
349
- if (filtered) {
350
- for (const outPacket of filtered) {
351
- yield outPacket;
352
- }
502
+ // Process all input packets
503
+ for await (const packet of packets) {
504
+ // Handle EOF signal
505
+ if (packet === null) {
506
+ // Flush filter
507
+ await this.flush();
508
+ while (true) {
509
+ const remaining = await this.receive();
510
+ if (!remaining)
511
+ break;
512
+ yield remaining;
353
513
  }
514
+ // Signal EOF and stop processing
515
+ yield null;
516
+ return;
517
+ }
518
+ if (this.isClosed) {
519
+ break;
354
520
  }
355
- // Send EOF and get remaining packets
356
- const remaining = await this.flush();
357
- if (remaining) {
358
- for (const packet of remaining) {
359
- yield packet;
521
+ // Send packet to filter
522
+ const sendRet = await this.ctx.sendPacket(packet);
523
+ // Handle EAGAIN
524
+ if (sendRet === AVERROR_EAGAIN) {
525
+ // Filter buffer full, receive packets first
526
+ while (true) {
527
+ const outPacket = await this.receive();
528
+ if (!outPacket)
529
+ break;
530
+ yield outPacket;
360
531
  }
532
+ // Retry sending
533
+ const retryRet = await this.ctx.sendPacket(packet);
534
+ if (retryRet < 0 && retryRet !== AVERROR_EOF && retryRet !== AVERROR_EAGAIN) {
535
+ FFmpegError.throwIfError(retryRet, 'Failed to send packet to bitstream filter');
536
+ }
537
+ }
538
+ else if (sendRet < 0 && sendRet !== AVERROR_EOF) {
539
+ FFmpegError.throwIfError(sendRet, 'Failed to send packet to bitstream filter');
540
+ }
541
+ // Receive ALL available packets immediately
542
+ while (true) {
543
+ const outPacket = await this.receive();
544
+ if (!outPacket)
545
+ break; // EAGAIN or EOF
546
+ yield outPacket;
361
547
  }
362
548
  }
363
- catch (error) {
364
- // Ensure cleanup on error
365
- this.ctx.flush();
366
- throw error;
549
+ // Flush filter after all packets (fallback if no null was sent)
550
+ await this.flush();
551
+ while (true) {
552
+ const remaining = await this.receive();
553
+ if (!remaining)
554
+ break;
555
+ yield remaining;
367
556
  }
557
+ // Signal EOF
558
+ yield null;
368
559
  }
369
560
  /**
370
561
  * Process packet stream through filter synchronously.
@@ -404,149 +595,331 @@ export class BitStreamFilterAPI {
404
595
  * @see {@link packets} For async version
405
596
  */
406
597
  *packetsSync(packets) {
407
- try {
408
- // Process all input packets
409
- for (const packet of packets) {
410
- const filtered = this.processSync(packet);
411
- if (filtered) {
412
- for (const outPacket of filtered) {
413
- yield outPacket;
414
- }
598
+ // Process all input packets
599
+ for (const packet of packets) {
600
+ // Handle EOF signal
601
+ if (packet === null) {
602
+ // Flush filter
603
+ this.flushSync();
604
+ while (true) {
605
+ const remaining = this.receiveSync();
606
+ if (!remaining)
607
+ break;
608
+ yield remaining;
415
609
  }
610
+ // Signal EOF and stop processing
611
+ yield null;
612
+ return;
613
+ }
614
+ if (this.isClosed) {
615
+ break;
416
616
  }
417
- // Send EOF and get remaining packets
418
- const remaining = this.flushSync();
419
- if (remaining) {
420
- for (const packet of remaining) {
421
- yield packet;
617
+ // Send packet to filter
618
+ const sendRet = this.ctx.sendPacketSync(packet);
619
+ // Handle EAGAIN
620
+ if (sendRet === AVERROR_EAGAIN) {
621
+ // Filter buffer full, receive packets first
622
+ while (true) {
623
+ const outPacket = this.receiveSync();
624
+ if (!outPacket)
625
+ break;
626
+ yield outPacket;
422
627
  }
628
+ // Retry sending
629
+ const retryRet = this.ctx.sendPacketSync(packet);
630
+ if (retryRet < 0 && retryRet !== AVERROR_EOF && retryRet !== AVERROR_EAGAIN) {
631
+ FFmpegError.throwIfError(retryRet, 'Failed to send packet to bitstream filter');
632
+ }
633
+ }
634
+ else if (sendRet < 0 && sendRet !== AVERROR_EOF) {
635
+ FFmpegError.throwIfError(sendRet, 'Failed to send packet to bitstream filter');
636
+ }
637
+ // Receive ALL available packets immediately
638
+ while (true) {
639
+ const outPacket = this.receiveSync();
640
+ if (!outPacket)
641
+ break; // EAGAIN or EOF
642
+ yield outPacket;
423
643
  }
424
644
  }
425
- catch (error) {
426
- // Ensure cleanup on error
427
- this.ctx.flush();
428
- throw error;
645
+ // Flush filter after all packets (fallback if no null was sent)
646
+ this.flushSync();
647
+ while (true) {
648
+ const remaining = this.receiveSync();
649
+ if (!remaining)
650
+ break;
651
+ yield remaining;
429
652
  }
653
+ // Signal EOF
654
+ yield null;
430
655
  }
431
656
  /**
432
- * Flush filter and get remaining packets.
657
+ * Flush filter and signal end-of-stream.
433
658
  *
434
- * Signals end-of-stream and retrieves buffered packets.
435
- * Also resets internal filter state.
659
+ * Sends null packet to filter to signal end-of-stream.
660
+ * Does nothing if filter is closed.
661
+ * Must call receive() or flushPackets() to get remaining buffered packets.
436
662
  *
437
- * Direct mapping to av_bsf_flush().
663
+ * Direct mapping to av_bsf_send_packet(NULL) and av_bsf_flush().
438
664
  *
439
- * @returns Array of remaining packets or null if filter is closed
665
+ * @throws {FFmpegError} If flush fails
440
666
  *
441
667
  * @example
442
668
  * ```typescript
443
- * const remaining = await filter.flush();
444
- * if (remaining) {
445
- * for (const packet of remaining) {
446
- * await output.writePacket(packet);
447
- * packet.free();
448
- * }
669
+ * // Signal end of stream
670
+ * await filter.flush();
671
+ *
672
+ * // Then get remaining packets
673
+ * let packet;
674
+ * while ((packet = await filter.receive()) !== null) {
675
+ * console.log('Got buffered packet');
676
+ * await output.writePacket(packet);
677
+ * packet.free();
449
678
  * }
450
679
  * ```
451
680
  *
452
681
  * @see {@link flushPackets} For async iteration
682
+ * @see {@link receive} For getting buffered packets
453
683
  * @see {@link reset} For state reset only
684
+ * @see {@link flushSync} For synchronous version
454
685
  */
455
686
  async flush() {
456
687
  if (this.isClosed) {
457
- return [];
688
+ return;
458
689
  }
459
690
  // Send EOF
460
- const filtered = await this.process(null);
691
+ const sendRet = await this.ctx.sendPacket(null);
692
+ if (sendRet < 0 && sendRet !== AVERROR_EOF && sendRet !== AVERROR_EAGAIN) {
693
+ FFmpegError.throwIfError(sendRet, 'Failed to flush bitstream filter');
694
+ }
461
695
  // Also flush the context to reset internal state
462
696
  this.ctx.flush();
463
- return filtered;
464
697
  }
465
698
  /**
466
- * Flush filter and get remaining packets synchronously.
699
+ * Flush filter and signal end-of-stream synchronously.
467
700
  * Synchronous version of flush.
468
701
  *
469
- * Signals end-of-stream and retrieves buffered packets.
470
- * Also resets internal filter state.
702
+ * Sends null packet to filter to signal end-of-stream.
703
+ * Does nothing if filter is closed.
704
+ * Must call receiveSync() or flushPacketsSync() to get remaining buffered packets.
471
705
  *
472
- * Direct mapping to av_bsf_flush().
706
+ * Direct mapping to av_bsf_send_packet(NULL) and av_bsf_flush().
473
707
  *
474
- * @returns Array of remaining packets or null if filter is closed
708
+ * @throws {FFmpegError} If flush fails
475
709
  *
476
710
  * @example
477
711
  * ```typescript
478
- * const remaining = filter.flushSync();
479
- * if (remaining) {
480
- * for (const packet of remaining) {
481
- * output.writePacketSync(packet);
482
- * packet.free();
483
- * }
712
+ * // Signal end of stream
713
+ * filter.flushSync();
714
+ *
715
+ * // Then get remaining packets
716
+ * let packet;
717
+ * while ((packet = filter.receiveSync()) !== null) {
718
+ * console.log('Got buffered packet');
719
+ * output.writePacketSync(packet);
720
+ * packet.free();
484
721
  * }
485
722
  * ```
486
723
  *
724
+ * @see {@link flushPacketsSync} For sync iteration
725
+ * @see {@link receiveSync} For getting buffered packets
726
+ * @see {@link reset} For state reset only
487
727
  * @see {@link flush} For async version
488
728
  */
489
729
  flushSync() {
490
730
  if (this.isClosed) {
491
- return [];
731
+ return;
492
732
  }
493
733
  // Send EOF
494
- const filtered = this.processSync(null);
734
+ const sendRet = this.ctx.sendPacketSync(null);
735
+ if (sendRet < 0 && sendRet !== AVERROR_EOF && sendRet !== AVERROR_EAGAIN) {
736
+ FFmpegError.throwIfError(sendRet, 'Failed to flush bitstream filter');
737
+ }
495
738
  // Also flush the context to reset internal state
496
739
  this.ctx.flush();
497
- return filtered;
498
740
  }
499
741
  /**
500
- * Flush filter as async generator.
742
+ * Receive packet from filter.
743
+ *
744
+ * Gets filtered packets from the filter's internal buffer.
745
+ * Handles packet allocation and error checking.
746
+ * Returns null if filter is closed or no packets available.
747
+ * Call repeatedly until null to drain all buffered packets.
748
+ *
749
+ * Direct mapping to av_bsf_receive_packet().
750
+ *
751
+ * @returns Cloned packet or null if no packets available
752
+ *
753
+ * @throws {FFmpegError} If receive fails with error other than AVERROR_EAGAIN or AVERROR_EOF
754
+ *
755
+ * @example
756
+ * ```typescript
757
+ * const packet = await filter.receive();
758
+ * if (packet) {
759
+ * console.log('Got filtered packet');
760
+ * await output.writePacket(packet);
761
+ * packet.free();
762
+ * }
763
+ * ```
764
+ *
765
+ * @example
766
+ * ```typescript
767
+ * // Drain all buffered packets
768
+ * let packet;
769
+ * while ((packet = await filter.receive()) !== null) {
770
+ * console.log(`Packet PTS: ${packet.pts}`);
771
+ * await output.writePacket(packet);
772
+ * packet.free();
773
+ * }
774
+ * ```
775
+ *
776
+ * @see {@link filter} For filtering packets
777
+ * @see {@link flush} For signaling end-of-stream
778
+ * @see {@link receiveSync} For synchronous version
779
+ */
780
+ async receive() {
781
+ if (this.isClosed) {
782
+ return null;
783
+ }
784
+ // Clear previous packet data
785
+ this.packet.unref();
786
+ const recvRet = await this.ctx.receivePacket(this.packet);
787
+ if (recvRet === 0) {
788
+ // Got a packet, clone it for the user
789
+ return this.packet.clone();
790
+ }
791
+ else if (recvRet === AVERROR_EAGAIN || recvRet === AVERROR_EOF) {
792
+ // Need more data or end of stream
793
+ return null;
794
+ }
795
+ else {
796
+ // Error
797
+ FFmpegError.throwIfError(recvRet, 'Failed to receive packet from bitstream filter');
798
+ return null;
799
+ }
800
+ }
801
+ /**
802
+ * Receive packet from filter synchronously.
803
+ * Synchronous version of receive.
804
+ *
805
+ * Gets filtered packets from the filter's internal buffer.
806
+ * Handles packet allocation and error checking.
807
+ * Returns null if filter is closed or no packets available.
808
+ * Call repeatedly until null to drain all buffered packets.
809
+ *
810
+ * Direct mapping to av_bsf_receive_packet().
811
+ *
812
+ * @returns Cloned packet or null if no packets available
813
+ *
814
+ * @throws {FFmpegError} If receive fails with error other than AVERROR_EAGAIN or AVERROR_EOF
815
+ *
816
+ * @example
817
+ * ```typescript
818
+ * const packet = filter.receiveSync();
819
+ * if (packet) {
820
+ * console.log('Got filtered packet');
821
+ * output.writePacketSync(packet);
822
+ * packet.free();
823
+ * }
824
+ * ```
825
+ *
826
+ * @example
827
+ * ```typescript
828
+ * // Drain all buffered packets
829
+ * let packet;
830
+ * while ((packet = filter.receiveSync()) !== null) {
831
+ * console.log(`Packet PTS: ${packet.pts}`);
832
+ * output.writePacketSync(packet);
833
+ * packet.free();
834
+ * }
835
+ * ```
836
+ *
837
+ * @see {@link filterSync} For filtering packets
838
+ * @see {@link flushSync} For signaling end-of-stream
839
+ * @see {@link receive} For async version
840
+ */
841
+ receiveSync() {
842
+ if (this.isClosed) {
843
+ return null;
844
+ }
845
+ // Clear previous packet data
846
+ this.packet.unref();
847
+ const recvRet = this.ctx.receivePacketSync(this.packet);
848
+ if (recvRet === 0) {
849
+ // Got a packet, clone it for the user
850
+ return this.packet.clone();
851
+ }
852
+ else if (recvRet === AVERROR_EAGAIN || recvRet === AVERROR_EOF) {
853
+ // Need more data or end of stream
854
+ return null;
855
+ }
856
+ else {
857
+ // Error
858
+ FFmpegError.throwIfError(recvRet, 'Failed to receive packet from bitstream filter');
859
+ return null;
860
+ }
861
+ }
862
+ /**
863
+ * Flush all buffered packets as async generator.
501
864
  *
502
865
  * Convenient async iteration over remaining packets.
503
- * Combines flush and iteration.
866
+ * Automatically sends flush signal and retrieves buffered packets.
867
+ * Useful for end-of-stream processing.
504
868
  *
505
- * @yields {Packet} Remaining packets
869
+ * @yields {Packet} Buffered packets
506
870
  *
507
871
  * @example
508
872
  * ```typescript
873
+ * // Flush at end of filtering
509
874
  * for await (const packet of filter.flushPackets()) {
875
+ * console.log('Processing buffered packet');
510
876
  * await output.writePacket(packet);
511
877
  * packet.free();
512
878
  * }
513
879
  * ```
514
880
  *
515
- * @see {@link flush} For array return
881
+ * @see {@link filter} For filtering packets
882
+ * @see {@link flush} For signaling end-of-stream
883
+ * @see {@link flushPacketsSync} For synchronous version
516
884
  */
517
885
  async *flushPackets() {
518
- const remaining = await this.flush();
519
- if (remaining) {
520
- for (const packet of remaining) {
521
- yield packet;
522
- }
886
+ while (true) {
887
+ const packet = await this.receive();
888
+ if (!packet)
889
+ break;
890
+ yield packet;
523
891
  }
524
892
  }
525
893
  /**
526
- * Flush filter as generator synchronously.
894
+ * Flush all buffered packets as generator synchronously.
527
895
  * Synchronous version of flushPackets.
528
896
  *
529
897
  * Convenient sync iteration over remaining packets.
530
- * Combines flush and iteration.
898
+ * Automatically retrieves buffered packets after flush.
899
+ * Useful for end-of-stream processing.
531
900
  *
532
- * @yields {Packet} Remaining packets
901
+ * @yields {Packet} Buffered packets
533
902
  *
534
903
  * @example
535
904
  * ```typescript
905
+ * // Flush at end of filtering
536
906
  * for (const packet of filter.flushPacketsSync()) {
907
+ * console.log('Processing buffered packet');
537
908
  * output.writePacketSync(packet);
538
909
  * packet.free();
539
910
  * }
540
911
  * ```
541
912
  *
913
+ * @see {@link filterSync} For filtering packets
914
+ * @see {@link flushSync} For signaling end-of-stream
542
915
  * @see {@link flushPackets} For async version
543
916
  */
544
917
  *flushPacketsSync() {
545
- const remaining = this.flushSync();
546
- if (remaining) {
547
- for (const packet of remaining) {
548
- yield packet;
549
- }
918
+ while (true) {
919
+ const packet = this.receiveSync();
920
+ if (!packet)
921
+ break;
922
+ yield packet;
550
923
  }
551
924
  }
552
925
  /**
@@ -605,6 +978,10 @@ export class BitStreamFilterAPI {
605
978
  return;
606
979
  }
607
980
  this.isClosed = true;
981
+ // Close queues
982
+ this.inputQueue.close();
983
+ this.outputQueue.close();
984
+ this.packet.free();
608
985
  this.ctx.free();
609
986
  }
610
987
  /**
@@ -626,5 +1003,161 @@ export class BitStreamFilterAPI {
626
1003
  [Symbol.dispose]() {
627
1004
  this.close();
628
1005
  }
1006
+ /**
1007
+ * Send packet to input queue or flush the pipeline.
1008
+ *
1009
+ * When packet is provided, queues it for filtering.
1010
+ * When null is provided, triggers flush sequence:
1011
+ * - Closes input queue
1012
+ * - Waits for worker completion
1013
+ * - Closes output queue (no buffering, bitstream filters are stateless)
1014
+ * - Waits for pipeTo task completion
1015
+ * - Propagates flush to next component (if any)
1016
+ *
1017
+ * Used by scheduler system for pipeline control.
1018
+ *
1019
+ * @param packet - Packet to send, or null to flush
1020
+ *
1021
+ * @internal
1022
+ */
1023
+ async sendToQueue(packet) {
1024
+ if (packet) {
1025
+ await this.inputQueue.send(packet);
1026
+ }
1027
+ else {
1028
+ // Close input queue to signal end of stream to worker
1029
+ this.inputQueue.close();
1030
+ // Wait for worker to finish processing all packets
1031
+ if (this.workerPromise) {
1032
+ await this.workerPromise;
1033
+ }
1034
+ // Close output queue to signal end of stream to pipeTo() task
1035
+ this.outputQueue.close();
1036
+ // Wait for pipeTo() task to finish processing all packets (if exists)
1037
+ if (this.pipeToPromise) {
1038
+ await this.pipeToPromise;
1039
+ }
1040
+ // Then propagate flush to next component
1041
+ if (this.nextComponent) {
1042
+ await this.nextComponent.sendToQueue(null);
1043
+ }
1044
+ }
1045
+ }
1046
+ /**
1047
+ * Receive packet from output queue.
1048
+ *
1049
+ * @returns Packet from queue or null if closed
1050
+ *
1051
+ * @internal
1052
+ */
1053
+ async receiveFromQueue() {
1054
+ return await this.outputQueue.receive();
1055
+ }
1056
+ /**
1057
+ * Worker loop for push-based processing.
1058
+ *
1059
+ * @internal
1060
+ */
1061
+ async runWorker() {
1062
+ try {
1063
+ // Outer loop - receive packets
1064
+ while (!this.inputQueue.isClosed) {
1065
+ const env_1 = { stack: [], error: void 0, hasError: false };
1066
+ try {
1067
+ const packet = __addDisposableResource(env_1, await this.inputQueue.receive(), false);
1068
+ if (!packet)
1069
+ break;
1070
+ if (this.isClosed) {
1071
+ break;
1072
+ }
1073
+ // Send packet to filter
1074
+ const sendRet = await this.ctx.sendPacket(packet);
1075
+ // Handle EAGAIN
1076
+ if (sendRet === AVERROR_EAGAIN) {
1077
+ // Filter buffer full, receive packets first
1078
+ while (!this.outputQueue.isClosed) {
1079
+ const outPacket = await this.receive();
1080
+ if (!outPacket)
1081
+ break;
1082
+ await this.outputQueue.send(outPacket);
1083
+ }
1084
+ // Retry sending
1085
+ const retryRet = await this.ctx.sendPacket(packet);
1086
+ if (retryRet < 0 && retryRet !== AVERROR_EOF && retryRet !== AVERROR_EAGAIN) {
1087
+ FFmpegError.throwIfError(retryRet, 'Failed to send packet to bitstream filter');
1088
+ }
1089
+ }
1090
+ else if (sendRet < 0 && sendRet !== AVERROR_EOF) {
1091
+ FFmpegError.throwIfError(sendRet, 'Failed to send packet to bitstream filter');
1092
+ }
1093
+ // Receive ALL available packets immediately
1094
+ while (!this.outputQueue.isClosed) {
1095
+ const outPacket = await this.receive();
1096
+ if (!outPacket)
1097
+ break;
1098
+ await this.outputQueue.send(outPacket);
1099
+ }
1100
+ }
1101
+ catch (e_1) {
1102
+ env_1.error = e_1;
1103
+ env_1.hasError = true;
1104
+ }
1105
+ finally {
1106
+ __disposeResources(env_1);
1107
+ }
1108
+ }
1109
+ // Flush filter at end
1110
+ await this.flush();
1111
+ while (!this.outputQueue.isClosed) {
1112
+ const outPacket = await this.receive();
1113
+ if (!outPacket)
1114
+ break;
1115
+ await this.outputQueue.send(outPacket);
1116
+ }
1117
+ }
1118
+ catch {
1119
+ // Ignore error
1120
+ }
1121
+ finally {
1122
+ // Close output queue when done
1123
+ this.outputQueue?.close();
1124
+ }
1125
+ }
1126
+ pipeTo(target, streamIndex) {
1127
+ if (target instanceof Muxer) {
1128
+ // Start worker if not already running
1129
+ this.workerPromise ??= this.runWorker();
1130
+ // Start pipe task: filter.outputQueue -> output
1131
+ this.pipeToPromise = (async () => {
1132
+ while (true) {
1133
+ const packet = await this.receiveFromQueue();
1134
+ if (!packet)
1135
+ break;
1136
+ await target.writePacket(packet, streamIndex);
1137
+ }
1138
+ })();
1139
+ // Return control without pipeTo (terminal stage)
1140
+ return new SchedulerControl(this);
1141
+ }
1142
+ else {
1143
+ // BitStreamFilterAPI
1144
+ const t = target;
1145
+ // Store reference to next component for flush propagation
1146
+ this.nextComponent = t;
1147
+ // Start worker if not already running
1148
+ this.workerPromise ??= this.runWorker();
1149
+ // Start pipe task: filter.outputQueue -> target.inputQueue (via target.send)
1150
+ this.pipeToPromise = (async () => {
1151
+ while (true) {
1152
+ const packet = await this.receiveFromQueue();
1153
+ if (!packet)
1154
+ break;
1155
+ await t.sendToQueue(packet);
1156
+ }
1157
+ })();
1158
+ // Return scheduler for chaining (target is now the last component)
1159
+ return new Scheduler(this, t);
1160
+ }
1161
+ }
629
1162
  }
630
1163
  //# sourceMappingURL=bitstream-filter.js.map