node-av 3.1.2 → 4.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 (157) hide show
  1. package/README.md +65 -52
  2. package/binding.gyp +4 -0
  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 +319 -78
  7. package/dist/api/bitstream-filter.js +680 -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 +279 -17
  17. package/dist/api/decoder.js +998 -209
  18. package/dist/api/decoder.js.map +1 -1
  19. package/dist/api/{media-input.d.ts → demuxer.d.ts} +294 -44
  20. package/dist/api/demuxer.js +1968 -0
  21. package/dist/api/demuxer.js.map +1 -0
  22. package/dist/api/encoder.d.ts +308 -50
  23. package/dist/api/encoder.js +1133 -111
  24. package/dist/api/encoder.js.map +1 -1
  25. package/dist/api/filter-presets.d.ts +12 -5
  26. package/dist/api/filter-presets.js +21 -7
  27. package/dist/api/filter-presets.js.map +1 -1
  28. package/dist/api/filter.d.ts +406 -40
  29. package/dist/api/filter.js +966 -139
  30. package/dist/api/filter.js.map +1 -1
  31. package/dist/api/{fmp4.d.ts → fmp4-stream.d.ts} +141 -140
  32. package/dist/api/fmp4-stream.js +539 -0
  33. package/dist/api/fmp4-stream.js.map +1 -0
  34. package/dist/api/hardware.d.ts +58 -6
  35. package/dist/api/hardware.js +127 -11
  36. package/dist/api/hardware.js.map +1 -1
  37. package/dist/api/index.d.ts +6 -4
  38. package/dist/api/index.js +14 -8
  39. package/dist/api/index.js.map +1 -1
  40. package/dist/api/io-stream.d.ts +3 -3
  41. package/dist/api/io-stream.js +5 -4
  42. package/dist/api/io-stream.js.map +1 -1
  43. package/dist/api/{media-output.d.ts → muxer.d.ts} +274 -60
  44. package/dist/api/muxer.js +1934 -0
  45. package/dist/api/muxer.js.map +1 -0
  46. package/dist/api/pipeline.d.ts +77 -29
  47. package/dist/api/pipeline.js +435 -425
  48. package/dist/api/pipeline.js.map +1 -1
  49. package/dist/api/rtp-stream.d.ts +312 -0
  50. package/dist/api/rtp-stream.js +630 -0
  51. package/dist/api/rtp-stream.js.map +1 -0
  52. package/dist/api/types.d.ts +476 -55
  53. package/dist/api/utilities/async-queue.d.ts +91 -0
  54. package/dist/api/utilities/async-queue.js +162 -0
  55. package/dist/api/utilities/async-queue.js.map +1 -0
  56. package/dist/api/utilities/audio-sample.d.ts +1 -1
  57. package/dist/api/utilities/image.d.ts +1 -1
  58. package/dist/api/utilities/index.d.ts +2 -0
  59. package/dist/api/utilities/index.js +4 -0
  60. package/dist/api/utilities/index.js.map +1 -1
  61. package/dist/api/utilities/media-type.d.ts +1 -1
  62. package/dist/api/utilities/pixel-format.d.ts +1 -1
  63. package/dist/api/utilities/sample-format.d.ts +1 -1
  64. package/dist/api/utilities/scheduler.d.ts +169 -0
  65. package/dist/api/utilities/scheduler.js +136 -0
  66. package/dist/api/utilities/scheduler.js.map +1 -0
  67. package/dist/api/utilities/streaming.d.ts +74 -15
  68. package/dist/api/utilities/streaming.js +170 -12
  69. package/dist/api/utilities/streaming.js.map +1 -1
  70. package/dist/api/utilities/timestamp.d.ts +1 -1
  71. package/dist/api/webrtc-stream.d.ts +288 -0
  72. package/dist/api/webrtc-stream.js +440 -0
  73. package/dist/api/webrtc-stream.js.map +1 -0
  74. package/dist/constants/constants.d.ts +51 -1
  75. package/dist/constants/constants.js +47 -1
  76. package/dist/constants/constants.js.map +1 -1
  77. package/dist/constants/encoders.d.ts +2 -1
  78. package/dist/constants/encoders.js +4 -3
  79. package/dist/constants/encoders.js.map +1 -1
  80. package/dist/constants/hardware.d.ts +26 -0
  81. package/dist/constants/hardware.js +27 -0
  82. package/dist/constants/hardware.js.map +1 -0
  83. package/dist/constants/index.d.ts +1 -0
  84. package/dist/constants/index.js +1 -0
  85. package/dist/constants/index.js.map +1 -1
  86. package/dist/lib/binding.d.ts +19 -8
  87. package/dist/lib/binding.js.map +1 -1
  88. package/dist/lib/codec-context.d.ts +87 -0
  89. package/dist/lib/codec-context.js +125 -4
  90. package/dist/lib/codec-context.js.map +1 -1
  91. package/dist/lib/codec-parameters.d.ts +183 -1
  92. package/dist/lib/codec-parameters.js +209 -0
  93. package/dist/lib/codec-parameters.js.map +1 -1
  94. package/dist/lib/codec-parser.d.ts +23 -0
  95. package/dist/lib/codec-parser.js +25 -0
  96. package/dist/lib/codec-parser.js.map +1 -1
  97. package/dist/lib/codec.d.ts +26 -4
  98. package/dist/lib/codec.js +35 -0
  99. package/dist/lib/codec.js.map +1 -1
  100. package/dist/lib/dictionary.js +1 -0
  101. package/dist/lib/dictionary.js.map +1 -1
  102. package/dist/lib/error.js +1 -1
  103. package/dist/lib/error.js.map +1 -1
  104. package/dist/lib/filter-context.d.ts +52 -11
  105. package/dist/lib/filter-context.js +56 -12
  106. package/dist/lib/filter-context.js.map +1 -1
  107. package/dist/lib/filter-graph.d.ts +9 -0
  108. package/dist/lib/filter-graph.js +13 -0
  109. package/dist/lib/filter-graph.js.map +1 -1
  110. package/dist/lib/filter.d.ts +21 -0
  111. package/dist/lib/filter.js +28 -0
  112. package/dist/lib/filter.js.map +1 -1
  113. package/dist/lib/format-context.d.ts +48 -14
  114. package/dist/lib/format-context.js +76 -7
  115. package/dist/lib/format-context.js.map +1 -1
  116. package/dist/lib/frame.d.ts +168 -0
  117. package/dist/lib/frame.js +212 -0
  118. package/dist/lib/frame.js.map +1 -1
  119. package/dist/lib/hardware-device-context.d.ts +3 -2
  120. package/dist/lib/hardware-device-context.js.map +1 -1
  121. package/dist/lib/index.d.ts +1 -0
  122. package/dist/lib/index.js +2 -0
  123. package/dist/lib/index.js.map +1 -1
  124. package/dist/lib/input-format.d.ts +21 -0
  125. package/dist/lib/input-format.js +42 -2
  126. package/dist/lib/input-format.js.map +1 -1
  127. package/dist/lib/native-types.d.ts +48 -26
  128. package/dist/lib/option.d.ts +25 -13
  129. package/dist/lib/option.js +28 -0
  130. package/dist/lib/option.js.map +1 -1
  131. package/dist/lib/output-format.d.ts +22 -1
  132. package/dist/lib/output-format.js +28 -0
  133. package/dist/lib/output-format.js.map +1 -1
  134. package/dist/lib/packet.d.ts +35 -0
  135. package/dist/lib/packet.js +52 -2
  136. package/dist/lib/packet.js.map +1 -1
  137. package/dist/lib/stream.d.ts +126 -0
  138. package/dist/lib/stream.js +188 -5
  139. package/dist/lib/stream.js.map +1 -1
  140. package/dist/lib/sync-queue.d.ts +179 -0
  141. package/dist/lib/sync-queue.js +197 -0
  142. package/dist/lib/sync-queue.js.map +1 -0
  143. package/dist/lib/types.d.ts +27 -1
  144. package/dist/lib/utilities.d.ts +281 -53
  145. package/dist/lib/utilities.js +298 -55
  146. package/dist/lib/utilities.js.map +1 -1
  147. package/install/check.js +18 -7
  148. package/package.json +20 -19
  149. package/dist/api/fmp4.js +0 -710
  150. package/dist/api/fmp4.js.map +0 -1
  151. package/dist/api/media-input.js +0 -1075
  152. package/dist/api/media-input.js.map +0 -1
  153. package/dist/api/media-output.js +0 -1040
  154. package/dist/api/media-output.js.map +0 -1
  155. package/dist/api/webrtc.d.ts +0 -664
  156. package/dist/api/webrtc.js +0 -1132
  157. package/dist/api/webrtc.js.map +0 -1
