node-av 3.1.3 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. package/README.md +88 -52
  2. package/binding.gyp +23 -11
  3. package/dist/api/audio-frame-buffer.d.ts +201 -0
  4. package/dist/api/audio-frame-buffer.js +275 -0
  5. package/dist/api/audio-frame-buffer.js.map +1 -0
  6. package/dist/api/bitstream-filter.d.ts +320 -78
  7. package/dist/api/bitstream-filter.js +684 -151
  8. package/dist/api/bitstream-filter.js.map +1 -1
  9. package/dist/api/constants.d.ts +44 -0
  10. package/dist/api/constants.js +45 -0
  11. package/dist/api/constants.js.map +1 -0
  12. package/dist/api/data/test_av1.ivf +0 -0
  13. package/dist/api/data/test_mjpeg.mjpeg +0 -0
  14. package/dist/api/data/test_vp8.ivf +0 -0
  15. package/dist/api/data/test_vp9.ivf +0 -0
  16. package/dist/api/decoder.d.ts +454 -77
  17. package/dist/api/decoder.js +1081 -271
  18. package/dist/api/decoder.js.map +1 -1
  19. package/dist/api/{media-input.d.ts → demuxer.d.ts} +295 -45
  20. package/dist/api/demuxer.js +1965 -0
  21. package/dist/api/demuxer.js.map +1 -0
  22. package/dist/api/encoder.d.ts +423 -132
  23. package/dist/api/encoder.js +1089 -240
  24. package/dist/api/encoder.js.map +1 -1
  25. package/dist/api/filter-complex.d.ts +769 -0
  26. package/dist/api/filter-complex.js +1596 -0
  27. package/dist/api/filter-complex.js.map +1 -0
  28. package/dist/api/filter-presets.d.ts +80 -5
  29. package/dist/api/filter-presets.js +117 -7
  30. package/dist/api/filter-presets.js.map +1 -1
  31. package/dist/api/filter.d.ts +561 -125
  32. package/dist/api/filter.js +1083 -274
  33. package/dist/api/filter.js.map +1 -1
  34. package/dist/api/{fmp4.d.ts → fmp4-stream.d.ts} +141 -140
  35. package/dist/api/fmp4-stream.js +539 -0
  36. package/dist/api/fmp4-stream.js.map +1 -0
  37. package/dist/api/hardware.d.ts +58 -6
  38. package/dist/api/hardware.js +127 -11
  39. package/dist/api/hardware.js.map +1 -1
  40. package/dist/api/index.d.ts +8 -4
  41. package/dist/api/index.js +17 -8
  42. package/dist/api/index.js.map +1 -1
  43. package/dist/api/io-stream.d.ts +6 -6
  44. package/dist/api/io-stream.js +5 -4
  45. package/dist/api/io-stream.js.map +1 -1
  46. package/dist/api/{media-output.d.ts → muxer.d.ts} +280 -66
  47. package/dist/api/muxer.js +1934 -0
  48. package/dist/api/muxer.js.map +1 -0
  49. package/dist/api/pipeline.d.ts +77 -29
  50. package/dist/api/pipeline.js +449 -439
  51. package/dist/api/pipeline.js.map +1 -1
  52. package/dist/api/rtp-stream.d.ts +312 -0
  53. package/dist/api/rtp-stream.js +630 -0
  54. package/dist/api/rtp-stream.js.map +1 -0
  55. package/dist/api/types.d.ts +533 -56
  56. package/dist/api/utilities/async-queue.d.ts +91 -0
  57. package/dist/api/utilities/async-queue.js +162 -0
  58. package/dist/api/utilities/async-queue.js.map +1 -0
  59. package/dist/api/utilities/audio-sample.d.ts +11 -1
  60. package/dist/api/utilities/audio-sample.js +10 -0
  61. package/dist/api/utilities/audio-sample.js.map +1 -1
  62. package/dist/api/utilities/channel-layout.d.ts +1 -0
  63. package/dist/api/utilities/channel-layout.js +1 -0
  64. package/dist/api/utilities/channel-layout.js.map +1 -1
  65. package/dist/api/utilities/image.d.ts +39 -1
  66. package/dist/api/utilities/image.js +38 -0
  67. package/dist/api/utilities/image.js.map +1 -1
  68. package/dist/api/utilities/index.d.ts +3 -0
  69. package/dist/api/utilities/index.js +6 -0
  70. package/dist/api/utilities/index.js.map +1 -1
  71. package/dist/api/utilities/media-type.d.ts +2 -1
  72. package/dist/api/utilities/media-type.js +1 -0
  73. package/dist/api/utilities/media-type.js.map +1 -1
  74. package/dist/api/utilities/pixel-format.d.ts +4 -1
  75. package/dist/api/utilities/pixel-format.js +3 -0
  76. package/dist/api/utilities/pixel-format.js.map +1 -1
  77. package/dist/api/utilities/sample-format.d.ts +6 -1
  78. package/dist/api/utilities/sample-format.js +5 -0
  79. package/dist/api/utilities/sample-format.js.map +1 -1
  80. package/dist/api/utilities/scheduler.d.ts +138 -0
  81. package/dist/api/utilities/scheduler.js +98 -0
  82. package/dist/api/utilities/scheduler.js.map +1 -0
  83. package/dist/api/utilities/streaming.d.ts +105 -15
  84. package/dist/api/utilities/streaming.js +201 -12
  85. package/dist/api/utilities/streaming.js.map +1 -1
  86. package/dist/api/utilities/timestamp.d.ts +15 -1
  87. package/dist/api/utilities/timestamp.js +14 -0
  88. package/dist/api/utilities/timestamp.js.map +1 -1
  89. package/dist/api/utilities/whisper-model.d.ts +310 -0
  90. package/dist/api/utilities/whisper-model.js +528 -0
  91. package/dist/api/utilities/whisper-model.js.map +1 -0
  92. package/dist/api/webrtc-stream.d.ts +288 -0
  93. package/dist/api/webrtc-stream.js +440 -0
  94. package/dist/api/webrtc-stream.js.map +1 -0
  95. package/dist/api/whisper.d.ts +324 -0
  96. package/dist/api/whisper.js +362 -0
  97. package/dist/api/whisper.js.map +1 -0
  98. package/dist/constants/constants.d.ts +54 -2
  99. package/dist/constants/constants.js +48 -1
  100. package/dist/constants/constants.js.map +1 -1
  101. package/dist/constants/encoders.d.ts +2 -1
  102. package/dist/constants/encoders.js +4 -3
  103. package/dist/constants/encoders.js.map +1 -1
  104. package/dist/constants/hardware.d.ts +26 -0
  105. package/dist/constants/hardware.js +27 -0
  106. package/dist/constants/hardware.js.map +1 -0
  107. package/dist/constants/index.d.ts +1 -0
  108. package/dist/constants/index.js +1 -0
  109. package/dist/constants/index.js.map +1 -1
  110. package/dist/ffmpeg/index.d.ts +3 -3
  111. package/dist/ffmpeg/index.js +3 -3
  112. package/dist/ffmpeg/utils.d.ts +27 -0
  113. package/dist/ffmpeg/utils.js +28 -16
  114. package/dist/ffmpeg/utils.js.map +1 -1
  115. package/dist/lib/binding.d.ts +22 -11
  116. package/dist/lib/binding.js.map +1 -1
  117. package/dist/lib/codec-context.d.ts +87 -0
  118. package/dist/lib/codec-context.js +125 -4
  119. package/dist/lib/codec-context.js.map +1 -1
  120. package/dist/lib/codec-parameters.d.ts +229 -1
  121. package/dist/lib/codec-parameters.js +264 -0
  122. package/dist/lib/codec-parameters.js.map +1 -1
  123. package/dist/lib/codec-parser.d.ts +23 -0
  124. package/dist/lib/codec-parser.js +25 -0
  125. package/dist/lib/codec-parser.js.map +1 -1
  126. package/dist/lib/codec.d.ts +26 -4
  127. package/dist/lib/codec.js +35 -0
  128. package/dist/lib/codec.js.map +1 -1
  129. package/dist/lib/dictionary.js +1 -0
  130. package/dist/lib/dictionary.js.map +1 -1
  131. package/dist/lib/error.js +1 -1
  132. package/dist/lib/error.js.map +1 -1
  133. package/dist/lib/fifo.d.ts +416 -0
  134. package/dist/lib/fifo.js +453 -0
  135. package/dist/lib/fifo.js.map +1 -0
  136. package/dist/lib/filter-context.d.ts +52 -11
  137. package/dist/lib/filter-context.js +56 -12
  138. package/dist/lib/filter-context.js.map +1 -1
  139. package/dist/lib/filter-graph.d.ts +9 -0
  140. package/dist/lib/filter-graph.js +13 -0
  141. package/dist/lib/filter-graph.js.map +1 -1
  142. package/dist/lib/filter.d.ts +21 -0
  143. package/dist/lib/filter.js +28 -0
  144. package/dist/lib/filter.js.map +1 -1
  145. package/dist/lib/format-context.d.ts +48 -14
  146. package/dist/lib/format-context.js +76 -7
  147. package/dist/lib/format-context.js.map +1 -1
  148. package/dist/lib/frame.d.ts +264 -1
  149. package/dist/lib/frame.js +351 -1
  150. package/dist/lib/frame.js.map +1 -1
  151. package/dist/lib/hardware-device-context.d.ts +3 -2
  152. package/dist/lib/hardware-device-context.js.map +1 -1
  153. package/dist/lib/index.d.ts +2 -0
  154. package/dist/lib/index.js +4 -0
  155. package/dist/lib/index.js.map +1 -1
  156. package/dist/lib/input-format.d.ts +21 -0
  157. package/dist/lib/input-format.js +42 -2
  158. package/dist/lib/input-format.js.map +1 -1
  159. package/dist/lib/native-types.d.ts +76 -27
  160. package/dist/lib/option.d.ts +25 -13
  161. package/dist/lib/option.js +28 -0
  162. package/dist/lib/option.js.map +1 -1
  163. package/dist/lib/output-format.d.ts +22 -1
  164. package/dist/lib/output-format.js +28 -0
  165. package/dist/lib/output-format.js.map +1 -1
  166. package/dist/lib/packet.d.ts +35 -0
  167. package/dist/lib/packet.js +52 -2
  168. package/dist/lib/packet.js.map +1 -1
  169. package/dist/lib/rational.d.ts +18 -0
  170. package/dist/lib/rational.js +19 -0
  171. package/dist/lib/rational.js.map +1 -1
  172. package/dist/lib/stream.d.ts +126 -0
  173. package/dist/lib/stream.js +188 -5
  174. package/dist/lib/stream.js.map +1 -1
  175. package/dist/lib/sync-queue.d.ts +179 -0
  176. package/dist/lib/sync-queue.js +197 -0
  177. package/dist/lib/sync-queue.js.map +1 -0
  178. package/dist/lib/types.d.ts +49 -1
  179. package/dist/lib/utilities.d.ts +281 -53
  180. package/dist/lib/utilities.js +298 -55
  181. package/dist/lib/utilities.js.map +1 -1
  182. package/install/check.js +2 -2
  183. package/package.json +37 -26
  184. package/dist/api/fmp4.js +0 -710
  185. package/dist/api/fmp4.js.map +0 -1
  186. package/dist/api/media-input.js +0 -1075
  187. package/dist/api/media-input.js.map +0 -1
  188. package/dist/api/media-output.js +0 -1040
  189. package/dist/api/media-output.js.map +0 -1
  190. package/dist/api/webrtc.d.ts +0 -664
  191. package/dist/api/webrtc.js +0 -1132
  192. package/dist/api/webrtc.js.map +0 -1
