node-av-lgpl 0.0.0 → 7.1.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (311) hide show
  1. package/LICENSE.md +22 -0
  2. package/README.md +711 -0
  3. package/dist/api/audio-frame-buffer.d.ts +636 -0
  4. package/dist/api/audio-frame-buffer.js +1027 -0
  5. package/dist/api/audio-frame-buffer.js.map +1 -0
  6. package/dist/api/bitstream-filter.d.ts +938 -0
  7. package/dist/api/bitstream-filter.js +1427 -0
  8. package/dist/api/bitstream-filter.js.map +1 -0
  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_h264.h264 +0 -0
  14. package/dist/api/data/test_hevc.h265 +0 -0
  15. package/dist/api/data/test_mjpeg.mjpeg +0 -0
  16. package/dist/api/data/test_vp8.ivf +0 -0
  17. package/dist/api/data/test_vp9.ivf +0 -0
  18. package/dist/api/decoder.d.ts +1413 -0
  19. package/dist/api/decoder.js +2367 -0
  20. package/dist/api/decoder.js.map +1 -0
  21. package/dist/api/demuxer.d.ts +1295 -0
  22. package/dist/api/demuxer.js +2344 -0
  23. package/dist/api/demuxer.js.map +1 -0
  24. package/dist/api/device.d.ts +589 -0
  25. package/dist/api/device.js +964 -0
  26. package/dist/api/device.js.map +1 -0
  27. package/dist/api/encoder-pool.d.ts +262 -0
  28. package/dist/api/encoder-pool.js +397 -0
  29. package/dist/api/encoder-pool.js.map +1 -0
  30. package/dist/api/encoder.d.ts +1509 -0
  31. package/dist/api/encoder.js +2619 -0
  32. package/dist/api/encoder.js.map +1 -0
  33. package/dist/api/filter-complex.d.ts +828 -0
  34. package/dist/api/filter-complex.js +1661 -0
  35. package/dist/api/filter-complex.js.map +1 -0
  36. package/dist/api/filter-presets.d.ts +800 -0
  37. package/dist/api/filter-presets.js +1554 -0
  38. package/dist/api/filter-presets.js.map +1 -0
  39. package/dist/api/filter.d.ts +1339 -0
  40. package/dist/api/filter.js +2075 -0
  41. package/dist/api/filter.js.map +1 -0
  42. package/dist/api/fmp4-stream.d.ts +797 -0
  43. package/dist/api/fmp4-stream.js +1428 -0
  44. package/dist/api/fmp4-stream.js.map +1 -0
  45. package/dist/api/hardware.d.ts +677 -0
  46. package/dist/api/hardware.js +1300 -0
  47. package/dist/api/hardware.js.map +1 -0
  48. package/dist/api/index.d.ts +21 -0
  49. package/dist/api/index.js +38 -0
  50. package/dist/api/index.js.map +1 -0
  51. package/dist/api/io-stream.d.ts +308 -0
  52. package/dist/api/io-stream.js +358 -0
  53. package/dist/api/io-stream.js.map +1 -0
  54. package/dist/api/muxer.d.ts +1311 -0
  55. package/dist/api/muxer.js +2672 -0
  56. package/dist/api/muxer.js.map +1 -0
  57. package/dist/api/pipeline.d.ts +801 -0
  58. package/dist/api/pipeline.js +1344 -0
  59. package/dist/api/pipeline.js.map +1 -0
  60. package/dist/api/probe.d.ts +128 -0
  61. package/dist/api/probe.js +227 -0
  62. package/dist/api/probe.js.map +1 -0
  63. package/dist/api/rtp-stream.d.ts +497 -0
  64. package/dist/api/rtp-stream.js +1131 -0
  65. package/dist/api/rtp-stream.js.map +1 -0
  66. package/dist/api/scaler.d.ts +561 -0
  67. package/dist/api/scaler.js +918 -0
  68. package/dist/api/scaler.js.map +1 -0
  69. package/dist/api/types.d.ts +17 -0
  70. package/dist/api/types.js +2 -0
  71. package/dist/api/types.js.map +1 -0
  72. package/dist/api/utilities/async-queue.d.ts +149 -0
  73. package/dist/api/utilities/async-queue.js +254 -0
  74. package/dist/api/utilities/async-queue.js.map +1 -0
  75. package/dist/api/utilities/audio-sample.d.ts +117 -0
  76. package/dist/api/utilities/audio-sample.js +112 -0
  77. package/dist/api/utilities/audio-sample.js.map +1 -0
  78. package/dist/api/utilities/audio-transcode.d.ts +20 -0
  79. package/dist/api/utilities/audio-transcode.js +27 -0
  80. package/dist/api/utilities/audio-transcode.js.map +1 -0
  81. package/dist/api/utilities/channel-layout.d.ts +76 -0
  82. package/dist/api/utilities/channel-layout.js +80 -0
  83. package/dist/api/utilities/channel-layout.js.map +1 -0
  84. package/dist/api/utilities/codec-format.d.ts +87 -0
  85. package/dist/api/utilities/codec-format.js +117 -0
  86. package/dist/api/utilities/codec-format.js.map +1 -0
  87. package/dist/api/utilities/context-options.d.ts +25 -0
  88. package/dist/api/utilities/context-options.js +23 -0
  89. package/dist/api/utilities/context-options.js.map +1 -0
  90. package/dist/api/utilities/electron-shared-texture.d.ts +368 -0
  91. package/dist/api/utilities/electron-shared-texture.js +540 -0
  92. package/dist/api/utilities/electron-shared-texture.js.map +1 -0
  93. package/dist/api/utilities/image.d.ts +207 -0
  94. package/dist/api/utilities/image.js +213 -0
  95. package/dist/api/utilities/image.js.map +1 -0
  96. package/dist/api/utilities/index.d.ts +14 -0
  97. package/dist/api/utilities/index.js +27 -0
  98. package/dist/api/utilities/index.js.map +1 -0
  99. package/dist/api/utilities/live-decoding.d.ts +15 -0
  100. package/dist/api/utilities/live-decoding.js +32 -0
  101. package/dist/api/utilities/live-decoding.js.map +1 -0
  102. package/dist/api/utilities/media-type.d.ts +49 -0
  103. package/dist/api/utilities/media-type.js +53 -0
  104. package/dist/api/utilities/media-type.js.map +1 -0
  105. package/dist/api/utilities/packet-age-watchdog.d.ts +198 -0
  106. package/dist/api/utilities/packet-age-watchdog.js +594 -0
  107. package/dist/api/utilities/packet-age-watchdog.js.map +1 -0
  108. package/dist/api/utilities/pixel-format.d.ts +89 -0
  109. package/dist/api/utilities/pixel-format.js +97 -0
  110. package/dist/api/utilities/pixel-format.js.map +1 -0
  111. package/dist/api/utilities/sample-format.d.ts +129 -0
  112. package/dist/api/utilities/sample-format.js +141 -0
  113. package/dist/api/utilities/sample-format.js.map +1 -0
  114. package/dist/api/utilities/scale-size.d.ts +51 -0
  115. package/dist/api/utilities/scale-size.js +55 -0
  116. package/dist/api/utilities/scale-size.js.map +1 -0
  117. package/dist/api/utilities/scheduler.d.ts +138 -0
  118. package/dist/api/utilities/scheduler.js +98 -0
  119. package/dist/api/utilities/scheduler.js.map +1 -0
  120. package/dist/api/utilities/streaming.d.ts +186 -0
  121. package/dist/api/utilities/streaming.js +309 -0
  122. package/dist/api/utilities/streaming.js.map +1 -0
  123. package/dist/api/utilities/timestamp.d.ts +193 -0
  124. package/dist/api/utilities/timestamp.js +206 -0
  125. package/dist/api/utilities/timestamp.js.map +1 -0
  126. package/dist/api/utilities/video-transcode.d.ts +218 -0
  127. package/dist/api/utilities/video-transcode.js +624 -0
  128. package/dist/api/utilities/video-transcode.js.map +1 -0
  129. package/dist/api/utilities/whisper-model.d.ts +330 -0
  130. package/dist/api/utilities/whisper-model.js +587 -0
  131. package/dist/api/utilities/whisper-model.js.map +1 -0
  132. package/dist/api/utils.d.ts +19 -0
  133. package/dist/api/utils.js +39 -0
  134. package/dist/api/utils.js.map +1 -0
  135. package/dist/api/webrtc-stream.d.ts +294 -0
  136. package/dist/api/webrtc-stream.js +546 -0
  137. package/dist/api/webrtc-stream.js.map +1 -0
  138. package/dist/api/whisper.d.ts +326 -0
  139. package/dist/api/whisper.js +402 -0
  140. package/dist/api/whisper.js.map +1 -0
  141. package/dist/constants/bsf-options.d.ts +364 -0
  142. package/dist/constants/bsf-options.js +7 -0
  143. package/dist/constants/bsf-options.js.map +1 -0
  144. package/dist/constants/channel-layouts.d.ts +53 -0
  145. package/dist/constants/channel-layouts.js +57 -0
  146. package/dist/constants/channel-layouts.js.map +1 -0
  147. package/dist/constants/constants.d.ts +2435 -0
  148. package/dist/constants/constants.js +1989 -0
  149. package/dist/constants/constants.js.map +1 -0
  150. package/dist/constants/decoders.d.ts +651 -0
  151. package/dist/constants/decoders.js +641 -0
  152. package/dist/constants/decoders.js.map +1 -0
  153. package/dist/constants/encoders.d.ts +314 -0
  154. package/dist/constants/encoders.js +309 -0
  155. package/dist/constants/encoders.js.map +1 -0
  156. package/dist/constants/filter-options.d.ts +12099 -0
  157. package/dist/constants/filter-options.js +7 -0
  158. package/dist/constants/filter-options.js.map +1 -0
  159. package/dist/constants/format-options.d.ts +4319 -0
  160. package/dist/constants/format-options.js +7 -0
  161. package/dist/constants/format-options.js.map +1 -0
  162. package/dist/constants/formats.d.ts +18 -0
  163. package/dist/constants/formats.js +7 -0
  164. package/dist/constants/formats.js.map +1 -0
  165. package/dist/constants/hardware.d.ts +26 -0
  166. package/dist/constants/hardware.js +27 -0
  167. package/dist/constants/hardware.js.map +1 -0
  168. package/dist/constants/index.d.ts +10 -0
  169. package/dist/constants/index.js +6 -0
  170. package/dist/constants/index.js.map +1 -0
  171. package/dist/constants/options.d.ts +6217 -0
  172. package/dist/constants/options.js +7 -0
  173. package/dist/constants/options.js.map +1 -0
  174. package/dist/ffmpeg/index.d.ts +101 -0
  175. package/dist/ffmpeg/index.js +161 -0
  176. package/dist/ffmpeg/index.js.map +1 -0
  177. package/dist/ffmpeg/version.d.ts +6 -0
  178. package/dist/ffmpeg/version.js +7 -0
  179. package/dist/ffmpeg/version.js.map +1 -0
  180. package/dist/index.d.ts +4 -0
  181. package/dist/index.js +9 -0
  182. package/dist/index.js.map +1 -0
  183. package/dist/lib/audio-fifo.d.ts +399 -0
  184. package/dist/lib/audio-fifo.js +431 -0
  185. package/dist/lib/audio-fifo.js.map +1 -0
  186. package/dist/lib/binding.d.ts +242 -0
  187. package/dist/lib/binding.js +102 -0
  188. package/dist/lib/binding.js.map +1 -0
  189. package/dist/lib/bitstream-filter-context.d.ts +381 -0
  190. package/dist/lib/bitstream-filter-context.js +443 -0
  191. package/dist/lib/bitstream-filter-context.js.map +1 -0
  192. package/dist/lib/bitstream-filter.d.ts +140 -0
  193. package/dist/lib/bitstream-filter.js +154 -0
  194. package/dist/lib/bitstream-filter.js.map +1 -0
  195. package/dist/lib/codec-context.d.ts +1069 -0
  196. package/dist/lib/codec-context.js +1336 -0
  197. package/dist/lib/codec-context.js.map +1 -0
  198. package/dist/lib/codec-parameters.d.ts +664 -0
  199. package/dist/lib/codec-parameters.js +813 -0
  200. package/dist/lib/codec-parameters.js.map +1 -0
  201. package/dist/lib/codec-parser.d.ts +201 -0
  202. package/dist/lib/codec-parser.js +213 -0
  203. package/dist/lib/codec-parser.js.map +1 -0
  204. package/dist/lib/codec.d.ts +617 -0
  205. package/dist/lib/codec.js +746 -0
  206. package/dist/lib/codec.js.map +1 -0
  207. package/dist/lib/device.d.ts +294 -0
  208. package/dist/lib/device.js +326 -0
  209. package/dist/lib/device.js.map +1 -0
  210. package/dist/lib/dictionary.d.ts +333 -0
  211. package/dist/lib/dictionary.js +372 -0
  212. package/dist/lib/dictionary.js.map +1 -0
  213. package/dist/lib/error.d.ts +311 -0
  214. package/dist/lib/error.js +395 -0
  215. package/dist/lib/error.js.map +1 -0
  216. package/dist/lib/fifo.d.ts +416 -0
  217. package/dist/lib/fifo.js +453 -0
  218. package/dist/lib/fifo.js.map +1 -0
  219. package/dist/lib/filter-context.d.ts +714 -0
  220. package/dist/lib/filter-context.js +783 -0
  221. package/dist/lib/filter-context.js.map +1 -0
  222. package/dist/lib/filter-graph-segment.d.ts +161 -0
  223. package/dist/lib/filter-graph-segment.js +172 -0
  224. package/dist/lib/filter-graph-segment.js.map +1 -0
  225. package/dist/lib/filter-graph.d.ts +641 -0
  226. package/dist/lib/filter-graph.js +704 -0
  227. package/dist/lib/filter-graph.js.map +1 -0
  228. package/dist/lib/filter-inout.d.ts +202 -0
  229. package/dist/lib/filter-inout.js +261 -0
  230. package/dist/lib/filter-inout.js.map +1 -0
  231. package/dist/lib/filter.d.ts +243 -0
  232. package/dist/lib/filter.js +272 -0
  233. package/dist/lib/filter.js.map +1 -0
  234. package/dist/lib/format-context.d.ts +1335 -0
  235. package/dist/lib/format-context.js +1455 -0
  236. package/dist/lib/format-context.js.map +1 -0
  237. package/dist/lib/frame-utils.d.ts +116 -0
  238. package/dist/lib/frame-utils.js +98 -0
  239. package/dist/lib/frame-utils.js.map +1 -0
  240. package/dist/lib/frame.d.ts +1315 -0
  241. package/dist/lib/frame.js +1535 -0
  242. package/dist/lib/frame.js.map +1 -0
  243. package/dist/lib/hardware-device-context.d.ts +362 -0
  244. package/dist/lib/hardware-device-context.js +383 -0
  245. package/dist/lib/hardware-device-context.js.map +1 -0
  246. package/dist/lib/hardware-frames-context.d.ts +418 -0
  247. package/dist/lib/hardware-frames-context.js +471 -0
  248. package/dist/lib/hardware-frames-context.js.map +1 -0
  249. package/dist/lib/index.d.ts +35 -0
  250. package/dist/lib/index.js +60 -0
  251. package/dist/lib/index.js.map +1 -0
  252. package/dist/lib/input-format.d.ts +249 -0
  253. package/dist/lib/input-format.js +306 -0
  254. package/dist/lib/input-format.js.map +1 -0
  255. package/dist/lib/io-context.d.ts +698 -0
  256. package/dist/lib/io-context.js +771 -0
  257. package/dist/lib/io-context.js.map +1 -0
  258. package/dist/lib/log.d.ts +174 -0
  259. package/dist/lib/log.js +184 -0
  260. package/dist/lib/log.js.map +1 -0
  261. package/dist/lib/native-types.d.ts +1024 -0
  262. package/dist/lib/native-types.js +2 -0
  263. package/dist/lib/native-types.js.map +1 -0
  264. package/dist/lib/option.d.ts +953 -0
  265. package/dist/lib/option.js +1607 -0
  266. package/dist/lib/option.js.map +1 -0
  267. package/dist/lib/output-format.d.ts +222 -0
  268. package/dist/lib/output-format.js +259 -0
  269. package/dist/lib/output-format.js.map +1 -0
  270. package/dist/lib/packet.d.ts +521 -0
  271. package/dist/lib/packet.js +613 -0
  272. package/dist/lib/packet.js.map +1 -0
  273. package/dist/lib/rational.d.ts +251 -0
  274. package/dist/lib/rational.js +278 -0
  275. package/dist/lib/rational.js.map +1 -0
  276. package/dist/lib/software-resample-context.d.ts +552 -0
  277. package/dist/lib/software-resample-context.js +592 -0
  278. package/dist/lib/software-resample-context.js.map +1 -0
  279. package/dist/lib/software-scale-context.d.ts +344 -0
  280. package/dist/lib/software-scale-context.js +366 -0
  281. package/dist/lib/software-scale-context.js.map +1 -0
  282. package/dist/lib/stream.d.ts +383 -0
  283. package/dist/lib/stream.js +524 -0
  284. package/dist/lib/stream.js.map +1 -0
  285. package/dist/lib/sync-queue.d.ts +179 -0
  286. package/dist/lib/sync-queue.js +197 -0
  287. package/dist/lib/sync-queue.js.map +1 -0
  288. package/dist/lib/types.d.ts +34 -0
  289. package/dist/lib/types.js +2 -0
  290. package/dist/lib/types.js.map +1 -0
  291. package/dist/lib/utilities.d.ts +1198 -0
  292. package/dist/lib/utilities.js +1302 -0
  293. package/dist/lib/utilities.js.map +1 -0
  294. package/dist/utils/electron.d.ts +49 -0
  295. package/dist/utils/electron.js +63 -0
  296. package/dist/utils/electron.js.map +1 -0
  297. package/dist/utils/index.d.ts +6 -0
  298. package/dist/utils/index.js +7 -0
  299. package/dist/utils/index.js.map +1 -0
  300. package/dist/utils/libc.d.ts +11 -0
  301. package/dist/utils/libc.js +35 -0
  302. package/dist/utils/libc.js.map +1 -0
  303. package/dist/utils/variant.d.ts +26 -0
  304. package/dist/utils/variant.js +31 -0
  305. package/dist/utils/variant.js.map +1 -0
  306. package/dist/webrtc/index.d.ts +4 -0
  307. package/dist/webrtc/index.js +7 -0
  308. package/dist/webrtc/index.js.map +1 -0
  309. package/install/check.js +124 -0
  310. package/install/ffmpeg.js +66 -0
  311. package/package.json +165 -3