@@ -1,18 +1,16 @@
1
- import { FormatContext } from '../lib/index.js';
1
+ import { FormatContext } from '../lib/format-context.js';
2
+ import { Packet } from '../lib/packet.js';
2
3
  import { Encoder } from './encoder.js';
3
- import type { IRational, OutputFormat, Packet, Stream } from '../lib/index.js';
4
+ import type { OutputFormat, Stream } from '../lib/index.js';
4
5
  import type { IOOutputCallbacks, MediaOutputOptions } from './types.js';
5
- export interface StreamDescription {
6
- initialized: boolean;
7
- stream: Stream;
8
- source: Encoder | Stream;
9
- timeBase?: IRational;
10
- sourceTimeBase?: IRational;
11
- isStreamCopy: boolean;
12
- bufferedPackets: Packet[];
6
+ export interface AddStreamOptionsWithEncoder {
7
+ encoder?: Encoder;
8
+ }
9
+ export interface AddStreamOptionsWithInputStream {
10
+ inputStream?: Stream;
13
11
  }
14
12
  /**
15
- * High-level media output for writing and muxing media files.
13
+ * High-level muxer for writing and muxing media files.
16
14
  *
17
15
  * Provides simplified access to media muxing and file writing operations.
18
16
  * Automatically manages header and trailer writing - header is written on first packet,
@@ -23,10 +21,10 @@ export interface StreamDescription {
23
21
  *
24
22
  * @example
25
23
  * ```typescript
26
- * import { MediaOutput } from 'node-av/api';
24
+ * import { Muxer } from 'node-av/api';
27
25
  *
28
26
  * // Create output file
29
- * await using output = await MediaOutput.open('output.mp4');
27
+ * await using output = await Muxer.open('output.mp4');
30
28
  *
31
29
  * // Add streams from encoders
32
30
  * const videoIdx = output.addStream(videoEncoder);
@@ -42,8 +40,8 @@ export interface StreamDescription {
42
40
  * @example
43
41
  * ```typescript
44
42
  * // Stream copy
45
- * await using input = await MediaInput.open('input.mp4');
46
- * await using output = await MediaOutput.open('output.mp4');
43
+ * await using input = await Demuxer.open('input.mp4');
44
+ * await using output = await Muxer.open('output.mp4');
47
45
  *
48
46
  * // Copy stream configuration
49
47
  * const videoIdx = output.addStream(input.video());
@@ -55,24 +53,32 @@ export interface StreamDescription {
55
53
  * }
56
54
  * ```
57
55
  *
58
- * @see {@link MediaInput} For reading media files
56
+ * @see {@link Demuxer} For reading media files
59
57
  * @see {@link Encoder} For encoding frames to packets
60
58
  * @see {@link FormatContext} For low-level API
61
59
  */
62
- export declare class MediaOutput implements AsyncDisposable, Disposable {
60
+ export declare class Muxer implements AsyncDisposable, Disposable {
63
61
  private formatContext;
62
+ private options;
64
63
  private _streams;
65
64
  private ioContext?;
66
65
  private headerWritten;
66
+ private headerWritePromise?;
67
67
  private trailerWritten;
68
68
  private isClosed;
69
- private headerWritePromise?;
69
+ private syncQueue?;
70
+ private sqPacket?;
71
+ private containerMetadataCopied;
72
+ private writeQueue?;
73
+ private writeWorkerPromise?;
70
74
  /**
75
+ * @param options - Media output options
76
+ *
71
77
  * @internal
72
78
  */
73
79
  private constructor();
74
80
  /**
75
- * Open media output for writing.
81
+ * Open muxer for writing.
76
82
  *
77
83
  * Creates and configures output context for muxing.
78
84
  * Automatically creates directories for file output.
@@ -84,7 +90,7 @@ export declare class MediaOutput implements AsyncDisposable, Disposable {
84
90
  *
85
91
  * @param options - Output configuration options
86
92
  *
87
- * @returns Opened media output instance
93
+ * @returns Opened muxer instance
88
94
  *
89
95
  * @throws {Error} If format required for custom I/O
90
96
  *
@@ -93,13 +99,13 @@ export declare class MediaOutput implements AsyncDisposable, Disposable {
93
99
  * @example
94
100
  * ```typescript
95
101
  * // Create file output
96
- * await using output = await MediaOutput.open('output.mp4');
102
+ * await using output = await Muxer.open('output.mp4');
97
103
  * ```
98
104
  *
99
105
  * @example
100
106
  * ```typescript
101
107
  * // Create output with specific format
102
- * await using output = await MediaOutput.open('output.ts', {
108
+ * await using output = await Muxer.open('output.ts', {
103
109
  * format: 'mpegts'
104
110
  * });
105
111
  * ```
@@ -118,7 +124,7 @@ export declare class MediaOutput implements AsyncDisposable, Disposable {
118
124
  * }
119
125
  * };
120
126
  *
121
- * await using output = await MediaOutput.open(callbacks, {
127
+ * await using output = await Muxer.open(callbacks, {
122
128
  * format: 'mp4',
123
129
  * bufferSize: 8192
124
130
  * });
@@ -127,12 +133,12 @@ export declare class MediaOutput implements AsyncDisposable, Disposable {
127
133
  * @see {@link MediaOutputOptions} For configuration options
128
134
  * @see {@link IOOutputCallbacks} For custom I/O interface
129
135
  */
130
- static open(target: string, options?: MediaOutputOptions): Promise<MediaOutput>;
136
+ static open(target: string, options?: MediaOutputOptions): Promise<Muxer>;
131
137
  static open(target: IOOutputCallbacks, options: MediaOutputOptions & {
132
138
  format: string;
133
- }): Promise<MediaOutput>;
139
+ }): Promise<Muxer>;
134
140
  /**
135
- * Open media output for writing synchronously.
141
+ * Open muxer for writing synchronously.
136
142
  * Synchronous version of open.
137
143
  *
138
144
  * Creates and configures output context for muxing.
@@ -145,7 +151,7 @@ export declare class MediaOutput implements AsyncDisposable, Disposable {
145
151
  *
146
152
  * @param options - Output configuration options
147
153
  *
148
- * @returns Opened media output instance
154
+ * @returns Opened muxer instance
149
155
  *
150
156
  * @throws {Error} If format required for custom I/O
151
157
  *
@@ -154,23 +160,23 @@ export declare class MediaOutput implements AsyncDisposable, Disposable {
154
160
  * @example
155
161
  * ```typescript
156
162
  * // Create file output
157
- * using output = MediaOutput.openSync('output.mp4');
163
+ * using output = Muxer.openSync('output.mp4');
158
164
  * ```
159
165
  *
160
166
  * @example
161
167
  * ```typescript
162
168
  * // Create output with specific format
163
- * using output = MediaOutput.openSync('output.ts', {
169
+ * using output = Muxer.openSync('output.ts', {
164
170
  * format: 'mpegts'
165
171
  * });
166
172
  * ```
167
173
  *
168
174
  * @see {@link open} For async version
169
175
  */
170
- static openSync(target: string, options?: MediaOutputOptions): MediaOutput;
176
+ static openSync(target: string, options?: MediaOutputOptions): Muxer;
171
177
  static openSync(target: IOOutputCallbacks, options: MediaOutputOptions & {
172
178
  format: string;
173
- }): MediaOutput;
179
+ }): Muxer;
174
180
  /**
175
181
  * Check if output is open.
176
182
  *
@@ -181,7 +187,7 @@ export declare class MediaOutput implements AsyncDisposable, Disposable {
181
187
  * }
182
188
  * ```
183
189
  */