@@ -1,5 +1,12 @@
1
- import { Codec, CodecContext, Frame } from '../lib/index.js';
2
- import type { Packet, Stream } from '../lib/index.js';
1
+ import { CodecContext } from '../lib/codec-context.js';
2
+ import { Codec } from '../lib/codec.js';
3
+ import { Frame } from '../lib/frame.js';
4
+ import { Packet } from '../lib/packet.js';
5
+ import { Scheduler } from './utilities/scheduler.js';
6
+ import type { AVCodecID, EOFSignal, FFDecoderCodec } from '../constants/index.js';
7
+ import type { Stream } from '../lib/stream.js';
8
+ import type { Encoder } from './encoder.js';
9
+ import type { FilterAPI } from './filter.js';
3
10
  import type { DecoderOptions } from './types.js';
4
11
  /**
5
12
  * High-level decoder for audio and video streams.
@@ -11,10 +18,10 @@ import type { DecoderOptions } from './types.js';
11
18
  *
12
19
  * @example
13
20
  * ```typescript
14
- * import { MediaInput, Decoder } from 'node-av/api';
21
+ * import { Demuxer, Decoder } from 'node-av/api';
15
22
  *
16
23
  * // Open media and create decoder
17
- * await using input = await MediaInput.open('video.mp4');
24
+ * await using input = await Demuxer.open('video.mp4');
18
25
  * using decoder = await Decoder.create(input.video());
19
26
  *
20
27
  * // Decode frames
@@ -40,7 +47,7 @@ import type { DecoderOptions } from './types.js';
40
47
  * ```
41
48
  *
42
49
  * @see {@link Encoder} For encoding frames to packets
43
- * @see {@link MediaInput} For reading media files
50
+ * @see {@link Demuxer} For reading media files
44
51
  * @see {@link HardwareContext} For GPU acceleration
45
52
  */
