node-av 1.2.0 → 2.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.
- package/README.md +37 -59
- package/dist/api/bitstream-filter.d.ts +5 -2
- package/dist/api/bitstream-filter.js +7 -4
- package/dist/api/bitstream-filter.js.map +1 -1
- package/dist/api/decoder.d.ts +135 -119
- package/dist/api/decoder.js +195 -202
- package/dist/api/decoder.js.map +1 -1
- package/dist/api/encoder.d.ts +141 -78
- package/dist/api/encoder.js +241 -193
- package/dist/api/encoder.js.map +1 -1
- package/dist/api/filter-presets.d.ts +699 -573
- package/dist/api/filter-presets.js +1157 -840
- package/dist/api/filter-presets.js.map +1 -1
- package/dist/api/filter.d.ts +180 -157
- package/dist/api/filter.js +314 -366
- package/dist/api/filter.js.map +1 -1
- package/dist/api/hardware.d.ts +28 -29
- package/dist/api/hardware.js +80 -74
- package/dist/api/hardware.js.map +1 -1
- package/dist/api/index.d.ts +1 -1
- package/dist/api/index.js +1 -1
- package/dist/api/index.js.map +1 -1
- package/dist/api/io-stream.d.ts +6 -0
- package/dist/api/io-stream.js +6 -0
- package/dist/api/io-stream.js.map +1 -1
- package/dist/api/media-input.d.ts +2 -1
- package/dist/api/media-input.js +3 -8
- package/dist/api/media-input.js.map +1 -1
- package/dist/api/media-output.d.ts +37 -126
- package/dist/api/media-output.js +138 -206
- package/dist/api/media-output.js.map +1 -1
- package/dist/api/pipeline.d.ts +193 -0
- package/dist/api/pipeline.js +36 -42
- package/dist/api/pipeline.js.map +1 -1
- package/dist/api/types.d.ts +22 -57
- package/dist/api/utilities/audio-sample.d.ts +0 -8
- package/dist/api/utilities/audio-sample.js +0 -8
- package/dist/api/utilities/audio-sample.js.map +1 -1
- package/dist/api/utilities/channel-layout.d.ts +0 -8
- package/dist/api/utilities/channel-layout.js +0 -8
- package/dist/api/utilities/channel-layout.js.map +1 -1
- package/dist/api/utilities/image.d.ts +0 -8
- package/dist/api/utilities/image.js +0 -8
- package/dist/api/utilities/image.js.map +1 -1
- package/dist/api/utilities/index.d.ts +3 -3
- package/dist/api/utilities/index.js +3 -3
- package/dist/api/utilities/index.js.map +1 -1
- package/dist/api/utilities/media-type.d.ts +1 -9
- package/dist/api/utilities/media-type.js +1 -9
- package/dist/api/utilities/media-type.js.map +1 -1
- package/dist/api/utilities/pixel-format.d.ts +1 -9
- package/dist/api/utilities/pixel-format.js +1 -9
- package/dist/api/utilities/pixel-format.js.map +1 -1
- package/dist/api/utilities/sample-format.d.ts +1 -9
- package/dist/api/utilities/sample-format.js +1 -9
- package/dist/api/utilities/sample-format.js.map +1 -1
- package/dist/api/utilities/streaming.d.ts +0 -8
- package/dist/api/utilities/streaming.js +0 -8
- package/dist/api/utilities/streaming.js.map +1 -1
- package/dist/api/utilities/timestamp.d.ts +0 -8
- package/dist/api/utilities/timestamp.js +0 -8
- package/dist/api/utilities/timestamp.js.map +1 -1
- package/dist/api/utils.js +2 -0
- package/dist/api/utils.js.map +1 -1
- package/dist/constants/constants.d.ts +1 -1
- package/dist/constants/constants.js +2 -0
- package/dist/constants/constants.js.map +1 -1
- package/dist/lib/binding.d.ts +1 -0
- package/dist/lib/binding.js +2 -0
- package/dist/lib/binding.js.map +1 -1
- package/dist/lib/codec.d.ts +4 -4
- package/dist/lib/codec.js +4 -4
- package/dist/lib/dictionary.d.ts +2 -2
- package/dist/lib/dictionary.js +2 -2
- package/dist/lib/dictionary.js.map +1 -1
- package/dist/lib/error.d.ts +1 -1
- package/dist/lib/error.js +1 -1
- package/dist/lib/filter-context.d.ts +19 -2
- package/dist/lib/filter-context.js +15 -0
- package/dist/lib/filter-context.js.map +1 -1
- package/dist/lib/format-context.d.ts +18 -18
- package/dist/lib/format-context.js +20 -20
- package/dist/lib/format-context.js.map +1 -1
- package/dist/lib/frame.d.ts +43 -1
- package/dist/lib/frame.js +53 -0
- package/dist/lib/frame.js.map +1 -1
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/index.js +1 -1
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/native-types.d.ts +1 -0
- package/dist/lib/option.d.ts +176 -0
- package/dist/lib/option.js +176 -0
- package/dist/lib/option.js.map +1 -1
- package/dist/lib/utilities.d.ts +64 -1
- package/dist/lib/utilities.js +65 -0
- package/dist/lib/utilities.js.map +1 -1
- package/install/ffmpeg.js +0 -11
- package/package.json +16 -18
- package/release_notes.md +0 -48
package/dist/api/media-output.js
CHANGED
|
@@ -7,6 +7,8 @@ import { Encoder } from './encoder.js';
|
|
|
7
7
|
* High-level media output for writing and muxing media files.
|
|
8
8
|
*
|
|
9
9
|
* Provides simplified access to media muxing and file writing operations.
|
|
10
|
+
* Automatically manages header and trailer writing - header is written on first packet,
|
|
11
|
+
* trailer is written on close. Supports lazy initialization for both encoders and streams.
|
|
10
12
|
* Handles stream configuration, packet writing, and format management.
|
|
11
13
|
* Supports files, URLs, and custom I/O with automatic cleanup.
|
|
12
14
|
* Essential component for media encoding pipelines and transcoding.
|
|
@@ -22,14 +24,11 @@ import { Encoder } from './encoder.js';
|
|
|
22
24
|
* const videoIdx = output.addStream(videoEncoder);
|
|
23
25
|
* const audioIdx = output.addStream(audioEncoder);
|
|
24
26
|
*
|
|
25
|
-
* // Write header
|
|
26
|
-
* await output.writeHeader();
|
|
27
|
-
*
|
|
28
|
-
* // Write packets
|
|
27
|
+
* // Write packets - header written automatically on first packet
|
|
29
28
|
* await output.writePacket(packet, videoIdx);
|
|
30
29
|
*
|
|
31
|
-
* //
|
|
32
|
-
* await
|
|
30
|
+
* // Close - trailer written automatically
|
|
31
|
+
* // (automatic with await using)
|
|
33
32
|
* ```
|
|
34
33
|
*
|
|
35
34
|
* @example
|
|
@@ -40,8 +39,8 @@ import { Encoder } from './encoder.js';
|
|
|
40
39
|
*
|
|
41
40
|
* // Copy stream configuration
|
|
42
41
|
* const videoIdx = output.addStream(input.video());
|
|
43
|
-
* await output.writeHeader();
|
|
44
42
|
*
|
|
43
|
+
* // Process packets - header/trailer handled automatically
|
|
45
44
|
* for await (const packet of input.packets()) {
|
|
46
45
|
* await output.writePacket(packet, videoIdx);
|
|
47
46
|
* packet.free();
|
|
@@ -58,7 +57,8 @@ export class MediaOutput {
|
|
|
58
57
|
ioContext;
|
|
59
58
|
headerWritten = false;
|
|
60
59
|
trailerWritten = false;
|
|
61
|
-
|
|
60
|
+
isClosed = false;
|
|
61
|
+
headerWritePromise;
|
|
62
62
|
/**
|
|
63
63
|
* @internal
|
|
64
64
|
*/
|
|
@@ -79,6 +79,7 @@ export class MediaOutput {
|
|
|
79
79
|
* @returns Opened media output instance
|
|
80
80
|
*
|
|
81
81
|
* @throws {Error} If format required for custom I/O
|
|
82
|
+
*
|
|
82
83
|
* @throws {FFmpegError} If allocation or opening fails
|
|
83
84
|
*
|
|
84
85
|
* @example
|
|
@@ -196,21 +197,25 @@ export class MediaOutput {
|
|
|
196
197
|
* Add a stream to the output.
|
|
197
198
|
*
|
|
198
199
|
* Configures output stream from encoder or input stream.
|
|
199
|
-
* Must be called before
|
|
200
|
+
* Must be called before writing any packets.
|
|
200
201
|
* Returns stream index for packet writing.
|
|
201
202
|
*
|
|
202
|
-
*
|
|
203
|
+
* Streams are initialized lazily - codec parameters are configured
|
|
204
|
+
* automatically when the first packet is written. This allows encoders
|
|
205
|
+
* to be initialized from frame properties.
|
|
206
|
+
*
|
|
207
|
+
* Direct mapping to avformat_new_stream().
|
|
203
208
|
*
|
|
204
209
|
* @param source - Encoder or stream to add
|
|
205
210
|
* @param options - Stream configuration options
|
|
206
211
|
* @param options.timeBase - Optional custom timebase for the stream
|
|
207
212
|
* @returns Stream index for packet writing
|
|
208
213
|
*
|
|
209
|
-
* @throws {Error} If called after
|
|
214
|
+
* @throws {Error} If called after packets have been written or output closed
|
|
210
215
|
*
|
|
211
216
|
* @example
|
|
212
217
|
* ```typescript
|
|
213
|
-
* // Add stream from encoder
|
|
218
|
+
* // Add stream from encoder (lazy initialization)
|
|
214
219
|
* const videoIdx = output.addStream(videoEncoder);
|
|
215
220
|
* const audioIdx = output.addStream(audioEncoder);
|
|
216
221
|
* ```
|
|
@@ -227,67 +232,72 @@ export class MediaOutput {
|
|
|
227
232
|
* @see {@link Encoder} For transcoding source
|
|
228
233
|
*/
|
|
229
234
|
addStream(source, options) {
|
|
230
|
-
if (this.
|
|
235
|
+
if (this.isClosed) {
|
|
231
236
|
throw new Error('MediaOutput is closed');
|
|
232
237
|
}
|
|
233
238
|
if (this.headerWritten) {
|
|
234
|
-
throw new Error('Cannot add streams after
|
|
239
|
+
throw new Error('Cannot add streams after packets have been written');
|
|
235
240
|
}
|
|
236
241
|
const stream = this.formatContext.newStream(null);
|
|
237
242
|
if (!stream) {
|
|
238
243
|
throw new Error('Failed to create new stream');
|
|
239
244
|
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
if (
|
|
243
|
-
|
|
244
|
-
const
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
245
|
+
const isStreamCopy = !(source instanceof Encoder);
|
|
246
|
+
// For stream copy, initialize immediately since we have all the info
|
|
247
|
+
if (isStreamCopy) {
|
|
248
|
+
const inputStream = source;
|
|
249
|
+
const ret = inputStream.codecpar.copy(stream.codecpar);
|
|
250
|
+
FFmpegError.throwIfError(ret, 'Failed to copy codec parameters');
|
|
251
|
+
// Set the timebases
|
|
252
|
+
const sourceTimeBase = inputStream.timeBase;
|
|
253
|
+
stream.timeBase = options?.timeBase ? new Rational(options.timeBase.num, options.timeBase.den) : inputStream.timeBase;
|
|
254
|
+
this.streams.set(stream.index, {
|
|
255
|
+
initialized: true,
|
|
256
|
+
stream,
|
|
257
|
+
source,
|
|
258
|
+
timeBase: options?.timeBase,
|
|
259
|
+
sourceTimeBase,
|
|
260
|
+
isStreamCopy: true,
|
|
261
|
+
bufferedPackets: [],
|
|
262
|
+
});
|
|
254
263
|
}
|
|
255
264
|
else {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
+
this.streams.set(stream.index, {
|
|
266
|
+
initialized: false,
|
|
267
|
+
stream,
|
|
268
|
+
source,
|
|
269
|
+
timeBase: options?.timeBase,
|
|
270
|
+
sourceTimeBase: undefined, // Will be set on initialization
|
|
271
|
+
isStreamCopy: false,
|
|
272
|
+
bufferedPackets: [],
|
|
273
|
+
});
|
|
265
274
|
}
|
|
266
|
-
this.streams.set(stream.index, {
|
|
267
|
-
stream,
|
|
268
|
-
timeBase: stream.timeBase,
|
|
269
|
-
isStreamCopy,
|
|
270
|
-
sourceTimeBase,
|
|
271
|
-
});
|
|
272
275
|
return stream.index;
|
|
273
276
|
}
|
|
274
277
|
/**
|
|
275
278
|
* Write a packet to the output.
|
|
276
279
|
*
|
|
277
280
|
* Writes muxed packet to the specified stream.
|
|
278
|
-
* Automatically handles
|
|
279
|
-
*
|
|
281
|
+
* Automatically handles:
|
|
282
|
+
* - Stream initialization on first packet (lazy initialization)
|
|
283
|
+
* - Codec parameter configuration from encoder or input stream
|
|
284
|
+
* - Header writing on first packet
|
|
285
|
+
* - Timestamp rescaling between source and output timebases
|
|
280
286
|
*
|
|
281
|
-
*
|
|
287
|
+
* For encoder sources, the encoder must have processed at least one frame
|
|
288
|
+
* before packets can be written (encoder must be initialized).
|
|
289
|
+
*
|
|
290
|
+
* Direct mapping to avformat_write_header() (on first packet) and av_interleaved_write_frame().
|
|
282
291
|
*
|
|
283
292
|
* @param packet - Packet to write
|
|
284
293
|
* @param streamIndex - Target stream index
|
|
285
|
-
* @throws {Error} If stream invalid or
|
|
294
|
+
* @throws {Error} If stream invalid or encoder not initialized
|
|
295
|
+
*
|
|
286
296
|
* @throws {FFmpegError} If write fails
|
|
287
297
|
*
|
|
288
298
|
* @example
|
|
289
299
|
* ```typescript
|
|
290
|
-
* // Write encoded packet
|
|
300
|
+
* // Write encoded packet - header written automatically on first packet
|
|
291
301
|
* const packet = await encoder.encode(frame);
|
|
292
302
|
* if (packet) {
|
|
293
303
|
* await output.writePacket(packet, videoIdx);
|
|
@@ -307,117 +317,93 @@ export class MediaOutput {
|
|
|
307
317
|
* ```
|
|
308
318
|
*
|
|
309
319
|
* @see {@link addStream} For adding streams
|
|
310
|
-
* @see {@link writeHeader} Must be called first
|
|
311
320
|
*/
|
|
312
321
|
async writePacket(packet, streamIndex) {
|
|
313
|
-
if (this.
|
|
322
|
+
if (this.isClosed) {
|
|
314
323
|
throw new Error('MediaOutput is closed');
|
|
315
324
|
}
|
|
316
|
-
if (!this.headerWritten) {
|
|
317
|
-
throw new Error('Header must be written before packets');
|
|
318
|
-
}
|
|
319
325
|
if (this.trailerWritten) {
|
|
320
|
-
throw new Error('Cannot write packets after
|
|
326
|
+
throw new Error('Cannot write packets after output is finalized');
|
|
321
327
|
}
|
|
322
|
-
|
|
323
|
-
if (!streamInfo) {
|
|
328
|
+
if (!this.streams.get(streamIndex)) {
|
|
324
329
|
throw new Error(`Invalid stream index: ${streamIndex}`);
|
|
325
330
|
}
|
|
326
|
-
//
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
const srcTb = streamInfo.sourceTimeBase;
|
|
335
|
-
const dstTb = outputStream.timeBase;
|
|
336
|
-
if (srcTb.num !== dstTb.num || srcTb.den !== dstTb.den) {
|
|
337
|
-
packet.rescaleTs(streamInfo.sourceTimeBase, outputStream.timeBase);
|
|
331
|
+
// Initialize any encoder streams that are ready
|
|
332
|
+
for (const streamInfo of this.streams.values()) {
|
|
333
|
+
if (!streamInfo.initialized && streamInfo.source instanceof Encoder) {
|
|
334
|
+
const encoder = streamInfo.source;
|
|
335
|
+
const codecContext = encoder.getCodecContext();
|
|
336
|
+
// Skip if encoder not ready yet
|
|
337
|
+
if (!encoder.isEncoderInitialized || !codecContext) {
|
|
338
|
+
continue;
|
|
338
339
|
}
|
|
340
|
+
// This encoder is ready, initialize it now
|
|
341
|
+
const ret = streamInfo.stream.codecpar.fromContext(codecContext);
|
|
342
|
+
FFmpegError.throwIfError(ret, 'Failed to copy codec parameters from encoder');
|
|
343
|
+
// Update the timebase from the encoder
|
|
344
|
+
streamInfo.sourceTimeBase = codecContext.timeBase;
|
|
345
|
+
// Output stream uses encoder's timebase (or custom if specified)
|
|
346
|
+
streamInfo.stream.timeBase = streamInfo.timeBase ? new Rational(streamInfo.timeBase.num, streamInfo.timeBase.den) : codecContext.timeBase;
|
|
347
|
+
// Mark as initialized
|
|
348
|
+
streamInfo.initialized = true;
|
|
339
349
|
}
|
|
340
350
|
}
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
*
|
|
352
|
-
* Direct mapping to avformat_write_header().
|
|
353
|
-
*
|
|
354
|
-
* @throws {Error} If already written or output closed
|
|
355
|
-
* @throws {FFmpegError} If write fails
|
|
356
|
-
*
|
|
357
|
-
* @example
|
|
358
|
-
* ```typescript
|
|
359
|
-
* // Standard workflow
|
|
360
|
-
* const output = await MediaOutput.open('output.mp4');
|
|
361
|
-
* output.addStream(encoder);
|
|
362
|
-
* await output.writeHeader();
|
|
363
|
-
* // Now ready to write packets
|
|
364
|
-
* ```
|
|
365
|
-
*
|
|
366
|
-
* @see {@link addStream} Must add streams first
|
|
367
|
-
* @see {@link writePacket} Can write packets after
|
|
368
|
-
* @see {@link writeTrailer} Must call at end
|
|
369
|
-
*/
|
|
370
|
-
async writeHeader() {
|
|
371
|
-
if (this.closed) {
|
|
372
|
-
throw new Error('MediaOutput is closed');
|
|
373
|
-
}
|
|
374
|
-
if (this.headerWritten) {
|
|
375
|
-
throw new Error('Header already written');
|
|
376
|
-
}
|
|
377
|
-
const ret = await this.formatContext.writeHeader();
|
|
378
|
-
FFmpegError.throwIfError(ret, 'Failed to write header');
|
|
379
|
-
this.headerWritten = true;
|
|
380
|
-
}
|
|
381
|
-
/**
|
|
382
|
-
* Write file trailer.
|
|
383
|
-
*
|
|
384
|
-
* Writes format trailer and finalizes the file.
|
|
385
|
-
* Must be called after all packets are written.
|
|
386
|
-
* Flushes any buffered data and updates file headers.
|
|
387
|
-
*
|
|
388
|
-
* Direct mapping to av_write_trailer().
|
|
389
|
-
*
|
|
390
|
-
* @throws {Error} If header not written or already written
|
|
391
|
-
* @throws {FFmpegError} If write fails
|
|
392
|
-
*
|
|
393
|
-
* @example
|
|
394
|
-
* ```typescript
|
|
395
|
-
* // Finalize output
|
|
396
|
-
* await output.writeTrailer();
|
|
397
|
-
* await output.close();
|
|
398
|
-
* ```
|
|
399
|
-
*
|
|
400
|
-
* @see {@link writeHeader} Must be called first
|
|
401
|
-
* @see {@link close} For cleanup after trailer
|
|
402
|
-
*/
|
|
403
|
-
async writeTrailer() {
|
|
404
|
-
if (this.closed) {
|
|
405
|
-
throw new Error('MediaOutput is closed');
|
|
351
|
+
const streamInfo = this.streams.get(streamIndex);
|
|
352
|
+
// Check if any streams are still uninitialized
|
|
353
|
+
const uninitialized = Array.from(this.streams.values()).some((s) => !s.initialized);
|
|
354
|
+
if (uninitialized) {
|
|
355
|
+
const clonedPacket = packet.clone();
|
|
356
|
+
packet.free();
|
|
357
|
+
if (clonedPacket) {
|
|
358
|
+
streamInfo.bufferedPackets.push(clonedPacket);
|
|
359
|
+
}
|
|
360
|
+
return;
|
|
406
361
|
}
|
|
362
|
+
// Automatically write header if not written yet
|
|
363
|
+
// Use a promise to ensure only one thread writes the header
|
|
407
364
|
if (!this.headerWritten) {
|
|
408
|
-
|
|
365
|
+
this.headerWritePromise ??= (async () => {
|
|
366
|
+
const ret = await this.formatContext.writeHeader();
|
|
367
|
+
FFmpegError.throwIfError(ret, 'Failed to write header');
|
|
368
|
+
this.headerWritten = true;
|
|
369
|
+
})();
|
|
370
|
+
// All threads wait for the header to be written
|
|
371
|
+
await this.headerWritePromise;
|
|
409
372
|
}
|
|
410
|
-
|
|
411
|
-
|
|
373
|
+
// Set stream index
|
|
374
|
+
packet.streamIndex = streamIndex;
|
|
375
|
+
const write = async (pkt) => {
|
|
376
|
+
// Rescale packet timestamps if source and output timebases differ
|
|
377
|
+
// Note: The stream's timebase may have been changed by writeHeader (e.g., MP4 uses 1/time_scale)
|
|
378
|
+
if (streamInfo.sourceTimeBase) {
|
|
379
|
+
const outputStream = this.formatContext.streams?.[streamIndex];
|
|
380
|
+
if (outputStream) {
|
|
381
|
+
// Only rescale if timebases actually differ
|
|
382
|
+
const srcTb = streamInfo.sourceTimeBase;
|
|
383
|
+
const dstTb = outputStream.timeBase;
|
|
384
|
+
if (srcTb.num !== dstTb.num || srcTb.den !== dstTb.den) {
|
|
385
|
+
pkt.rescaleTs(streamInfo.sourceTimeBase, outputStream.timeBase);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
// Write the packet
|
|
390
|
+
const ret = await this.formatContext.interleavedWriteFrame(pkt);
|
|
391
|
+
FFmpegError.throwIfError(ret, 'Failed to write packet');
|
|
392
|
+
};
|
|
393
|
+
// Write any buffered packets first
|
|
394
|
+
for (const bufferedPacket of streamInfo.bufferedPackets) {
|
|
395
|
+
await write(bufferedPacket);
|
|
396
|
+
bufferedPacket.free();
|
|
412
397
|
}
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
398
|
+
streamInfo.bufferedPackets = [];
|
|
399
|
+
// Write the current packet
|
|
400
|
+
await write(packet);
|
|
416
401
|
}
|
|
417
402
|
/**
|
|
418
403
|
* Close media output and free resources.
|
|
419
404
|
*
|
|
420
|
-
*
|
|
405
|
+
* Automatically writes trailer if header was written.
|
|
406
|
+
* Closes the output file and releases all resources.
|
|
421
407
|
* Safe to call multiple times.
|
|
422
408
|
* Automatically called by Symbol.asyncDispose.
|
|
423
409
|
*
|
|
@@ -425,7 +411,7 @@ export class MediaOutput {
|
|
|
425
411
|
* ```typescript
|
|
426
412
|
* const output = await MediaOutput.open('output.mp4');
|
|
427
413
|
* try {
|
|
428
|
-
* // Use output
|
|
414
|
+
* // Use output - trailer written automatically on close
|
|
429
415
|
* } finally {
|
|
430
416
|
* await output.close();
|
|
431
417
|
* }
|
|
@@ -434,14 +420,23 @@ export class MediaOutput {
|
|
|
434
420
|
* @see {@link Symbol.asyncDispose} For automatic cleanup
|
|
435
421
|
*/
|
|
436
422
|
async close() {
|
|
437
|
-
if (this.
|
|
423
|
+
if (this.isClosed) {
|
|
438
424
|
return;
|
|
439
425
|
}
|
|
440
|
-
this.
|
|
426
|
+
this.isClosed = true;
|
|
427
|
+
// Free any buffered packets
|
|
428
|
+
for (const streamInfo of this.streams.values()) {
|
|
429
|
+
// Free any buffered packets
|
|
430
|
+
for (const pkt of streamInfo.bufferedPackets) {
|
|
431
|
+
pkt.free();
|
|
432
|
+
}
|
|
433
|
+
streamInfo.bufferedPackets = [];
|
|
434
|
+
}
|
|
441
435
|
// Try to write trailer if header was written but trailer wasn't
|
|
442
436
|
try {
|
|
443
437
|
if (this.headerWritten && !this.trailerWritten) {
|
|
444
438
|
await this.formatContext.writeTrailer();
|
|
439
|
+
this.trailerWritten = true;
|
|
445
440
|
}
|
|
446
441
|
}
|
|
447
442
|
catch {
|
|
@@ -482,69 +477,6 @@ export class MediaOutput {
|
|
|
482
477
|
}
|
|
483
478
|
}
|
|
484
479
|
}
|
|
485
|
-
/**
|
|
486
|
-
* Get stream information.
|
|
487
|
-
*
|
|
488
|
-
* Returns internal stream info for the specified index.
|
|
489
|
-
*
|
|
490
|
-
* @param streamIndex - Stream index
|
|
491
|
-
* @returns Stream info or undefined
|
|
492
|
-
*
|
|
493
|
-
* @example
|
|
494
|
-
* ```typescript
|
|
495
|
-
* const info = output.getStreamInfo(0);
|
|
496
|
-
* console.log(`Stream 0 timebase: ${info?.timeBase.num}/${info?.timeBase.den}`);
|
|
497
|
-
* ```
|
|
498
|
-
*/
|
|
499
|
-
getStreamInfo(streamIndex) {
|
|
500
|
-
return this.streams.get(streamIndex);
|
|
501
|
-
}
|
|
502
|
-
/**
|
|
503
|
-
* Get all stream indices.
|
|
504
|
-
*
|
|
505
|
-
* Returns array of all added stream indices.
|
|
506
|
-
*
|
|
507
|
-
* @returns Array of stream indices
|
|
508
|
-
*
|
|
509
|
-
* @example
|
|
510
|
-
* ```typescript
|
|
511
|
-
* const indices = output.getStreamIndices();
|
|
512
|
-
* console.log(`Output has ${indices.length} streams`);
|
|
513
|
-
* ```
|
|
514
|
-
*/
|
|
515
|
-
getStreamIndices() {
|
|
516
|
-
return Array.from(this.streams.keys());
|
|
517
|
-
}
|
|
518
|
-
/**
|
|
519
|
-
* Check if header has been written.
|
|
520
|
-
*
|
|
521
|
-
* @returns true if header written
|
|
522
|
-
*
|
|
523
|
-
* @example
|
|
524
|
-
* ```typescript
|
|
525
|
-
* if (!output.isHeaderWritten()) {
|
|
526
|
-
* await output.writeHeader();
|
|
527
|
-
* }
|
|
528
|
-
* ```
|
|
529
|
-
*/
|
|
530
|
-
isHeaderWritten() {
|
|
531
|
-
return this.headerWritten;
|
|
532
|
-
}
|
|
533
|
-
/**
|
|
534
|
-
* Check if trailer has been written.
|
|
535
|
-
*
|
|
536
|
-
* @returns true if trailer written
|
|
537
|
-
*
|
|
538
|
-
* @example
|
|
539
|
-
* ```typescript
|
|
540
|
-
* if (!output.isTrailerWritten()) {
|
|
541
|
-
* await output.writeTrailer();
|
|
542
|
-
* }
|
|
543
|
-
* ```
|
|
544
|
-
*/
|
|
545
|
-
isTrailerWritten() {
|
|
546
|
-
return this.trailerWritten;
|
|
547
|
-
}
|
|
548
480
|
/**
|
|
549
481
|
* Get underlying format context.
|
|
550
482
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"media-output.js","sourceRoot":"","sources":["../../src/api/media-output.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAExC,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAChG,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAClF,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"media-output.js","sourceRoot":"","sources":["../../src/api/media-output.ts"],"names":[],"mappings":"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"}
|