184
- get isOutputOpen(): boolean;
190
+ get isOpen(): boolean;
185
191
  /**
186
192
  * Check if output is initialized.
187
193
  *
@@ -195,7 +201,7 @@ export declare class MediaOutput implements AsyncDisposable, Disposable {
195
201
  * }
196
202
  * ```
197
203
  */
198
- get isOutputInitialized(): boolean;
204
+ get streamsInitialized(): boolean;
199
205
  /**
200
206
  * Get all streams in the media.
201
207
  *
@@ -206,7 +212,7 @@ export declare class MediaOutput implements AsyncDisposable, Disposable {
206
212
  * }
207
213
  * ```
208
214
  */
209
- get streams(): Stream[] | null;
215
+ get streams(): Stream[];
210
216
  /**
211
217
  * Get format name.
212
218
  *
@@ -248,22 +254,67 @@ export declare class MediaOutput implements AsyncDisposable, Disposable {
248
254
  */
249
255
  get mimeType(): string | null;
250
256
  /**
251
- * Add a stream to the output.
257
+ * Add a stream to the output (encoder-only mode).
258
+ *
259
+ * Configures output stream from encoder. Stream is initialized lazily from first encoded frame.
260
+ * Use this when generating frames programmatically without an input stream.
261
+ *
262
+ * @param encoder - Encoder for encoding frames to packets
263
+ *
264
+ * @param options - Stream configuration options
265
+ *
266
+ * @param options.inputStream - Optional input stream for metadata/properties
267
+ *
268
+ * @param options.timeBase - Optional custom timebase for the stream
252
269
  *
253
- * Configures output stream from encoder or input stream.
270
+ * @returns Stream index for packet writing
271
+ *
272
+ * @throws {Error} If called after packets have been written or output closed
273
+ *
274
+ * @example
275
+ * ```typescript
276
+ * // Encoder-only (e.g., frame generator)
277
+ * const encoder = await Encoder.create(FF_ENCODER_LIBX264);
278
+ * const streamIdx = output.addStream(encoder);
279
+ * ```
280
+ *
281
+ * @example
282
+ * ```typescript
283
+ * // Encoder with input stream for metadata
284
+ * const streamIdx = output.addStream(encoder, {
285
+ * inputStream: input.video()
286
+ * });
287
+ * ```
288
+ */
289
+ addStream(encoder: Encoder, options?: AddStreamOptionsWithInputStream): number;
290
+ /**
291
+ * Add a stream to the output (stream copy or transcoding mode).
292
+ *
293
+ * Configures output stream from input stream and optional encoder.
254
294
  * Must be called before writing any packets.
255
295
  * Returns stream index for packet writing.
256
296
  *
257
- * Streams are initialized lazily - codec parameters are configured
258
- * automatically when the first packet is written. This allows encoders
259
- * to be initialized from frame properties.
297
+ * Automatically copies from input stream:
298
+ * - Codec parameters (stream copy mode)
299
+ * - Metadata
300
+ * - Disposition flags
301
+ * - Frame rates and aspect ratios
302
+ * - Duration hints
303
+ * - HDR/Dolby Vision side data (coded_side_data)
304
+ *
305
+ * When encoder is provided:
306
+ * - Stream is initialized lazily from first encoded frame
307
+ * - Metadata and disposition copied from input stream
308
+ * - Duration hint used for muxer
260
309
  *
261
310
  * Direct mapping to avformat_new_stream().
262
311
  *
263
- * @param source - Encoder or stream to add
312
+ * @param stream - Input stream (source for properties/metadata)
264
313
  *
265
314
  * @param options - Stream configuration options
266
315
  *
316
+ * @param options.encoder - Optional encoder for transcoding
317
+ *
267
318
  * @param options.timeBase - Optional custom timebase for the stream
268
319
  *
269
320
  * @returns Stream index for packet writing
@@ -272,9 +323,17 @@ export declare class MediaOutput implements AsyncDisposable, Disposable {
272
323
  *
273
324
  * @example
274
325
  * ```typescript
275
- * // Add stream from encoder (lazy initialization)
276
- * const videoIdx = output.addStream(videoEncoder);
277
- * const audioIdx = output.addStream(audioEncoder);
326
+ * // Stream copy
327
+ * const videoIdx = output.addStream(input.video());
328
+ * const audioIdx = output.addStream(input.audio());
329
+ * ```
330
+ *
331
+ * @example
332
+ * ```typescript
333
+ * // With encoding
334
+ * const videoIdx = output.addStream(input.video(), {
335
+ * encoder: videoEncoder
336
+ * });
278
337
  * ```
279
338
  *
280
339
  * @example
@@ -288,9 +347,7 @@ export declare class MediaOutput implements AsyncDisposable, Disposable {
288
347
  * @see {@link writePacket} For writing packets to streams
289
348
  * @see {@link Encoder} For transcoding source
290
349
  */