46
53
  export declare class Decoder implements Disposable {
@@ -51,6 +58,16 @@ export declare class Decoder implements Disposable {
51
58
  private initialized;
52
59
  private isClosed;
53
60
  private options;
61
+ private lastFramePts;
62
+ private lastFrameDurationEst;
63
+ private lastFrameTb;
64
+ private lastFrameSampleRate;
65
+ private lastFilterInRescaleDelta;
66
+ private inputQueue;
67
+ private outputQueue;
68
+ private workerPromise;
69
+ private nextComponent;
70
+ private pipeToPromise;
54
71
  /**
55
72
  * @param codecContext - Configured codec context
56
73
  *
@@ -84,9 +101,9 @@ export declare class Decoder implements Disposable {
84
101
  *
85
102
  * @example
86
103
  * ```typescript
87
- * import { MediaInput, Decoder } from 'node-av/api';
104
+ * import { Demuxer, Decoder } from 'node-av/api';
88
105
  *
89
- * await using input = await MediaInput.open('video.mp4');
106
+ * await using input = await Demuxer.open('video.mp4');
90
107
  * using decoder = await Decoder.create(input.video());
91
108
  * ```
92
109
  *
@@ -111,10 +128,20 @@ export declare class Decoder implements Disposable {
111
128
  * });
112
129
  * ```
113
130
  *
131
+ * @example
132
+ * ```typescript
133
+ * using decoder = await Decoder.create(stream, FF_DECODER_H264_AMF, {
134
+ * hardware: hw,
135
+ * threads: 2,
136
+ * });
137
+ * ```
138
+ *
114
139
  * @see {@link HardwareContext} For GPU acceleration setup
115
140
  * @see {@link DecoderOptions} For configuration options
141
+ * @see {@link createSync} For synchronous version
116
142
  */
117
143
  static create(stream: Stream, options?: DecoderOptions): Promise<Decoder>;
144
+ static create(stream: Stream, decoderCodec?: FFDecoderCodec | AVCodecID | Codec, options?: DecoderOptions): Promise<Decoder>;
118
145
  /**
119
146
  * Create a decoder for a media stream synchronously.
120
147
  * Synchronous version of create.
@@ -135,15 +162,15 @@ export declare class Decoder implements Disposable {
135
162
  *
136
163
  * @example
137
164
  * ```typescript
138
- * import { MediaInput, Decoder } from 'node-av/api';
165
+ * import { Demuxer, Decoder } from 'node-av/api';
139
166
  *
140
- * await using input = await MediaInput.open('video.mp4');
141
- * using decoder = await Decoder.create(input.video());
167
+ * await using input = await Demuxer.open('video.mp4');
168
+ * using decoder = Decoder.createSync(input.video());
142
169
  * ```
143
170
  *
144
171
  * @example
145
172
  * ```typescript
146
- * using decoder = await Decoder.create(stream, {
173
+ * using decoder = Decoder.createSync(stream, {
147
174
  * threads: 4,
148
175
  * options: {
149
176
  * 'refcounted_frames': '1',
@@ -155,15 +182,25 @@ export declare class Decoder implements Disposable {
155
182
  * @example
156
183
  * ```typescript
157
184
  * const hw = HardwareContext.auto();
158
- * using decoder = await Decoder.create(stream, {
185
+ * using decoder = Decoder.createSync(stream, {
159
186
  * hardware: hw,
160
187
  * threads: 0 // Auto-detect thread count
161
188
  * });
162
189
  * ```
163
190
  *
191
+ * @example
192
+ * ```typescript
193
+ * using decoder = Decoder.createSync(stream, FF_DECODER_H264_NVDEC, {
194
+ * hardware: hw
195
+ * });
196
+ * ```
197
+ *
198
+ * @see {@link HardwareContext} For GPU acceleration setup
199
+ * @see {@link DecoderOptions} For configuration options
164
200
  * @see {@link create} For async version
165
201
  */
166
202
  static createSync(stream: Stream, options?: DecoderOptions): Decoder;
203
+ static createSync(stream: Stream, decoderCodec?: FFDecoderCodec | AVCodecID | Codec, options?: DecoderOptions): Decoder;
167
204
  /**
168
205
  * Check if decoder is open.
169
206
  *
@@ -222,24 +259,31 @@ export declare class Decoder implements Disposable {
222
259
  */
223
260
  isReady(): boolean;
224
261
  /**
225
- * Decode a packet to a frame.
262
+ * Send a packet to the decoder.
226
263
  *
227
- * Sends a packet to the decoder and attempts to receive a decoded frame.
228
- * Handles internal buffering - may return null if more packets needed.
264
+ * Sends a compressed packet to the decoder for decoding.
265
+ * Does not return decoded frames - use {@link receive} to retrieve frames.
266
+ * A single packet can produce zero, one, or multiple frames depending on codec buffering.
229
267
  * Automatically manages decoder state and error recovery.
230
268
  *
231
- * Direct mapping to avcodec_send_packet() and avcodec_receive_frame().
269
+ * **Important**: This method only SENDS the packet to the decoder.
270
+ * You must call {@link receive} separately (potentially multiple times) to get decoded frames.
232
271
  *
233
- * @param packet - Compressed packet to decode
272
+ * Direct mapping to avcodec_send_packet().
234
273
  *
235
- * @returns Decoded frame or null if more data needed or decoder is closed
274
+ * @param packet - Compressed packet to send to decoder
236
275
  *
237
- * @throws {FFmpegError} If decoding fails
276
+ * @throws {FFmpegError} If sending packet fails
238
277
  *
239
278
  * @example
240
279
  * ```typescript
241
- * const frame = await decoder.decode(packet);
242
- * if (frame) {
280
+ * // Send packet and receive frames
281
+ * await decoder.decode(packet);
282
+ *
283
+ * // Receive all available frames
284
+ * while (true) {
285
+ * const frame = await decoder.receive();
286
+ * if (!frame) break;
243
287
  * console.log(`Decoded frame with PTS: ${frame.pts}`);
244
288
  * frame.free();
245
289
  * }
@@ -249,8 +293,12 @@ export declare class Decoder implements Disposable {
249
293
  * ```typescript
250
294
  * for await (const packet of input.packets()) {
251
295
  * if (packet.streamIndex === decoder.getStream().index) {
252
- * const frame = await decoder.decode(packet);
253
- * if (frame) {
296
+ * // Send packet
297
+ * await decoder.decode(packet);
298
+ *
299
+ * // Receive available frames
300
+ * let frame;
301
+ * while ((frame = await decoder.receive())) {
254
302
  * await processFrame(frame);
255
303
  * frame.free();
256
304
  * }
@@ -259,46 +307,168 @@ export declare class Decoder implements Disposable {
259
307
  * }
260
308
  * ```
261
309
  *
310
+ * @see {@link receive} For receiving decoded frames
311
+ * @see {@link decodeAll} For combined send+receive operation
262
312
  * @see {@link frames} For automatic packet iteration
263
313
  * @see {@link flush} For end-of-stream handling
314
+ * @see {@link decodeSync} For synchronous version
264
315
  */
265
- decode(packet: Packet): Promise<Frame | null>;
316
+ decode(packet: Packet): Promise<void>;
266
317
  /**
267
- * Decode a packet to frame synchronously.
318
+ * Send a packet to the decoder synchronously.
268
319
  * Synchronous version of decode.
269
320
  *
270
- * Send packet to decoder and attempt to receive frame.
271
- * Handles decoder buffering and error conditions.
272
- * May return null if decoder needs more data.
321
+ * Sends a compressed packet to the decoder for decoding.
322
+ * Does not return decoded frames - use {@link receiveSync} to retrieve frames.
323
+ * A single packet can produce zero, one, or multiple frames depending on codec buffering.
324
+ * Automatically manages decoder state and error recovery.
325
+ *
326
+ * **Important**: This method only SENDS the packet to the decoder.
327
+ * You must call {@link receiveSync} separately (potentially multiple times) to get decoded frames.
328
+ *
329
+ * Direct mapping to avcodec_send_packet().
330
+ *
331
+ * @param packet - Compressed packet to send to decoder
332
+ *
333
+ * @throws {FFmpegError} If sending packet fails
334
+ *
335
+ * @example
336
+ * ```typescript
337
+ * // Send packet and receive frames
338
+ * await decoder.decode(packet);
339
+ *
340
+ * // Receive all available frames
341
+ * while (true) {
342
+ * const frame = await decoder.receive();
343
+ * if (!frame) break;
344
+ * console.log(`Decoded frame with PTS: ${frame.pts}`);
345
+ * frame.free();
346
+ * }
347
+ * ```
348
+ *
349
+ * @example
350
+ * ```typescript
351
+ * for await (const packet of input.packets()) {
352
+ * if (packet.streamIndex === decoder.getStream().index) {
353
+ * // Send packet
354
+ * await decoder.decode(packet);
355
+ *
356
+ * // Receive available frames
357
+ * let frame;
358
+ * while ((frame = await decoder.receive())) {
359
+ * await processFrame(frame);
360
+ * frame.free();
361
+ * }
362
+ * }
363
+ * packet.free();
364
+ * }
365
+ * ```
366
+ *
367
+ * @see {@link receiveSync} For receiving decoded frames
368
+ * @see {@link decodeAllSync} For combined send+receive operation
369
+ * @see {@link framesSync} For automatic packet iteration
370
+ * @see {@link flushSync} For end-of-stream handling
371
+ * @see {@link decode} For async version
372
+ */
373
+ decodeSync(packet: Packet): void;
374
+ /**
375
+ * Decode a packet to frames.
376
+ *
377
+ * Sends a packet to the decoder and receives all available decoded frames.
378
+ * Returns array of frames - may be empty if decoder needs more data.
379
+ * One packet can produce zero, one, or multiple frames depending on codec.
380
+ * Automatically manages decoder state and error recovery.
381
+ *
382
+ * Direct mapping to avcodec_send_packet() and avcodec_receive_frame().
383
+ *
384
+ * @param packet - Compressed packet to decode
385
+ *
386
+ * @returns Array of decoded frames (empty if more data needed or decoder is closed)
387
+ *
388
+ * @throws {FFmpegError} If decoding fails
389
+ *
390
+ * @example
391
+ * ```typescript
392
+ * const frames = await decoder.decodeAll(packet);
393
+ * for (const frame of frames) {
394
+ * console.log(`Decoded frame with PTS: ${frame.pts}`);
395
+ * frame.free();
396
+ * }
397
+ * ```
398
+ *
399
+ * @example
400
+ * ```typescript
401
+ * for await (const packet of input.packets()) {
402
+ * const frames = await decoder.decodeAll(packet);
403
+ * for (const frame of frames) {
404
+ * await processFrame(frame);
405
+ * frame.free();
406
+ * }
407
+ * packet.free();
408
+ * }
409
+ * ```
410
+ *
411
+ * @see {@link decode} For single packet decoding
412
+ * @see {@link frames} For automatic packet iteration
413
+ * @see {@link flush} For end-of-stream handling
414
+ * @see {@link decodeAllSync} For synchronous version
415
+ */
416
+ decodeAll(packet: Packet | null): Promise<Frame[]>;
417
+ /**
418
+ * Decode a packet to frames synchronously.
419
+ * Synchronous version of decodeAll.
420
+ *
421
+ * Sends packet to decoder and receives all available decoded frames.
422
+ * Returns array of frames - may be empty if decoder needs more data.
423
+ * One packet can produce zero, one, or multiple frames depending on codec.
273
424
  *
274
425
  * @param packet - Compressed packet to decode
275
426
  *
276
- * @returns Decoded frame or null if more data needed or decoder is closed
427
+ * @returns Array of decoded frames (empty if more data needed or decoder is closed)
277
428
  *
278
429
  * @throws {FFmpegError} If decoding fails
279
430
  *
280
431
  * @example
281
432
  * ```typescript
282
- * const frame = decoder.decodeSync(packet);
283
- * if (frame) {
433
+ * const frames = decoder.decodeAllSync(packet);
434
+ * for (const frame of frames) {
284
435
  * console.log(`Decoded: ${frame.width}x${frame.height}`);
436
+ * frame.free();
437
+ * }
438
+ *
439
+ * @example
440
+ * ```typescript
441
+ * for (const packet of input.packetsSync()) {
442
+ * const frames = await decoder.decodeAllSync(packet);
443
+ * for (const frame of frames) {
444
+ * processFrame(frame);
445
+ * frame.free();
446
+ * }
447
+ * packet.free();
285
448
  * }
286
449
  * ```
287
450
  *
288
- * @see {@link decode} For async version
451
+ * @see {@link decodeSync} For single packet decoding
452
+ * @see {@link framesSync} For automatic packet iteration
453
+ * @see {@link flushSync} For end-of-stream handling
454
+ * @see {@link decodeAll} For async version
289
455
  */
290
- decodeSync(packet: Packet): Frame | null;
456
+ decodeAllSync(packet: Packet | null): Frame[];
291
457
  /**
292
458
  * Decode packet stream to frame stream.
293
459
  *
294
460
  * High-level async generator for complete decoding pipeline.
295
- * Automatically filters packets for this stream, manages memory,
296
- * and flushes buffered frames at end.
461
+ * Decoder is only flushed when EOF (null) signal is explicitly received.
297
462
  * Primary interface for stream-based decoding.
298
463
  *
299
- * @param packets - Async iterable of packets
464
+ * **EOF Handling:**
465
+ * - Send null to flush decoder and get remaining buffered frames
466
+ * - Generator yields null after flushing when null is received
467
+ * - No automatic flushing - decoder stays open until EOF or close()
468
+ *
469
+ * @param packets - Async iterable of packets, single packet, or null to flush
300
470
  *
301
- * @yields {Frame} Decoded frames
471
+ * @yields {Frame | null} Decoded frames, followed by null when explicitly flushed
302
472
  *
303
473
  * @throws {Error} If decoder is closed
304
474
  *
@@ -306,10 +476,15 @@ export declare class Decoder implements Disposable {
306
476
  *
307
477
  * @example
308
478
  * ```typescript
309
- * await using input = await MediaInput.open('video.mp4');
479
+ * // Stream of packets with automatic EOF propagation
480
+ * await using input = await Demuxer.open('video.mp4');
310
481
  * using decoder = await Decoder.create(input.video());
311
482
  *
312
483
  * for await (const frame of decoder.frames(input.packets())) {
484
+ * if (frame === null) {
485
+ * console.log('Decoding complete');
486
+ * break;
487
+ * }
313
488
  * console.log(`Frame: ${frame.width}x${frame.height}`);
314
489
  * frame.free();
315
490
  * }
@@ -317,43 +492,53 @@ export declare class Decoder implements Disposable {
317
492
  *
318
493
  * @example
319
494
  * ```typescript
320
- * for await (const frame of decoder.frames(input.packets())) {
321
- * // Process frame
322
- * await filter.process(frame);
323
- *
324
- * // Frame automatically freed
495
+ * // Single packet (no automatic flush)
496
+ * for await (const frame of decoder.frames(singlePacket)) {
497
+ * await encoder.encode(frame);
498
+ * frame.free();
499
+ * }
500
+ * // Decoder still has buffered frames - send null to flush
501
+ * for await (const frame of decoder.frames(null)) {
502
+ * if (frame === null) break;
503
+ * await encoder.encode(frame);
325
504
  * frame.free();
326
505
  * }
327
506
  * ```
328
507
  *
329
508
  * @example
330
509
  * ```typescript
331
- * import { pipeline } from 'node-av/api';
332
- *
333
- * const control = pipeline(
334
- * input,
335
- * decoder,
336
- * encoder,
337
- * output
338
- * );
339
- * await control.completion;
510
+ * // Explicit flush with EOF
511
+ * for await (const frame of decoder.frames(null)) {
512
+ * if (frame === null) {
513
+ * console.log('All buffered frames flushed');
514
+ * break;
515
+ * }
516
+ * console.log('Buffered frame:', frame.pts);
517
+ * frame.free();
518
+ * }
340
519
  * ```
341
520
  *
342
521
  * @see {@link decode} For single packet decoding
343
- * @see {@link MediaInput.packets} For packet source
522
+ * @see {@link Demuxer.packets} For packet source
523
+ * @see {@link framesSync} For sync version
344
524
  */
345
- frames(packets: AsyncIterable<Packet>): AsyncGenerator<Frame>;
525
+ frames(packets: AsyncIterable<Packet | null> | Packet | null): AsyncGenerator<Frame | null>;
346
526
  /**
347
527
  * Decode packet stream to frame stream synchronously.
348
528
  * Synchronous version of frames.
349
529
  *
350
- * High-level sync generator for complete decoding pipeline.
351
- * Automatically filters packets for this stream, manages memory,
352
- * and flushes buffered frames at end.
530
+ * High-level async generator for complete decoding pipeline.
531
+ * Decoder is only flushed when EOF (null) signal is explicitly received.
532
+ * Primary interface for stream-based decoding.
533
+ *
534
+ * **EOF Handling:**
535
+ * - Send null to flush decoder and get remaining buffered frames
536
+ * - Generator yields null after flushing when null is received
537
+ * - No automatic flushing - decoder stays open until EOF or close()
353
538
  *
354
- * @param packets - Iterable of packets
539
+ * @param packets - Iterable of packets, single packet, or null to flush
355
540
  *
356
- * @yields {Frame} Decoded frames
541
+ * @yields {Frame | null} Decoded frames, followed by null when explicitly flushed
357
542
  *
358
543
  * @throws {Error} If decoder is closed
359
544
  *
@@ -361,15 +546,49 @@ export declare class Decoder implements Disposable {
361
546
  *
362
547
  * @example
363
548
  * ```typescript
364
- * for (const frame of decoder.framesSync(packets)) {
549
+ * // Stream of packets with automatic EOF propagation
550
+ * await using input = await Demuxer.open('video.mp4');
551
+ * using decoder = await Decoder.create(input.video());
552
+ *
553
+ * for (const frame of decoder.framesSync(input.packetsSync())) {
554
+ * if (frame === null) {
555
+ * console.log('Decoding complete');
556
+ * break;
557
+ * }
365
558
  * console.log(`Frame: ${frame.width}x${frame.height}`);
366
- * // Process frame...
559
+ * frame.free();
560
+ * }
561
+ * ```
562
+ *
563
+ * @example
564
+ * ```typescript
565
+ * // Single packet (no automatic flush)
566
+ * for (const frame of decoder.framesSync(singlePacket)) {
567
+ * encoder.encodeSync(frame);
568
+ * frame.free();
569
+ * }
570
+ * // Decoder still has buffered frames - send null to flush
571
+ * for (const frame of decoder.framesSync(null)) {
572
+ * if (frame === null) break;
573
+ * encoder.encodeSync(frame);
574
+ * frame.free();
367
575
  * }
368
576
  * ```
369
577
  *
370
- * @see {@link frames} For async version
578
+ * @example
579
+ * ```typescript
580
+ * // Explicit flush with EOF
581
+ * for (const frame of decoder.framesSync(null)) {
582
+ * if (frame === null) {
583
+ * console.log('All buffered frames flushed');
584
+ * break;
585
+ * }
586
+ * console.log('Buffered frame:', frame.pts);
587
+ * frame.free();
588
+ * }
589
+ * ```
371
590
  */
372
- framesSync(packets: Iterable<Packet>): Generator<Frame>;
591
+ framesSync(packets: Iterable<Packet | null> | Packet | null): Generator<Frame | null>;
373
592
  /**
374
593
  * Flush decoder and signal end-of-stream.
375
594
  *
@@ -396,6 +615,7 @@ export declare class Decoder implements Disposable {
396
615
  *
397
616
  * @see {@link flushFrames} For convenient async iteration
398
617
  * @see {@link receive} For getting buffered frames
618
+ * @see {@link flushSync} For synchronous version
399
619
  */
400
620
  flush(): Promise<void>;
401
621
  /**
@@ -418,6 +638,8 @@ export declare class Decoder implements Disposable {
418
638
  * }
419
639
  * ```
420
640
  *
641
+ * @see {@link flushFramesSync} For convenient sync iteration
642
+ * @see {@link receiveSync} For getting buffered frames
421
643
  * @see {@link flush} For async version
422
644
  */
423
645
  flushSync(): void;
@@ -440,8 +662,9 @@ export declare class Decoder implements Disposable {
440
662
  * }
441
663
  * ```
442
664
  *
665
+ * @see {@link decode} For sending packets and receiving frames
443
666
  * @see {@link flush} For signaling end-of-stream
444
- * @see {@link frames} For complete pipeline
667
+ * @see {@link flushFramesSync} For synchronous version
445
668
  */
446
669
  flushFrames(): AsyncGenerator<Frame>;
447
670
  /**
@@ -464,6 +687,8 @@ export declare class Decoder implements Disposable {
464
687
  * }
465
688
  * ```
466
689
  *
690
+ * @see {@link decodeSync} For sending packets and receiving frames
691
+ * @see {@link flushSync} For signaling end-of-stream
467
692
  * @see {@link flushFrames} For async version
468
693
  */
469
694
  flushFramesSync(): Generator<Frame>;
@@ -473,37 +698,48 @@ export declare class Decoder implements Disposable {
473
698
  * Gets decoded frames from the codec's internal buffer.
474
699
  * Handles frame cloning and error checking.
475
700
  * Hardware frames include hw_frames_ctx reference.
476
- * Call repeatedly until null to drain all buffered frames.
701
+ * Call repeatedly to drain all buffered frames.
702
+ *
703
+ * **Return Values:**
704
+ * - `Frame` - Successfully decoded frame
705
+ * - `null` - No frame available (AVERROR_EAGAIN), send more packets
706
+ * - `undefined` - End of stream reached (AVERROR_EOF), decoder flushed
477
707
  *
478
708
  * Direct mapping to avcodec_receive_frame().
479
709
  *
480
- * @returns Cloned frame or null if no frames available
710
+ * @returns Decoded frame, null (need more data), or undefined (end of stream)
481
711
  *
482
712
  * @throws {FFmpegError} If receive fails with error other than AVERROR_EAGAIN or AVERROR_EOF
483
713
  *
484
714
  * @example
485
715
  * ```typescript
486
716
  * const frame = await decoder.receive();
487
- * if (frame) {
717
+ * if (frame === EOF) {
718
+ * console.log('Decoder flushed, no more frames');
719
+ * } else if (frame) {
488
720
  * console.log('Got decoded frame');
489
721
  * frame.free();
722
+ * } else {
723
+ * console.log('Need more packets');
490
724
  * }
491
725
  * ```
492
726
  *
493
727
  * @example
494
728
  * ```typescript
495
- * // Drain all buffered frames
729
+ * // Drain all buffered frames (stop on null or EOF)
496
730
  * let frame;
497
- * while ((frame = await decoder.receive()) !== null) {
731
+ * while ((frame = await decoder.receive()) && frame !== EOF) {
498
732
  * console.log(`Frame PTS: ${frame.pts}`);
499
733
  * frame.free();
500
734
  * }
501
735
  * ```
502
736
  *
503
- * @see {@link decode} For sending packets and receiving frames
737
+ * @see {@link decode} For sending packets
504
738
  * @see {@link flush} For signaling end-of-stream
739
+ * @see {@link receiveSync} For synchronous version
740
+ * @see {@link EOF} For end-of-stream signal
505
741
  */
506
- receive(): Promise<Frame | null>;
742
+ receive(): Promise<Frame | EOFSignal | null>;
507
743
  /**
508
744
  * Receive frame from decoder synchronously.
509
745
  * Synchronous version of receive.
@@ -511,36 +747,62 @@ export declare class Decoder implements Disposable {
511
747
  * Gets decoded frames from the codec's internal buffer.
512
748
  * Handles frame cloning and error checking.
513
749
  * Hardware frames include hw_frames_ctx reference.
514
- * Call repeatedly until null to drain all buffered frames.
750
+ * Call repeatedly to drain all buffered frames.
751
+ *
752
+ * **Return Values:**
753
+ * - `Frame` - Successfully decoded frame
754
+ * - `null` - No frame available (AVERROR_EAGAIN), send more packets
755
+ * - `undefined` - End of stream reached (AVERROR_EOF), decoder flushed
515
756
  *
516
757
  * Direct mapping to avcodec_receive_frame().
517
758
  *
518
- * @returns Cloned frame or null if no frames available
759
+ * @returns Decoded frame, null (need more data), or undefined (end of stream)
519
760
  *
520
761
  * @throws {FFmpegError} If receive fails with error other than AVERROR_EAGAIN or AVERROR_EOF
521
762
  *
522
763
  * @example
523
764
  * ```typescript
524
765
  * const frame = decoder.receiveSync();
525
- * if (frame) {
766
+ * if (frame === EOF) {
767
+ * console.log('Decoder flushed, no more frames');
768
+ * } else if (frame) {
526
769
  * console.log('Got decoded frame');
527
770
  * frame.free();
771
+ * } else {
772
+ * console.log('Need more packets');
528
773
  * }
529
774
  * ```
530
775
  *
531
776
  * @example
532
777
  * ```typescript
533
- * // Drain all buffered frames
778
+ * // Drain all buffered frames (stop on null or EOF)
534
779
  * let frame;
535
- * while ((frame = decoder.receiveSync()) !== null) {
780
+ * while ((frame = decoder.receiveSync()) && frame !== EOF) {
536
781
  * console.log(`Frame PTS: ${frame.pts}`);
537
782
  * frame.free();
538
783
  * }
539
784
  * ```
540
785
  *
786
+ * @see {@link decodeSync} For sending packets
787
+ * @see {@link flushSync} For signaling end-of-stream
541
788
  * @see {@link receive} For async version
789
+ * @see {@link EOF} For end-of-stream signal
790
+ */
791
+ receiveSync(): Frame | EOFSignal | null;
792
+ /**
793
+ * Pipe decoded frames to a filter component or encoder.
794
+ *
795
+ * @param target - Filter to receive frames or encoder to encode frames
796
+ *
797
+ * @returns Scheduler for continued chaining
798
+ *
799
+ * @example
800
+ * ```typescript
801
+ * decoder.pipeTo(filter).pipeTo(encoder)
802
+ * ```
542
803
  */
543
- receiveSync(): Frame | null;
804
+ pipeTo(target: FilterAPI): Scheduler<Packet>;
805
+ pipeTo(target: Encoder): Scheduler<Packet>;
544
806
  /**
545
807
  * Close decoder and free resources.
546
808
  *
@@ -601,6 +863,121 @@ export declare class Decoder implements Disposable {
601
863
  * @see {@link CodecContext} For context details
602
864
  */
603
865
  getCodecContext(): CodecContext | null;
866
+ /**
867
+ * Worker loop for push-based processing.
868
+ *
869
+ * @internal
870
+ */
871
+ private runWorker;
872
+ /**
873
+ * Send packet to input queue or flush the pipeline.
874
+ *
875
+ * When packet is provided, queues it for processing.
876
+ * When null is provided, triggers flush sequence:
877
+ * - Closes input queue
878
+ * - Waits for worker completion
879
+ * - Flushes decoder and sends remaining frames to output queue
880
+ * - Closes output queue
881
+ * - Waits for pipeTo task completion
882
+ * - Propagates flush to next component (if any)
883
+ *
884
+ * Used by scheduler system for pipeline control.
885
+ *
886
+ * @param packet - Packet to send, or null to flush
887
+ *
888
+ * @internal
889
+ */
890
+ private sendToQueue;
891
+ /**
892
+ * Receive frame from output queue.
893
+ *
894
+ * @returns Frame from output queue or null if closed
895
+ *
896
+ * @internal
897
+ */
898
+ private receiveFromQueue;
899
+ /**
900
+ * Estimate video frame duration.
901
+ *
902
+ * Implements FFmpeg CLI's video_duration_estimate() logic.
903
+ * Uses multiple heuristics to determine frame duration when not explicitly available:
904
+ * 1. Frame duration from container (if reliable)
905
+ * 2. Duration from codec framerate
906
+ * 3. PTS difference between frames
907
+ * 4. Stream framerate
908
+ * 5. Last frame's estimated duration
909
+ *
910
+ * @param frame - Frame to estimate duration for
911
+ *
912
+ * @returns Estimated duration in frame's timebase units
913
+ *
914
+ * @internal
915
+ */
916
+ private estimateVideoDuration;
917
+ /**
918
+ * Process video frame after decoding.
919
+ *
920
+ * Implements FFmpeg CLI's video_frame_process() logic.
921
+ * Handles:
922
+ * - Hardware frame transfer to software format
923
+ * - PTS assignment from best_effort_timestamp
924
+ * - PTS extrapolation when missing
925
+ * - Duration estimation
926
+ * - Frame tracking for next frame
927
+ *
928
+ * @param frame - Decoded frame to process
929
+ *
930
+ * @internal
931
+ */
932
+ private processVideoFrame;
933
+ /**
934
+ * Audio samplerate update - handles sample rate changes.
935
+ *
936
+ * Based on FFmpeg's audio_samplerate_update().
937
+ *
938
+ * On sample rate change, chooses a new internal timebase that can represent
939
+ * timestamps from all sample rates seen so far. Uses GCD to find minimal
940
+ * common timebase, with fallback to LCM of common sample rates (28224000).
941
+ *
942
+ * Handles:
943
+ * - Sample rate change detection
944
+ * - Timebase calculation via GCD
945
+ * - Overflow detection and fallback
946
+ * - Frame timebase optimization
947
+ * - Rescaling existing timestamps
948
+ *
949
+ * @param frame - Audio frame to process
950
+ *
951
+ * @returns Timebase to use for this frame
952
+ *
953
+ * @internal
954
+ */
955
+ private audioSamplerateUpdate;
956
+ /**
957
+ * Audio timestamp processing - handles audio frame timestamps.
958
+ *
959
+ * Based on FFmpeg's audio_ts_process().
960
+ *
961
+ * Processes audio frame timestamps with:
962
+ * - Sample rate change handling via audioSamplerateUpdate()
963
+ * - PTS extrapolation when missing (pts_pred)
964
+ * - Gap detection (resets av_rescale_delta state)
965
+ * - Smooth timestamp conversion via av_rescale_delta
966
+ * - Duration calculation from nb_samples
967
+ * - Conversion to filtering timebase {1, sample_rate}
968
+ *
969
+ * Handles:
970
+ * - Dynamic sample rate changes
971
+ * - Missing timestamps (AV_NOPTS_VALUE)
972
+ * - Timestamp gaps/discontinuities
973
+ * - Sample-accurate timestamp generation
974
+ * - Frame duration calculation
975
+ *
976
+ * @param frame - Decoded audio frame to process
977
+ *
978
+ * @internal
979
+ */
980
+ private processAudioFrame;
604
981
  /**
605
982
  * Dispose of decoder.
606
983
  *