@revizly/node-av 5.2.2-beta.1

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