291
- addStream(source: Encoder | Stream, options?: {
292
- timeBase?: IRational;
293
- }): number;
350
+ addStream(stream: Stream, options?: AddStreamOptionsWithEncoder): number;
294
351
  /**
295
352
  * Get output stream by index.
296
353
  *
@@ -303,7 +360,7 @@ export declare class MediaOutput implements AsyncDisposable, Disposable {
303
360
  *
304
361
  * @example
305
362
  * ```typescript
306
- * const output = await MediaOutput.open('output.mp4');
363
+ * const output = await Muxer.open('output.mp4');
307
364
  * const videoIdx = output.addStream(encoder);
308
365
  *
309
366
  * // Get the output stream to inspect codec parameters
@@ -330,7 +387,7 @@ export declare class MediaOutput implements AsyncDisposable, Disposable {
330
387
  *
331
388
  * @example
332
389
  * ```typescript
333
- * const output = await MediaOutput.open('output.mp4');
390
+ * const output = await Muxer.open('output.mp4');
334
391
  * output.addStream(videoEncoder);
335
392
  *
336
393
  * // Get first video stream
@@ -356,7 +413,7 @@ export declare class MediaOutput implements AsyncDisposable, Disposable {
356
413
  *
357
414
  * @example
358
415
  * ```typescript
359
- * const output = await MediaOutput.open('output.mp4');
416
+ * const output = await Muxer.open('output.mp4');
360
417
  * output.addStream(audioEncoder);
361
418
  *
362
419
  * // Get first audio stream
@@ -380,7 +437,7 @@ export declare class MediaOutput implements AsyncDisposable, Disposable {
380
437
  *
381
438
  * @example
382
439
  * ```typescript
383
- * const output = await MediaOutput.open('output.mp4');
440
+ * const output = await Muxer.open('output.mp4');
384
441
  * const format = output.outputFormat();
385
442
  * if (format) {
386
443
  * console.log(`Output format: ${format.name}`);
@@ -399,10 +456,18 @@ export declare class MediaOutput implements AsyncDisposable, Disposable {
399
456
  * - Codec parameter configuration from encoder or input stream
400
457
  * - Header writing on first packet
401
458
  * - Timestamp rescaling between source and output timebases
459
+ * - Sync queue for proper interleaving
402
460
  *
403
461
  * For encoder sources, the encoder must have processed at least one frame
404
462
  * before packets can be written (encoder must be initialized).
405
463
  *
464
+ * Uses FFmpeg CLI's sync queue pattern: buffers packets per stream and writes
465
+ * them in DTS order using av_compare_ts for timebase-aware comparison.
466
+ *
467
+ * To signal EOF for a stream, pass null as the packet.
468
+ * This tells the muxer that no more packets will be sent for this stream.
469
+ * The trailer is written only when close() is called.
470
+ *
406
471
  * Direct mapping to avformat_write_header() (on first packet) and av_interleaved_write_frame().
407
472
  *
408
473
  * @param packet - Packet to write
@@ -436,7 +501,7 @@ export declare class MediaOutput implements AsyncDisposable, Disposable {
436
501
  *
437
502
  * @see {@link addStream} For adding streams
438
503
  */