@@ -0,0 +1,1427 @@
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 { AV_PKT_DATA_NEW_EXTRADATA, 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 { Stream } from '../lib/stream.js';
59
+ import { PACKET_THREAD_QUEUE_SIZE } from './constants.js';
60
+ import { Encoder } from './encoder.js';
61
+ import { Muxer } from './muxer.js';
62
+ import { AsyncQueue } from './utilities/async-queue.js';
63
+ import { Scheduler, SchedulerControl } from './utilities/scheduler.js';
64
+ /**
65
+ * High-level bitstream filter for packet processing.
66
+ *
67
+ * Provides simplified interface for applying bitstream filters to packets.
68
+ * Handles filter initialization, packet processing, and memory management.
69
+ * Supports both synchronous packet-by-packet filtering and async iteration over packets.
70
+ * Supports filters like h264_mp4toannexb, hevc_mp4toannexb, aac_adtstoasc.
71
+ * Essential for format conversion and stream compatibility in transcoding pipelines.
72
+ *
73
+ * @example
74
+ * ```typescript
75
+ * import { BitStreamFilterAPI } from 'node-av/api';
76
+ *
77
+ * // Create H.264 Annex B converter
78
+ * const filter = BitStreamFilterAPI.create('h264_mp4toannexb', stream);
79
+ *
80
+ * // Filter packet
81
+ * const outputPackets = await filter.filterAll(inputPacket);
82
+ * for (const packet of outputPackets) {
83
+ * await output.writePacket(packet);
84
+ * packet.free();
85
+ * }
86
+ * ```
87
+ *
88
+ * @example
89
+ * ```typescript
90
+ * // Filter packet stream
91
+ * const filter = BitStreamFilterAPI.create('hevc_mp4toannexb', videoStream);
92
+ *
93
+ * for await (const packet of filter.packets(input.packets())) {
94
+ * await output.writePacket(packet);
95
+ * packet.free();
96
+ * }
97
+ * ```
98
+ *
99
+ * @see {@link BitStreamFilter} For available filters
100
+ * @see {@link BitStreamFilterContext} For low-level API
101
+ * @see {@link Muxer} For writing filtered packets
102
+ */
103
+ export class BitStreamFilterAPI {
104
+ ctx;
105
+ bsf;
106
+ source;
107
+ initialized = false;
108
+ packet;
109
+ pendingOutput = [];
110
+ isClosed = false;
111
+ // Worker pattern for push-based processing
112
+ inputQueue;
113
+ outputQueue;
114
+ workerPromise = null;
115
+ nextComponent = null;
116
+ pipeToPromise = null;
117
+ signal;
118
+ /**
119
+ * @param bsf - Bitstream filter
120
+ *
121
+ * @param ctx - Filter context
122
+ *
123
+ * @param source - Input source for lazy parameter resolution
124
+ *
125
+ * @internal
126
+ */
127
+ constructor(bsf, ctx, source) {
128
+ this.bsf = bsf;
129
+ this.ctx = ctx;
130
+ this.source = source;
131
+ this.packet = new Packet();
132
+ this.packet.alloc();
133
+ this.inputQueue = new AsyncQueue(PACKET_THREAD_QUEUE_SIZE, (p) => p.free());
134
+ this.outputQueue = new AsyncQueue(PACKET_THREAD_QUEUE_SIZE, (p) => p.free());
135
+ }
136
+ /**
137
+ * Create a bitstream filter.
138
+ *
139
+ * The input source provides the codec parameters the filter is configured with.
140
+ * Pass a {@link Stream} to filter its packets directly (stream copy), or an
141
+ * {@link Encoder} to filter that encoder's output (transcode) - parameters are
142
+ * derived from the encoder once it is open. Another {@link BitStreamFilterAPI}
143
+ * may be passed to chain filters.
144
+ *
145
+ * Initialization is lazy: filter options are validated immediately, but the
146
+ * input parameters are bound and the filter is initialized on the first packet,
147
+ * so an `Encoder` source (opened lazily on its first frame) is ready in time.
148
+ *
149
+ * Direct mapping to av_bsf_get_by_name() and av_bsf_alloc().
150
+ *
151
+ * @param filterName - Name of the bitstream filter
152
+ *
153
+ * @param source - Input source: a `Stream` (copy), `Encoder` (transcode), or upstream filter (chain)
154
+ *
155
+ * @param filterOptions - Optional filter-specific options
156
+ *
157
+ * @returns Configured bitstream filter
158
+ *
159
+ * @throws {FFmpegError} If the filter is not found, allocation fails, or an option is invalid
160
+ *
161
+ * @example
162
+ * ```typescript
163
+ * // Stream copy: H.264 MP4 to Annex B conversion
164
+ * const filter = BitStreamFilterAPI.create('h264_mp4toannexb', videoStream);
165
+ * ```
166
+ *
167
+ * @example
168
+ * ```typescript
169
+ * // Transcode: derive parameters from the encoder's output
170
+ * const filter = BitStreamFilterAPI.create('h264_metadata', encoder, {
171
+ * options: { aud: 'remove', level: '4.1' },
172
+ * });
173
+ * pipeline(input, decoder, encoder, filter, output);
174
+ * ```
175
+ *
176
+ * @see {@link BitStreamFilter.getByName} For filter discovery
177
+ * @see {@link BitstreamFilterOptions} For available options
178
+ */
179
+ // eslint-disable-next-line space-before-function-paren
180
+ static create(filterName, source, filterOptions) {
181
+ if (!source) {
182
+ throw new Error('A source (Stream, Encoder, or BitStreamFilterAPI) is required');
183
+ }
184
+ // Find the bitstream filter
185
+ const filter = BitStreamFilter.getByName(filterName);
186
+ if (!filter) {
187
+ throw new FFmpegError(AVERROR_BSF_NOT_FOUND);
188
+ }
189
+ // Create and allocate context
190
+ const ctx = new BitStreamFilterContext();
191
+ const allocRet = ctx.alloc(filter);
192
+ FFmpegError.throwIfError(allocRet, 'Failed to allocate bitstream filter context');
193
+ try {
194
+ // Apply (and validate) filter-specific options now; input parameters and
195
+ // init() are deferred to ensureInitialized() on the first packet.
196
+ if (filterOptions?.options) {
197
+ for (const [key, value] of Object.entries(filterOptions.options)) {
198
+ const ret = ctx.setOption(key, value);
199
+ FFmpegError.throwIfError(ret, `Failed to set bitstream filter option '${key}'`);
200
+ }
201
+ }
202
+ const bsfApi = new BitStreamFilterAPI(filter, ctx, source);
203
+ if (filterOptions?.signal) {
204
+ filterOptions.signal.throwIfAborted();
205
+ bsfApi.signal = filterOptions.signal;
206
+ }
207
+ return bsfApi;
208
+ }
209
+ catch (error) {
210
+ // Clean up on error
211
+ ctx.free();
212
+ throw error;
213
+ }
214
+ }
215
+ /**
216
+ * Get filter name.
217
+ *
218
+ * @example
219
+ * ```typescript
220
+ * console.log(`Using filter: ${filter.name}`);
221
+ * ```
222
+ */
223
+ get name() {
224
+ return this.bsf.name ?? 'unknown';
225
+ }
226
+ /**
227
+ * Get output codec parameters.
228
+ *
229
+ * Parameters after filter processing.
230
+ * May differ from input parameters.
231
+ *
232
+ * @example
233
+ * ```typescript
234
+ * const outputParams = filter.outputCodecParameters;
235
+ * console.log(`Output codec: ${outputParams?.codecId}`);
236
+ * ```
237
+ */
238
+ get outputCodecParameters() {
239
+ return this.ctx.outputCodecParameters;
240
+ }
241
+ /**
242
+ * Get output time base.
243
+ *
244
+ * Time base after filter processing.
245
+ *
246
+ * @example
247
+ * ```typescript
248
+ * const tb = filter.outputTimeBase;
249
+ * console.log(`Output timebase: ${tb?.num}/${tb?.den}`);
250
+ * ```
251
+ */
252
+ get outputTimeBase() {
253
+ return this.ctx.outputTimeBase;
254
+ }
255
+ /**
256
+ * Check if filter is open.
257
+ *
258
+ * @example
259
+ * ```typescript
260
+ * if (filter.isBitstreamFilterOpen) {
261
+ * const packet = await filter.process(frame);
262
+ * }
263
+ * ```
264
+ */
265
+ get isBitstreamFilterOpen() {
266
+ return !this.isClosed;
267
+ }
268
+ /**
269
+ * Check if the filter has been initialized.
270
+ *
271
+ * Initialization is lazy and happens on the first processed packet, after
272
+ * which {@link outputCodecParameters} reflect the filter's output.
273
+ *
274
+ * @example
275
+ * ```typescript
276
+ * if (filter.isInitialized) {
277
+ * const params = filter.outputCodecParameters;
278
+ * }
279
+ * ```
280
+ */
281
+ get isInitialized() {
282
+ return this.initialized;
283
+ }
284
+ /**
285
+ * Get associated stream.
286
+ *
287
+ * Returns the stream this filter was created for. Only available when the
288
+ * filter was created from a {@link Stream}; filters created from an `Encoder`
289
+ * derive their parameters from the encoder's output instead.
290
+ *
291
+ * @returns Associated stream
292
+ *
293
+ * @throws {Error} If the filter was not created from a stream
294
+ *
295
+ * @example
296
+ * ```typescript
297
+ * const stream = filter.getStream();
298
+ * console.log(`Filtering stream ${stream.index}`);
299
+ * ```
300
+ */
301
+ getStream() {
302
+ if (!(this.source instanceof Stream)) {
303
+ throw new Error('No associated stream: this bitstream filter derives its parameters from an upstream component');
304
+ }
305
+ return this.source;
306
+ }
307
+ /**
308
+ * Send a packet to the filter.
309
+ *
310
+ * Sends a packet to the filter for processing.
311
+ * Does not return filtered packets - use {@link receive} to retrieve packets.
312
+ * A single packet can produce zero, one, or multiple packets depending on filter.
313
+ *
314
+ * **Important**: This method only SENDS the packet to the filter.
315
+ * You must call {@link receive} separately (potentially multiple times) to get filtered packets.
316
+ *
317
+ * Direct mapping to av_bsf_send_packet().
318
+ *
319
+ * @param packet - Packet to send to filter, or null to flush
320
+ *
321
+ * @throws {FFmpegError} If sending fails
322
+ *
323
+ * @example
324
+ * ```typescript
325
+ * // Send packet and receive filtered packets
326
+ * await filter.filter(inputPacket);
327
+ *
328
+ * // Receive all available filtered packets
329
+ * while (true) {
330
+ * const outPacket = await filter.receive();
331
+ * if (!outPacket) break;
332
+ * console.log(`Filtered packet with PTS: ${outPacket.pts}`);
333
+ * await output.writePacket(outPacket);
334
+ * outPacket.free();
335
+ * }
336
+ * ```
337
+ *
338
+ * @example
339
+ * ```typescript
340
+ * for await (const packet of input.packets()) {
341
+ * // packet is null at end of stream - automatically flushes filter
342
+ * await filter.filter(packet);
343
+ *
344
+ * // Receive available filtered packets
345
+ * let outPacket;
346
+ * while ((outPacket = await filter.receive())) {
347
+ * await output.writePacket(outPacket);
348
+ * outPacket.free();
349
+ * }
350
+ * }
351
+ * ```
352
+ *
353
+ * @see {@link receive} For receiving filtered packets
354
+ * @see {@link filterAll} For combined send+receive operation
355
+ * @see {@link packets} For automatic packet iteration
356
+ * @see {@link flush} For end-of-stream handling
357
+ * @see {@link filterSync} For synchronous version
358
+ */
359
+ async filter(packet) {
360
+ this.signal?.throwIfAborted();
361
+ if (this.isClosed) {
362
+ return;
363
+ }
364
+ this.ensureInitialized();
365
+ // Send packet to filter (null signals EOF/flush)
366
+ await this.sendPacketWithRetry(packet);
367
+ }
368
+ /**
369
+ * Send a packet to the filter synchronously.
370
+ * Synchronous version of filter.
371
+ *
372
+ * Sends a packet to the filter for processing.
373
+ * Does not return filtered packets - use {@link receiveSync} to retrieve packets.
374
+ * A single packet can produce zero, one, or multiple packets depending on filter.
375
+ *
376
+ * **Important**: This method only SENDS the packet to the filter.
377
+ * You must call {@link receiveSync} separately (potentially multiple times) to get filtered packets.
378
+ *
379
+ * Direct mapping to av_bsf_send_packet().
380
+ *
381
+ * @param packet - Packet to send to filter, or null to flush
382
+ *
383
+ * @throws {FFmpegError} If sending fails
384
+ *
385
+ * @example
386
+ * ```typescript
387
+ * // Send packet and receive filtered packets
388
+ * filter.filterSync(inputPacket);
389
+ *
390
+ * // Receive all available filtered packets
391
+ * while (true) {
392
+ * const outPacket = filter.receiveSync();
393
+ * if (!outPacket) break;
394
+ * console.log(`Filtered packet with PTS: ${outPacket.pts}`);
395
+ * output.writePacketSync(outPacket);
396
+ * outPacket.free();
397
+ * }
398
+ * ```
399
+ *
400
+ * @example
401
+ * ```typescript
402
+ * for (const packet of packets) {
403
+ * // packet is null at end of stream - automatically flushes filter
404
+ * filter.filterSync(packet);
405
+ *
406
+ * // Receive available filtered packets
407
+ * let outPacket;
408
+ * while ((outPacket = filter.receiveSync())) {
409
+ * output.writePacketSync(outPacket);
410
+ * outPacket.free();
411
+ * }
412
+ * }
413
+ * ```
414
+ *
415
+ * @see {@link receiveSync} For receiving filtered packets
416
+ * @see {@link filterAllSync} For combined send+receive operation
417
+ * @see {@link packetsSync} For automatic packet iteration
418
+ * @see {@link flushSync} For end-of-stream handling
419
+ * @see {@link filter} For async version
420
+ */
421
+ filterSync(packet) {
422
+ if (this.isClosed) {
423
+ return;
424
+ }
425
+ this.ensureInitialized();
426
+ // Send packet to filter (null signals EOF/flush)
427
+ this.sendPacketWithRetrySync(packet);
428
+ }
429
+ /**
430
+ * Filter a packet to packets.
431
+ *
432
+ * Sends a packet to the filter and receives all available filtered packets.
433
+ * Returns array of packets - may be empty if filter needs more data.
434
+ * One packet can produce zero, one, or multiple packets depending on filter.
435
+ *
436
+ * Direct mapping to av_bsf_send_packet() and av_bsf_receive_packet().
437
+ *
438
+ * @param packet - Packet to filter, or null to flush
439
+ *
440
+ * @returns Array of filtered packets (empty if more data needed or filter is closed)
441
+ *
442
+ * @throws {FFmpegError} If filtering fails
443
+ *
444
+ * @example
445
+ * ```typescript
446
+ * const outputPackets = await filter.filterAll(inputPacket);
447
+ * for (const packet of outputPackets) {
448
+ * console.log(`Filtered packet: pts=${packet.pts}`);
449
+ * await output.writePacket(packet);
450
+ * packet.free();
451
+ * }
452
+ * ```
453
+ *
454
+ * @example
455
+ * ```typescript
456
+ * // Flush remaining packets at end of stream
457
+ * const remaining = await filter.filterAll(null);
458
+ * for (const packet of remaining) {
459
+ * await output.writePacket(packet);
460
+ * packet.free();
461
+ * }
462
+ * ```
463
+ *
464
+ * @see {@link filter} For single packet filtering
465
+ * @see {@link packets} For stream processing
466
+ * @see {@link flush} For end-of-stream handling
467
+ * @see {@link filterAllSync} For synchronous version
468
+ */
469
+ async filterAll(packet) {
470
+ this.signal?.throwIfAborted();
471
+ await this.filter(packet);
472
+ // Receive all output packets
473
+ const outputPackets = [];
474
+ while (true) {
475
+ const outPacket = await this.receive();
476
+ if (!outPacket)
477
+ break;
478
+ outputPackets.push(outPacket);
479
+ }
480
+ return outputPackets;
481
+ }
482
+ /**
483
+ * Filter a packet to packets synchronously.
484
+ * Synchronous version of filterAll.
485
+ *
486
+ * Sends a packet to the filter and receives all available filtered packets.
487
+ * Returns array of packets - may be empty if filter needs more data.
488
+ * One packet can produce zero, one, or multiple packets depending on filter.
489
+ *
490
+ * Direct mapping to av_bsf_send_packet() and av_bsf_receive_packet().
491
+ *
492
+ * @param packet - Packet to filter, or null to flush
493
+ *
494
+ * @returns Array of filtered packets (empty if more data needed or filter is closed)
495
+ *
496
+ * @throws {FFmpegError} If filtering fails
497
+ *
498
+ * @example
499
+ * ```typescript
500
+ * const outputPackets = filter.filterAllSync(inputPacket);
501
+ * for (const packet of outputPackets) {
502
+ * console.log(`Filtered packet: pts=${packet.pts}`);
503
+ * output.writePacketSync(packet);
504
+ * packet.free();
505
+ * }
506
+ * ```
507
+ *
508
+ * @example
509
+ * ```typescript
510
+ * // Flush remaining packets at end of stream
511
+ * const remaining = filter.filterAllSync(null);
512
+ * for (const packet of remaining) {
513
+ * output.writePacketSync(packet);
514
+ * packet.free();
515
+ * }
516
+ * ```
517
+ *
518
+ * @see {@link filterSync} For single packet filtering
519
+ * @see {@link packetsSync} For stream processing
520
+ * @see {@link flushSync} For end-of-stream handling
521
+ * @see {@link filterAll} For async version
522
+ */
523
+ filterAllSync(packet) {
524
+ this.filterSync(packet);
525
+ // Receive all output packets
526
+ const outputPackets = [];
527
+ while (true) {
528
+ const outPacket = this.receiveSync();
529
+ if (!outPacket)
530
+ break;
531
+ outputPackets.push(outPacket);
532
+ }
533
+ return outputPackets;
534
+ }
535
+ /**
536
+ * Filter packet stream to filtered packet stream.
537
+ *
538
+ * High-level async generator for complete filtering pipeline.
539
+ * Filter is only flushed when EOF (null) signal is explicitly received.
540
+ * Primary interface for stream-based filtering.
541
+ *
542
+ * **EOF Handling:**
543
+ * - Send null to flush filter and get remaining buffered packets
544
+ * - Generator yields null after flushing when null is received
545
+ * - No automatic flushing - filter stays open until EOF or close()
546
+ *
547
+ * @param packets - Async iterable of packets, single packet, or null to flush
548
+ *
549
+ * @yields {Packet | null} Filtered packets, followed by null when explicitly flushed
550
+ *
551
+ * @throws {FFmpegError} If filtering fails
552
+ *
553
+ * @example
554
+ * ```typescript
555
+ * // Stream of packets with automatic EOF propagation
556
+ * for await (const packet of filter.packets(input.packets())) {
557
+ * if (packet === null) {
558
+ * console.log('Filter flushed');
559
+ * break;
560
+ * }
561
+ * await output.writePacket(packet);
562
+ * packet.free(); // Must free output packets
563
+ * }
564
+ * ```
565
+ *
566
+ * @example
567
+ * ```typescript
568
+ * // Single packet - no automatic flush
569
+ * for await (const packet of filter.packets(singlePacket)) {
570
+ * await output.writePacket(packet);
571
+ * packet.free();
572
+ * }
573
+ * // Filter remains open, buffered packets not flushed
574
+ * ```
575
+ *
576
+ * @example
577
+ * ```typescript
578
+ * // Explicit flush with EOF
579
+ * for await (const packet of filter.packets(null)) {
580
+ * if (packet === null) {
581
+ * console.log('All buffered packets flushed');
582
+ * break;
583
+ * }
584
+ * console.log('Buffered packet:', packet.pts);
585
+ * await output.writePacket(packet);
586
+ * packet.free();
587
+ * }
588
+ * ```
589
+ *
590
+ * @see {@link filter} For single packet filtering
591
+ * @see {@link Demuxer.packets} For packet source
592
+ * @see {@link packetsSync} For sync version
593
+ */
594
+ async *packets(packets) {
595
+ const self = this;
596
+ const processPacket = async function* (packet) {
597
+ await self.filter(packet);
598
+ while (true) {
599
+ const outPacket = await self.receive();
600
+ if (!outPacket)
601
+ break;
602
+ yield outPacket;
603
+ }
604
+ }.bind(this);
605
+ const finalize = async function* () {
606
+ for await (const remaining of self.flushPackets()) {
607
+ yield remaining;
608
+ }
609
+ yield null;
610
+ }.bind(this);
611
+ if (packets === null) {
612
+ yield* finalize();
613
+ return;
614
+ }
615
+ if (packets instanceof Packet) {
616
+ yield* processPacket(packets);
617
+ return;
618
+ }
619
+ for await (const packet_1 of packets) {
620
+ const env_1 = { stack: [], error: void 0, hasError: false };
621
+ try {
622
+ const packet = __addDisposableResource(env_1, packet_1, false);
623
+ this.signal?.throwIfAborted();
624
+ if (packet === null) {
625
+ yield* finalize();
626
+ return;
627
+ }
628
+ yield* processPacket(packet);
629
+ }
630
+ catch (e_1) {
631
+ env_1.error = e_1;
632
+ env_1.hasError = true;
633
+ }
634
+ finally {
635
+ __disposeResources(env_1);
636
+ }
637
+ }
638
+ }
639
+ /**
640
+ * Filter packet stream to filtered packet stream synchronously.
641
+ * Synchronous version of packets.
642
+ *
643
+ * High-level sync generator for complete filtering pipeline.
644
+ * Filter is only flushed when EOF (null) signal is explicitly received.
645
+ * Primary interface for stream-based filtering.
646
+ *
647
+ * **EOF Handling:**
648
+ * - Send null to flush filter and get remaining buffered packets
649
+ * - Generator yields null after flushing when null is received
650
+ * - No automatic flushing - filter stays open until EOF or close()
651
+ *
652
+ * @param packets - Iterable of packets, single packet, or null to flush
653
+ *
654
+ * @yields {Packet | null} Filtered packets, followed by null when explicitly flushed
655
+ *
656
+ * @throws {FFmpegError} If filtering fails
657
+ *
658
+ * @example
659
+ * ```typescript
660
+ * // Stream of packets with automatic EOF propagation
661
+ * for (const packet of filter.packetsSync(inputPackets)) {
662
+ * if (packet === null) {
663
+ * console.log('Filter flushed');
664
+ * break;
665
+ * }
666
+ * output.writePacketSync(packet);
667
+ * packet.free(); // Must free output packets
668
+ * }
669
+ * ```
670
+ *
671
+ * @example
672
+ * ```typescript
673
+ * // Single packet - no automatic flush
674
+ * for (const packet of filter.packetsSync(singlePacket)) {
675
+ * output.writePacketSync(packet);
676
+ * packet.free();
677
+ * }
678
+ * // Filter remains open, buffered packets not flushed
679
+ * ```
680
+ *
681
+ * @example
682
+ * ```typescript
683
+ * // Explicit flush with EOF
684
+ * for (const packet of filter.packetsSync(null)) {
685
+ * if (packet === null) {
686
+ * console.log('All buffered packets flushed');
687
+ * break;
688
+ * }
689
+ * console.log('Buffered packet:', packet.pts);
690
+ * output.writePacketSync(packet);
691
+ * packet.free();
692
+ * }
693
+ * ```
694
+ *
695
+ * @see {@link filterSync} For single packet filtering
696
+ * @see {@link packets} For async version
697
+ */
698
+ *packetsSync(packets) {
699
+ const self = this;
700
+ const processPacket = function* (packet) {
701
+ self.filterSync(packet);
702
+ while (true) {
703
+ const outPacket = self.receiveSync();
704
+ if (!outPacket)
705
+ break;
706
+ yield outPacket;
707
+ }
708
+ }.bind(this);
709
+ const finalize = function* () {
710
+ for (const remaining of self.flushPacketsSync()) {
711
+ yield remaining;
712
+ }
713
+ yield null;
714
+ }.bind(this);
715
+ if (packets === null) {
716
+ yield* finalize();
717
+ return;
718
+ }
719
+ if (packets instanceof Packet) {
720
+ yield* processPacket(packets);
721
+ return;
722
+ }
723
+ for (const packet_2 of packets) {
724
+ const env_2 = { stack: [], error: void 0, hasError: false };
725
+ try {
726
+ const packet = __addDisposableResource(env_2, packet_2, false);
727
+ if (packet === null) {
728
+ yield* finalize();
729
+ return;
730
+ }
731
+ yield* processPacket(packet);
732
+ }
733
+ catch (e_2) {
734
+ env_2.error = e_2;
735
+ env_2.hasError = true;
736
+ }
737
+ finally {
738
+ __disposeResources(env_2);
739
+ }
740
+ }
741
+ }
742
+ /**
743
+ * Flush filter and signal end-of-stream.
744
+ *
745
+ * Sends null packet to filter to signal end-of-stream.
746
+ * Does nothing if filter is closed.
747
+ * Must call receive() or flushPackets() to get remaining buffered packets.
748
+ * Does not reset filter state - use {@link reset} for that.
749
+ *
750
+ * Direct mapping to av_bsf_send_packet(NULL).
751
+ *
752
+ * @throws {FFmpegError} If flush fails
753
+ *
754
+ * @example
755
+ * ```typescript
756
+ * // Signal end of stream
757
+ * await filter.flush();
758
+ *
759
+ * // Then get remaining packets
760
+ * let packet;
761
+ * while ((packet = await filter.receive()) !== null) {
762
+ * console.log('Got buffered packet');
763
+ * await output.writePacket(packet);
764
+ * packet.free();
765
+ * }
766
+ * ```
767
+ *
768
+ * @see {@link flushPackets} For async iteration
769
+ * @see {@link receive} For getting buffered packets
770
+ * @see {@link reset} For state reset only
771
+ * @see {@link flushSync} For synchronous version
772
+ */
773
+ async flush() {
774
+ this.signal?.throwIfAborted();
775
+ if (this.isClosed || !this.initialized) {
776
+ return;
777
+ }
778
+ // Send EOF only - resetting via av_bsf_flush() here would discard the
779
+ // packets that buffering filters (vp9_superframe, setts, ...) still hold.
780
+ await this.sendPacketWithRetry(null);
781
+ }
782
+ /**
783
+ * Flush filter and signal end-of-stream synchronously.
784
+ * Synchronous version of flush.
785
+ *
786
+ * Sends null packet to filter to signal end-of-stream.
787
+ * Does nothing if filter is closed.
788
+ * Must call receiveSync() or flushPacketsSync() to get remaining buffered packets.
789
+ * Does not reset filter state - use {@link reset} for that.
790
+ *
791
+ * Direct mapping to av_bsf_send_packet(NULL).
792
+ *
793
+ * @throws {FFmpegError} If flush fails
794
+ *
795
+ * @example
796
+ * ```typescript
797
+ * // Signal end of stream
798
+ * filter.flushSync();
799
+ *
800
+ * // Then get remaining packets
801
+ * let packet;
802
+ * while ((packet = filter.receiveSync()) !== null) {
803
+ * console.log('Got buffered packet');
804
+ * output.writePacketSync(packet);
805
+ * packet.free();
806
+ * }
807
+ * ```
808
+ *
809
+ * @see {@link flushPacketsSync} For sync iteration
810
+ * @see {@link receiveSync} For getting buffered packets
811
+ * @see {@link reset} For state reset only
812
+ * @see {@link flush} For async version
813
+ */
814
+ flushSync() {
815
+ if (this.isClosed || !this.initialized) {
816
+ return;
817
+ }
818
+ // See flush(): send EOF only, never av_bsf_flush()
819
+ this.sendPacketWithRetrySync(null);
820
+ }
821
+ /**
822
+ * Receive packet from filter.
823
+ *
824
+ * Gets filtered packets from the filter's internal buffer.
825
+ * Handles packet allocation and error checking.
826
+ * Returns null if filter is closed or no packets available.
827
+ * Call repeatedly until null to drain all buffered packets.
828
+ *
829
+ * Direct mapping to av_bsf_receive_packet().
830
+ *
831
+ * @returns Cloned packet or null if no packets available
832
+ *
833
+ * @throws {FFmpegError} If receive fails with error other than AVERROR_EAGAIN or AVERROR_EOF
834
+ *
835
+ * @throws {Error} If packet cloning fails (out of memory)
836
+ *
837
+ * @example
838
+ * ```typescript
839
+ * const packet = await filter.receive();
840
+ * if (packet) {
841
+ * console.log('Got filtered packet');
842
+ * await output.writePacket(packet);
843
+ * packet.free();
844
+ * }
845
+ * ```
846
+ *
847
+ * @example
848
+ * ```typescript
849
+ * // Drain all buffered packets
850
+ * let packet;
851
+ * while ((packet = await filter.receive()) !== null) {
852
+ * console.log(`Packet PTS: ${packet.pts}`);
853
+ * await output.writePacket(packet);
854
+ * packet.free();
855
+ * }
856
+ * ```
857
+ *
858
+ * @see {@link filter} For filtering packets
859
+ * @see {@link flush} For signaling end-of-stream
860
+ * @see {@link receiveSync} For synchronous version
861
+ */
862
+ async receive() {
863
+ if (this.isClosed || !this.initialized) {
864
+ return null;
865
+ }
866
+ // Deliver output buffered by an EAGAIN-triggered drain first (FIFO order)
867
+ const pending = this.pendingOutput.shift();
868
+ if (pending) {
869
+ return pending;
870
+ }
871
+ return await this.receiveFromContext();
872
+ }
873
+ /**
874
+ * Receive packet from filter synchronously.
875
+ * Synchronous version of receive.
876
+ *
877
+ * Gets filtered packets from the filter's internal buffer.
878
+ * Handles packet allocation and error checking.
879
+ * Returns null if filter is closed or no packets available.
880
+ * Call repeatedly until null to drain all buffered packets.
881
+ *
882
+ * Direct mapping to av_bsf_receive_packet().
883
+ *
884
+ * @returns Cloned packet or null if no packets available
885
+ *
886
+ * @throws {FFmpegError} If receive fails with error other than AVERROR_EAGAIN or AVERROR_EOF
887
+ *
888
+ * @throws {Error} If packet cloning fails (out of memory)
889
+ *
890
+ * @example
891
+ * ```typescript
892
+ * const packet = filter.receiveSync();
893
+ * if (packet) {
894
+ * console.log('Got filtered packet');
895
+ * output.writePacketSync(packet);
896
+ * packet.free();
897
+ * }
898
+ * ```
899
+ *
900
+ * @example
901
+ * ```typescript
902
+ * // Drain all buffered packets
903
+ * let packet;
904
+ * while ((packet = filter.receiveSync()) !== null) {
905
+ * console.log(`Packet PTS: ${packet.pts}`);
906
+ * output.writePacketSync(packet);
907
+ * packet.free();
908
+ * }
909
+ * ```
910
+ *
911
+ * @see {@link filterSync} For filtering packets
912
+ * @see {@link flushSync} For signaling end-of-stream
913
+ * @see {@link receive} For async version
914
+ */
915
+ receiveSync() {
916
+ if (this.isClosed || !this.initialized) {
917
+ return null;
918
+ }
919
+ // See receive(): pending output first
920
+ const pending = this.pendingOutput.shift();
921
+ if (pending) {
922
+ return pending;
923
+ }
924
+ return this.receiveFromContextSync();
925
+ }
926
+ pipeTo(target, streamIndex) {
927
+ if (target instanceof Muxer) {
928
+ // Start worker if not already running
929
+ this.workerPromise ??= this.runWorker();
930
+ // Start pipe task: filter.outputQueue -> output
931
+ this.pipeToPromise = (async () => {
932
+ while (true) {
933
+ const env_3 = { stack: [], error: void 0, hasError: false };
934
+ try {
935
+ // writePacket clones internally, so the queue-owned packet must be
936
+ // freed here - `using` also covers the write throwing
937
+ const packet = __addDisposableResource(env_3, await this.receiveFromQueue(), false);
938
+ if (!packet)
939
+ break;
940
+ await target.writePacket(packet, streamIndex);
941
+ }
942
+ catch (e_3) {
943
+ env_3.error = e_3;
944
+ env_3.hasError = true;
945
+ }
946
+ finally {
947
+ __disposeResources(env_3);
948
+ }
949
+ }
950
+ })();
951
+ // Return control without pipeTo (terminal stage)
952
+ return new SchedulerControl(this);
953
+ }
954
+ else {
955
+ // BitStreamFilterAPI
956
+ const t = target;
957
+ // Store reference to next component for flush propagation
958
+ this.nextComponent = t;
959
+ // Start worker if not already running
960
+ this.workerPromise ??= this.runWorker();
961
+ // Start pipe task: filter.outputQueue -> target.inputQueue (via target.send)
962
+ this.pipeToPromise = (async () => {
963
+ while (true) {
964
+ const packet = await this.receiveFromQueue();
965
+ if (!packet)
966
+ break;
967
+ await t.sendToQueue(packet);
968
+ }
969
+ })();
970
+ // Return scheduler for chaining (target is now the last component)
971
+ return new Scheduler(this, t);
972
+ }
973
+ }
974
+ /**
975
+ * Flush all buffered packets as async generator.
976
+ *
977
+ * Convenient async iteration over remaining packets.
978
+ * Automatically sends flush signal and retrieves buffered packets.
979
+ * Useful for end-of-stream processing.
980
+ *
981
+ * @yields {Packet} Buffered packets
982
+ *
983
+ * @example
984
+ * ```typescript
985
+ * // Flush at end of filtering
986
+ * for await (const packet of filter.flushPackets()) {
987
+ * console.log('Processing buffered packet');
988
+ * await output.writePacket(packet);
989
+ * packet.free();
990
+ * }
991
+ * ```
992
+ *
993
+ * @see {@link filter} For filtering packets
994
+ * @see {@link flush} For signaling end-of-stream
995
+ * @see {@link flushPacketsSync} For synchronous version
996
+ */
997
+ async *flushPackets() {
998
+ // Signal EOF first - buffering filters only release their queued packets
999
+ // after av_bsf_send_packet(NULL)
1000
+ await this.flush();
1001
+ while (true) {
1002
+ const packet = await this.receive();
1003
+ if (!packet)
1004
+ break;
1005
+ yield packet;
1006
+ }
1007
+ }
1008
+ /**
1009
+ * Flush all buffered packets as generator synchronously.
1010
+ * Synchronous version of flushPackets.
1011
+ *
1012
+ * Convenient sync iteration over remaining packets.
1013
+ * Automatically sends flush signal and retrieves buffered packets.
1014
+ * Useful for end-of-stream processing.
1015
+ *
1016
+ * @yields {Packet} Buffered packets
1017
+ *
1018
+ * @example
1019
+ * ```typescript
1020
+ * // Flush at end of filtering
1021
+ * for (const packet of filter.flushPacketsSync()) {
1022
+ * console.log('Processing buffered packet');
1023
+ * output.writePacketSync(packet);
1024
+ * packet.free();
1025
+ * }
1026
+ * ```
1027
+ *
1028
+ * @see {@link filterSync} For filtering packets
1029
+ * @see {@link flushSync} For signaling end-of-stream
1030
+ * @see {@link flushPackets} For async version
1031
+ */
1032
+ *flushPacketsSync() {
1033
+ // See flushPackets(): EOF first, then drain
1034
+ this.flushSync();
1035
+ while (true) {
1036
+ const packet = this.receiveSync();
1037
+ if (!packet)
1038
+ break;
1039
+ yield packet;
1040
+ }
1041
+ }
1042
+ /**
1043
+ * Reset filter state.
1044
+ *
1045
+ * Clears internal buffers and resets filter.
1046
+ * Does not dispose resources.
1047
+ *
1048
+ * Direct mapping to av_bsf_flush().
1049
+ *
1050
+ * @example
1051
+ * ```typescript
1052
+ * // Reset for new segment
1053
+ * filter.reset();
1054
+ * ```
1055
+ *
1056
+ * @see {@link flush} For end-of-stream signaling with packet retrieval
1057
+ */
1058
+ reset() {
1059
+ if (this.isClosed) {
1060
+ return;
1061
+ }
1062
+ // Drop output buffered from an EAGAIN drain - it belongs to the old segment
1063
+ this.clearPendingOutput();
1064
+ this.ctx.flush();
1065
+ }
1066
+ /**
1067
+ * Close filter and free resources.
1068
+ *
1069
+ * Releases filter context and marks as closed.
1070
+ * Safe to call multiple times.
1071
+ *
1072
+ * @example
1073
+ * ```typescript
1074
+ * filter.close();
1075
+ * ```
1076
+ *
1077
+ * @see {@link Symbol.dispose} For automatic cleanup
1078
+ */
1079
+ close() {
1080
+ if (this.isClosed) {
1081
+ return;
1082
+ }
1083
+ this.isClosed = true;
1084
+ this.inputQueue.close();
1085
+ this.outputQueue.close();
1086
+ this.inputQueue.clear();
1087
+ this.outputQueue.clear();
1088
+ this.clearPendingOutput();
1089
+ this.packet.free();
1090
+ this.ctx.free();
1091
+ }
1092
+ /**
1093
+ * Dispose of filter.
1094
+ *
1095
+ * Implements Disposable interface for automatic cleanup.
1096
+ * Equivalent to calling dispose().
1097
+ *
1098
+ * @example
1099
+ * ```typescript
1100
+ * {
1101
+ * using filter = BitStreamFilterAPI.create('h264_mp4toannexb', stream);
1102
+ * // Use filter...
1103
+ * } // Automatically disposed
1104
+ * ```
1105
+ *
1106
+ * @see {@link close} For manual cleanup
1107
+ */
1108
+ [Symbol.dispose]() {
1109
+ this.close();
1110
+ }
1111
+ /**
1112
+ * Bind input parameters from the source and initialize the filter.
1113
+ *
1114
+ * @internal
1115
+ */
1116
+ ensureInitialized() {
1117
+ if (this.initialized) {
1118
+ return;
1119
+ }
1120
+ const params = this.ctx.inputCodecParameters;
1121
+ if (!params) {
1122
+ throw new Error('Failed to get input codec parameters from filter context');
1123
+ }
1124
+ const source = this.source;
1125
+ if (source instanceof Stream) {
1126
+ source.codecpar.copy(params);
1127
+ this.ctx.inputTimeBase = source.timeBase;
1128
+ }
1129
+ else if (source instanceof Encoder) {
1130
+ const codecContext = source.getCodecContext();
1131
+ if (!codecContext) {
1132
+ throw new Error('Encoder is not initialized yet; cannot derive bitstream filter parameters.');
1133
+ }
1134
+ const ret = params.fromContext(codecContext);
1135
+ FFmpegError.throwIfError(ret, 'Failed to derive bitstream filter parameters from encoder');
1136
+ this.ctx.inputTimeBase = codecContext.timeBase;
1137
+ }
1138
+ else {
1139
+ // Upstream is another bitstream filter: chain from its output.
1140
+ source.ensureInitialized();
1141
+ const upstream = source.outputCodecParameters;
1142
+ if (!upstream) {
1143
+ throw new Error('Upstream bitstream filter has no output parameters.');
1144
+ }
1145
+ upstream.copy(params);
1146
+ const tb = source.outputTimeBase;
1147
+ if (tb) {
1148
+ this.ctx.inputTimeBase = tb;
1149
+ }
1150
+ }
1151
+ const initRet = this.ctx.init();
1152
+ FFmpegError.throwIfError(initRet, 'Failed to initialize bitstream filter');
1153
+ this.initialized = true;
1154
+ }
1155
+ /**
1156
+ * Send a packet to the filter context, retrying once on EAGAIN.
1157
+ *
1158
+ * av_bsf_send_packet() returning EAGAIN means the packet was NOT consumed:
1159
+ * the filter holds output that must be received before it accepts more
1160
+ * input. That output is drained into pendingOutput (delivered by subsequent
1161
+ * receive() calls in FIFO order) and the send is retried, mirroring how the
1162
+ * FFmpeg CLI interleaves send/receive.
1163
+ *
1164
+ * @param packet - Packet to send, or null to signal EOF
1165
+ *
1166
+ * @throws {FFmpegError} If sending fails
1167
+ *
1168
+ * @internal
1169
+ */
1170
+ async sendPacketWithRetry(packet) {
1171
+ let sendRet = await this.ctx.sendPacket(packet);
1172
+ if (sendRet === AVERROR_EAGAIN) {
1173
+ while (true) {
1174
+ const outPacket = await this.receiveFromContext();
1175
+ if (!outPacket)
1176
+ break;
1177
+ this.pendingOutput.push(outPacket);
1178
+ }
1179
+ sendRet = await this.ctx.sendPacket(packet);
1180
+ }
1181
+ if (sendRet < 0 && sendRet !== AVERROR_EOF && sendRet !== AVERROR_EAGAIN) {
1182
+ FFmpegError.throwIfError(sendRet, 'Failed to send packet to bitstream filter');
1183
+ }
1184
+ }
1185
+ /**
1186
+ * Send a packet to the filter context, retrying once on EAGAIN.
1187
+ * Synchronous version of sendPacketWithRetry.
1188
+ *
1189
+ * @param packet - Packet to send, or null to signal EOF
1190
+ *
1191
+ * @throws {FFmpegError} If sending fails
1192
+ *
1193
+ * @internal
1194
+ */
1195
+ sendPacketWithRetrySync(packet) {
1196
+ let sendRet = this.ctx.sendPacketSync(packet);
1197
+ if (sendRet === AVERROR_EAGAIN) {
1198
+ while (true) {
1199
+ const outPacket = this.receiveFromContextSync();
1200
+ if (!outPacket)
1201
+ break;
1202
+ this.pendingOutput.push(outPacket);
1203
+ }
1204
+ sendRet = this.ctx.sendPacketSync(packet);
1205
+ }
1206
+ if (sendRet < 0 && sendRet !== AVERROR_EOF && sendRet !== AVERROR_EAGAIN) {
1207
+ FFmpegError.throwIfError(sendRet, 'Failed to send packet to bitstream filter');
1208
+ }
1209
+ }
1210
+ /**
1211
+ * Receive one packet directly from the filter context.
1212
+ *
1213
+ * Bypasses pendingOutput so an EAGAIN drain can buffer packets without
1214
+ * re-reading them.
1215
+ *
1216
+ * @returns Cloned packet or null if no packets available
1217
+ *
1218
+ * @throws {FFmpegError} If receive fails
1219
+ *
1220
+ * @throws {Error} If packet cloning fails (out of memory)
1221
+ *
1222
+ * @internal
1223
+ */
1224
+ async receiveFromContext() {
1225
+ // Clear previous packet data
1226
+ this.packet.unref();
1227
+ const recvRet = await this.ctx.receivePacket(this.packet);
1228
+ return this.consumeReceived(recvRet);
1229
+ }
1230
+ /**
1231
+ * Receive one packet directly from the filter context.
1232
+ * Synchronous version of receiveFromContext.
1233
+ *
1234
+ * @returns Cloned packet or null if no packets available
1235
+ *
1236
+ * @throws {FFmpegError} If receive fails
1237
+ *
1238
+ * @throws {Error} If packet cloning fails (out of memory)
1239
+ *
1240
+ * @internal
1241
+ */
1242
+ receiveFromContextSync() {
1243
+ // Clear previous packet data
1244
+ this.packet.unref();
1245
+ const recvRet = this.ctx.receivePacketSync(this.packet);
1246
+ return this.consumeReceived(recvRet);
1247
+ }
1248
+ /**
1249
+ * Convert a receive return code into a cloned output packet.
1250
+ *
1251
+ * @param recvRet - Return code of av_bsf_receive_packet()
1252
+ *
1253
+ * @returns Cloned packet, or null on EAGAIN/EOF
1254
+ *
1255
+ * @throws {FFmpegError} If the return code is any other error
1256
+ *
1257
+ * @throws {Error} If packet cloning fails (out of memory)
1258
+ *
1259
+ * @internal
1260
+ */
1261
+ consumeReceived(recvRet) {
1262
+ if (recvRet === 0) {
1263
+ // Filters like aac_adtstoasc deliver new global headers via packet side
1264
+ // data rather than par_out; fold it into the output parameters so callers
1265
+ // (and Muxer's bsf integration) can read it from outputCodecParameters.
1266
+ this.foldNewExtradata(this.packet);
1267
+ // Got a packet, clone it for the user
1268
+ const cloned = this.packet.clone();
1269
+ if (!cloned) {
1270
+ throw new Error('Failed to clone packet (out of memory)');
1271
+ }
1272
+ return cloned;
1273
+ }
1274
+ else if (recvRet === AVERROR_EAGAIN || recvRet === AVERROR_EOF) {
1275
+ // Need more data or end of stream
1276
+ return null;
1277
+ }
1278
+ else {
1279
+ // Error
1280
+ FFmpegError.throwIfError(recvRet, 'Failed to receive packet from bitstream filter');
1281
+ return null;
1282
+ }
1283
+ }
1284
+ /**
1285
+ * Free and clear any packets buffered by an EAGAIN drain.
1286
+ *
1287
+ * @internal
1288
+ */
1289
+ clearPendingOutput() {
1290
+ for (const packet of this.pendingOutput) {
1291
+ packet.free();
1292
+ }
1293
+ this.pendingOutput = [];
1294
+ }
1295
+ /**
1296
+ * Send packet to input queue or flush the pipeline.
1297
+ *
1298
+ * When packet is provided, queues it for filtering.
1299
+ * When null is provided, triggers flush sequence:
1300
+ * - Closes input queue
1301
+ * - Waits for worker completion
1302
+ * - Closes output queue (no buffering, bitstream filters are stateless)
1303
+ * - Waits for pipeTo task completion
1304
+ * - Propagates flush to next component (if any)
1305
+ *
1306
+ * Used by scheduler system for pipeline control.
1307
+ *
1308
+ * @param packet - Packet to send, or null to flush
1309
+ *
1310
+ * @internal
1311
+ */
1312
+ async sendToQueue(packet) {
1313
+ if (packet) {
1314
+ await this.inputQueue.send(packet);
1315
+ }
1316
+ else {
1317
+ // Close input queue to signal end of stream to worker
1318
+ this.inputQueue.close();
1319
+ // Wait for worker to finish processing all packets
1320
+ if (this.workerPromise) {
1321
+ await this.workerPromise;
1322
+ }
1323
+ // Close output queue to signal end of stream to pipeTo() task
1324
+ this.outputQueue.close();
1325
+ // Wait for pipeTo() task to finish processing all packets (if exists)
1326
+ if (this.pipeToPromise) {
1327
+ await this.pipeToPromise;
1328
+ }
1329
+ // Then propagate flush to next component
1330
+ if (this.nextComponent) {
1331
+ await this.nextComponent.sendToQueue(null);
1332
+ }
1333
+ }
1334
+ }
1335
+ /**
1336
+ * Receive packet from output queue.
1337
+ *
1338
+ * @returns Packet from queue or null if closed
1339
+ *
1340
+ * @internal
1341
+ */
1342
+ async receiveFromQueue() {
1343
+ return await this.outputQueue.receive();
1344
+ }
1345
+ /**
1346
+ * Worker loop for push-based processing.
1347
+ *
1348
+ * @internal
1349
+ */
1350
+ async runWorker() {
1351
+ try {
1352
+ // Outer loop - receive packets
1353
+ while (!this.inputQueue.isClosed) {
1354
+ const env_4 = { stack: [], error: void 0, hasError: false };
1355
+ try {
1356
+ const packet = __addDisposableResource(env_4, await this.inputQueue.receive(), false);
1357
+ if (!packet)
1358
+ break;
1359
+ if (this.isClosed) {
1360
+ break;
1361
+ }
1362
+ this.ensureInitialized();
1363
+ // Send packet to filter; on EAGAIN the pending output is buffered
1364
+ // internally and delivered by the receive() calls below
1365
+ await this.sendPacketWithRetry(packet);
1366
+ // Receive ALL available packets immediately
1367
+ while (!this.outputQueue.isClosed) {
1368
+ const outPacket = await this.receive();
1369
+ if (!outPacket)
1370
+ break;
1371
+ await this.outputQueue.send(outPacket);
1372
+ }
1373
+ }
1374
+ catch (e_4) {
1375
+ env_4.error = e_4;
1376
+ env_4.hasError = true;
1377
+ }
1378
+ finally {
1379
+ __disposeResources(env_4);
1380
+ }
1381
+ }
1382
+ // Flush filter at end
1383
+ await this.flush();
1384
+ while (!this.outputQueue.isClosed) {
1385
+ const outPacket = await this.receive();
1386
+ if (!outPacket)
1387
+ break;
1388
+ await this.outputQueue.send(outPacket);
1389
+ }
1390
+ }
1391
+ catch (error) {
1392
+ // Propagate error to both queues so upstream and downstream know
1393
+ const err = error instanceof Error ? error : new Error(String(error));
1394
+ this.inputQueue?.closeWithError(err);
1395
+ this.outputQueue?.closeWithError(err);
1396
+ }
1397
+ finally {
1398
+ // Close output queue when done (if not already closed with error)
1399
+ this.outputQueue?.close();
1400
+ }
1401
+ }
1402
+ /**
1403
+ * Fold a filtered packet's new-extradata side data into the output parameters.
1404
+ *
1405
+ * Bitstream filters that adapt a stream's container framing — `aac_adtstoasc`,
1406
+ * `extract_extradata`, `dump_extra`, `*_mp4toannexb` — emit the resulting global
1407
+ * headers as {@link AV_PKT_DATA_NEW_EXTRADATA} side data on their output packets
1408
+ * rather than on `par_out`, matching FFmpeg's mid-stream extradata model. Without
1409
+ * this, {@link outputCodecParameters} would never reflect that extradata, so a
1410
+ * stream copy that relies on it (including {@link Muxer}'s `bsf` option) emits a
1411
+ * header with no codec configuration. Lifting it onto `par_out` keeps
1412
+ * `outputCodecParameters` current while leaving the side data on the packet too.
1413
+ *
1414
+ * @param packet - A freshly received filtered packet.
1415
+ *
1416
+ * @internal
1417
+ */
1418
+ foldNewExtradata(packet) {
1419
+ const extradata = packet.getSideData(AV_PKT_DATA_NEW_EXTRADATA);
1420
+ if (!extradata)
1421
+ return;
1422
+ const params = this.ctx.outputCodecParameters;
1423
+ if (params)
1424
+ params.extradata = extradata;
1425
+ }
1426
+ }
1427
+ //# sourceMappingURL=bitstream-filter.js.map