439
- writePacket(packet: Packet, streamIndex: number): Promise<void>;
504
+ writePacket(packet: Packet | null, streamIndex: number): Promise<void>;
440
505
  /**
441
506
  * Write a packet to the output synchronously.
442
507
  * Synchronous version of writePacket.
@@ -447,10 +512,18 @@ export declare class MediaOutput implements AsyncDisposable, Disposable {
447
512
  * - Codec parameter configuration from encoder or input stream
448
513
  * - Header writing on first packet
449
514
  * - Timestamp rescaling between source and output timebases
515
+ * - Sync queue for proper interleaving
450
516
  *
451
517
  * For encoder sources, the encoder must have processed at least one frame
452
518
  * before packets can be written (encoder must be initialized).
453
519
  *
520
+ * Uses FFmpeg CLI's sync queue pattern: buffers packets per stream and writes
521
+ * them in DTS order using av_compare_ts for timebase-aware comparison.
522
+ *
523
+ * To signal EOF for a stream, pass null as the packet.
524
+ * This tells the muxer that no more packets will be sent for this stream.
525
+ * The trailer is written only when close() is called.
526
+ *
454
527
  * Direct mapping to avformat_write_header() (on first packet) and av_interleaved_write_frame().
455
528
  *
456
529
  * @param packet - Packet to write
@@ -484,9 +557,9 @@ export declare class MediaOutput implements AsyncDisposable, Disposable {
484
557
  *
485
558
  * @see {@link writePacket} For async version
486
559
  */
487
- writePacketSync(packet: Packet, streamIndex: number): void;
560
+ writePacketSync(packet: Packet | null, streamIndex: number): void;
488
561
  /**
489
- * Close media output and free resources.
562
+ * Close muxer and free resources.
490
563
  *
491
564
  * Automatically writes trailer if header was written.
492
565
  * Closes the output file and releases all resources.
@@ -495,7 +568,7 @@ export declare class MediaOutput implements AsyncDisposable, Disposable {
495
568
  *
496
569
  * @example
497
570
  * ```typescript
498
- * const output = await MediaOutput.open('output.mp4');
571
+ * const output = await Muxer.open('output.mp4');
499
572
  * try {
500
573
  * // Use output - trailer written automatically on close
501
574
  * } finally {
@@ -507,7 +580,7 @@ export declare class MediaOutput implements AsyncDisposable, Disposable {
507
580
  */
508
581
  close(): Promise<void>;
509
582
  /**
510
- * Close media output and free resources synchronously.
583
+ * Close muxer and free resources synchronously.
511
584
  * Synchronous version of close.
512
585
  *
513
586
  * Automatically writes trailer if header was written.
@@ -517,7 +590,7 @@ export declare class MediaOutput implements AsyncDisposable, Disposable {
517
590
  *
518
591
  * @example
519
592
  * ```typescript
520
- * const output = MediaOutput.openSync('output.mp4');
593
+ * const output = Muxer.openSync('output.mp4');
521
594
  * try {
522
595
  * // Use output - trailer written automatically on close
523
596
  * } finally {
@@ -539,7 +612,148 @@ export declare class MediaOutput implements AsyncDisposable, Disposable {
539
612
  */
540
613
  getFormatContext(): FormatContext;
541
614
  /**
542
- * Dispose of media output.
615
+ * Setup sync queues based on stream configuration.
616
+ *
617
+ * Called before writing header.
618
+ * Muxing sync queue is created only if nb_interleaved > nb_av_enc
619
+ * (i.e., when there are streamcopy streams).
620
+ *
621
+ * All streams are added as non-limiting (FFmpeg default without -shortest),
622
+ * which means no timestamp-based synchronization - frames are output immediately.
623
+ *
624
+ * @internal
625
+ */
626
+ private setupSyncQueues;
627
+ /**
628
+ * Flush all PreMuxQueues in DTS-sorted order.
629
+ *
630
+ * Implements FFmpeg's PreMuxQueue flush algorithm from mux_task_start().
631
+ * Repeatedly finds the stream with the earliest DTS packet and sends it:
632
+ * - WITH SyncQueue: Sends to SyncQueue for interleaving
633
+ * - WITHOUT SyncQueue: Writes directly to muxer
634
+ * NULL packets (EOF markers) and packets with AV_NOPTS_VALUE have priority (sent first).
635
+ *
636
+ * @internal
637
+ */
638
+ private flushPreMuxQueues;
639
+ /**
640
+ * Flush all PreMuxQueues in DTS-sorted order (synchronous version).
641
+ *
642
+ * Implements FFmpeg's PreMuxQueue flush algorithm from mux_task_start().
643
+ * Repeatedly finds the stream with the earliest DTS packet and sends it:
644
+ * - WITH SyncQueue: Sends to SyncQueue for interleaving
645
+ * - WITHOUT SyncQueue: Writes directly to muxer
646
+ * NULL packets (EOF markers) and packets with AV_NOPTS_VALUE have priority (sent first).
647
+ *
648
+ * @internal
649
+ */
650
+ private flushPreMuxQueuesSync;
651
+ /**
652
+ * Write a packet to the output.
653
+ *
654
+ * @param pkt - Packet to write
655
+ *
656
+ * @param streamInfo - Stream description
657
+ *
658
+ * @param streamIndex - Stream index
659
+ *
660
+ * @internal
661
+ */
662
+ private write;
663
+ /**
664
+ * Internal write implementation.
665
+ * Called either directly or through the write worker.
666
+ *
667
+ * @param pkt - Packet to write
668
+ *
669
+ * @param streamInfo - Stream description
670
+ *
671
+ * @param streamIndex - Stream index
672
+ *
673
+ * @internal
674
+ */
675
+ private writeInternal;
676
+ /**
677
+ * Start background worker for async write queue.
678
+ * Processes write jobs sequentially to prevent race conditions.
679
+ *
680
+ * @internal
681
+ */
682
+ private startWriteWorker;
683
+ /**
684
+ * Write a packet to the output synchronously.
685
+ * Synchronous version of write.
686
+ *
687
+ * @param pkt - Packet to write
688
+ *
689
+ * @param streamInfo - Stream description
690
+ *
691
+ * @param streamIndex - Stream index
692
+ *
693
+ * @internal
694
+ */
695
+ private writeSync;
696
+ /**
697
+ * Streamcopy packet filtering and timestamp offset.
698
+ *
699
+ * Applies streamcopy-specific logic before muxing:
700
+ * 1. Recording time limit check
701
+ * 2. Skip non-keyframe packets at start (unless copyInitialNonkeyframes)
702
+ * 3. Skip packets before ts_copy_start (unless copyPriorStart)
703
+ * 4. Skip packets before startTime
704
+ * 5. Apply start_time timestamp offset
705
+ *
706
+ * @param pkt - Packet to process
707
+ *
708
+ * @param streamInfo - Stream description
709
+ *
710
+ * @param streamIndex - Stream index
711
+ *
712
+ * @returns true if packet should be written, false if packet should be skipped
713
+ *
714
+ * @throws {Error} If recording time limit reached
715
+ *
716
+ * @internal
717
+ */
718
+ private ofStreamcopy;
719
+ /**
720
+ * Fix packet timestamps before muxing.
721
+ *
722
+ * Performs timestamp corrections:
723
+ * 1. Rescales timestamps to output timebase (av_rescale_delta for audio streamcopy)
724
+ * 2. Sets pkt.timeBase to output stream timebase
725
+ * 3. Fixes invalid DTS > PTS relationships
726
+ * 4. Enforces monotonic DTS (never decreasing)
727
+ *
728
+ * @param pkt - Packet to fix
729
+ *
730
+ * @param streamInfo - Stream description
731
+ *
732
+ * @param streamIndex - Stream index
733
+ *
734
+ * @internal
735
+ */
736
+ private muxFixupTs;
737
+ /**
738
+ * Copy container metadata from input to output.
739
+ *
740
+ * Automatically copies global metadata from input Demuxer to output format context.
741
+ * Only copies once (on first call). Removes duration/creation_time metadata.
742
+ *
743
+ * @internal
744
+ */
745
+ private copyContainerMetadata;
746
+ /**
747
+ * Auto-set DEFAULT disposition for first stream of each type.
748
+ *
749
+ * FFmpeg automatically sets DEFAULT flag for the first stream of each type
750
+ * if no stream of that type has DEFAULT set yet.
751
+ *
752
+ * @internal
753
+ */
754
+ private updateDefaultDisposition;
755
+ /**
756
+ * Dispose of muxer.
543
757
  *
544
758
  * Implements AsyncDisposable interface for automatic cleanup.
545
759
  * Equivalent to calling close().
@@ -547,7 +761,7 @@ export declare class MediaOutput implements AsyncDisposable, Disposable {
547
761
  * @example
548
762
  * ```typescript
549
763
  * {
550
- * await using output = await MediaOutput.open('output.mp4');
764
+ * await using output = await Muxer.open('output.mp4');
551
765
  * // Use output...
552
766
  * } // Automatically closed
553
767
  * ```
@@ -556,7 +770,7 @@ export declare class MediaOutput implements AsyncDisposable, Disposable {
556
770
  */
557
771
  [Symbol.asyncDispose](): Promise<void>;
558
772
  /**
559
- * Dispose of media output synchronously.
773
+ * Dispose of muxer synchronously.
560
774
  *
561
775
  * Implements Disposable interface for automatic cleanup.
562
776
  * Equivalent to calling closeSync().
@@ -564,7 +778,7 @@ export declare class MediaOutput implements AsyncDisposable, Disposable {
564
778
  * @example
565
779
  * ```typescript
566
780
  * {
567
- * using output = MediaOutput.openSync('output.mp4');
781
+ * using output = Muxer.openSync('output.mp4');
568
782
  * // Use output...
569
783
  * } // Automatically closed
570
784
  * ```