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/decoder.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { AVERROR_EAGAIN, AVERROR_EOF } from '../constants/constants.js';
|
|
2
|
+
import { Codec, CodecContext, Dictionary, FFmpegError, Frame } from '../lib/index.js';
|
|
3
3
|
/**
|
|
4
4
|
* High-level decoder for audio and video streams.
|
|
5
5
|
*
|
|
@@ -44,23 +44,25 @@ import { AVERROR_EAGAIN, Codec, CodecContext, FFmpegError, Frame } from '../lib/
|
|
|
44
44
|
*/
|
|
45
45
|
export class Decoder {
|
|
46
46
|
codecContext;
|
|
47
|
+
codec;
|
|
47
48
|
frame;
|
|
48
|
-
streamIndex;
|
|
49
49
|
stream;
|
|
50
|
-
|
|
50
|
+
initialized = true;
|
|
51
|
+
isClosed = false;
|
|
51
52
|
hardware;
|
|
52
53
|
/**
|
|
53
54
|
* @param codecContext - Configured codec context
|
|
55
|
+
* @param codec - Codec being used
|
|
54
56
|
* @param stream - Media stream being decoded
|
|
55
57
|
* @param hardware - Optional hardware context
|
|
56
58
|
* Use {@link create} factory method
|
|
57
59
|
*
|
|
58
60
|
* @internal
|
|
59
61
|
*/
|
|
60
|
-
constructor(codecContext, stream, hardware) {
|
|
62
|
+
constructor(codecContext, codec, stream, hardware) {
|
|
61
63
|
this.codecContext = codecContext;
|
|
64
|
+
this.codec = codec;
|
|
62
65
|
this.stream = stream;
|
|
63
|
-
this.streamIndex = stream.index;
|
|
64
66
|
this.hardware = hardware;
|
|
65
67
|
this.frame = new Frame();
|
|
66
68
|
this.frame.alloc();
|
|
@@ -77,6 +79,7 @@ export class Decoder {
|
|
|
77
79
|
* @returns Configured decoder instance
|
|
78
80
|
*
|
|
79
81
|
* @throws {Error} If decoder not found for codec
|
|
82
|
+
*
|
|
80
83
|
* @throws {FFmpegError} If codec initialization fails
|
|
81
84
|
*
|
|
82
85
|
* @example
|
|
@@ -141,20 +144,14 @@ export class Decoder {
|
|
|
141
144
|
if (isHWDecoder && options.hardware) {
|
|
142
145
|
codecContext.hwDeviceCtx = options.hardware.deviceContext;
|
|
143
146
|
}
|
|
144
|
-
|
|
145
|
-
if (options.options) {
|
|
146
|
-
for (const [key, value] of Object.entries(options.options)) {
|
|
147
|
-
codecContext.setOption(key, value.toString());
|
|
148
|
-
}
|
|
149
|
-
}
|
|
147
|
+
const opts = options.options ? Dictionary.fromObject(options.options) : undefined;
|
|
150
148
|
// Open codec
|
|
151
|
-
const openRet = await codecContext.open2(codec,
|
|
149
|
+
const openRet = await codecContext.open2(codec, opts);
|
|
152
150
|
if (openRet < 0) {
|
|
153
151
|
codecContext.freeContext();
|
|
154
152
|
FFmpegError.throwIfError(openRet, 'Failed to open codec');
|
|
155
153
|
}
|
|
156
|
-
|
|
157
|
-
return decoder;
|
|
154
|
+
return new Decoder(codecContext, codec, stream, isHWDecoder ? options.hardware : undefined);
|
|
158
155
|
}
|
|
159
156
|
/**
|
|
160
157
|
* Check if decoder is open.
|
|
@@ -169,59 +166,25 @@ export class Decoder {
|
|
|
169
166
|
* ```
|
|
170
167
|
*/
|
|
171
168
|
get isDecoderOpen() {
|
|
172
|
-
return this.
|
|
169
|
+
return !this.isClosed;
|
|
173
170
|
}
|
|
174
171
|
/**
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
* Returns format information about decoded frames.
|
|
178
|
-
* For hardware decoding, returns the hardware pixel format.
|
|
179
|
-
* Essential for configuring downstream components like encoders or filters.
|
|
172
|
+
* Check if decoder has been initialized.
|
|
180
173
|
*
|
|
181
|
-
*
|
|
174
|
+
* Returns true if decoder is initialized (true by default for decoders).
|
|
175
|
+
* Decoders are pre-initialized from stream parameters.
|
|
182
176
|
*
|
|
183
|
-
* @
|
|
184
|
-
* ```typescript
|
|
185
|
-
* const info = decoder.getOutputStreamInfo();
|
|
186
|
-
* if (info.type === 'video') {
|
|
187
|
-
* console.log(`Video: ${info.width}x${info.height} @ ${info.pixelFormat}`);
|
|
188
|
-
* console.log(`Frame rate: ${info.frameRate.num}/${info.frameRate.den}`);
|
|
189
|
-
* }
|
|
190
|
-
* ```
|
|
177
|
+
* @returns true if decoder has been initialized
|
|
191
178
|
*
|
|
192
179
|
* @example
|
|
193
180
|
* ```typescript
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
* console.log(`Audio: ${info.sampleRate}Hz ${info.sampleFormat}`);
|
|
197
|
-
* console.log(`Channels: ${info.channelLayout}`);
|
|
181
|
+
* if (decoder.isDecoderInitialized) {
|
|
182
|
+
* console.log('Decoder is ready to process frames');
|
|
198
183
|
* }
|
|
199
184
|
* ```
|
|
200
|
-
*
|
|
201
|
-
* @see {@link StreamInfo} For format details
|
|
202
|
-
* @see {@link Encoder.create} For matching encoder configuration
|
|
203
185
|
*/
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
return {
|
|
207
|
-
type: 'video',
|
|
208
|
-
width: this.codecContext.width,
|
|
209
|
-
height: this.codecContext.height,
|
|
210
|
-
pixelFormat: this.hardware?.devicePixelFormat ?? this.codecContext.pixelFormat,
|
|
211
|
-
timeBase: this.stream.timeBase,
|
|
212
|
-
frameRate: this.stream.rFrameRate,
|
|
213
|
-
sampleAspectRatio: this.codecContext.sampleAspectRatio,
|
|
214
|
-
};
|
|
215
|
-
}
|
|
216
|
-
else {
|
|
217
|
-
return {
|
|
218
|
-
type: 'audio',
|
|
219
|
-
sampleRate: this.codecContext.sampleRate,
|
|
220
|
-
sampleFormat: this.codecContext.sampleFormat,
|
|
221
|
-
channelLayout: this.codecContext.channelLayout,
|
|
222
|
-
timeBase: this.stream.timeBase,
|
|
223
|
-
};
|
|
224
|
-
}
|
|
186
|
+
get isDecoderInitialized() {
|
|
187
|
+
return this.initialized;
|
|
225
188
|
}
|
|
226
189
|
/**
|
|
227
190
|
* Check if decoder uses hardware acceleration.
|
|
@@ -238,7 +201,22 @@ export class Decoder {
|
|
|
238
201
|
* @see {@link HardwareContext} For hardware setup
|
|
239
202
|
*/
|
|
240
203
|
isHardware() {
|
|
241
|
-
return !!this.hardware;
|
|
204
|
+
return !!this.hardware && this.codec.isHardwareAcceleratedDecoder();
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Check if decoder is ready for processing.
|
|
208
|
+
*
|
|
209
|
+
* @returns true if initialized and ready
|
|
210
|
+
*
|
|
211
|
+
* @example
|
|
212
|
+
* ```typescript
|
|
213
|
+
* if (decoder.isReady()) {
|
|
214
|
+
* const frame = await decoder.decode(packet);
|
|
215
|
+
* }
|
|
216
|
+
* ```
|
|
217
|
+
*/
|
|
218
|
+
isReady() {
|
|
219
|
+
return this.initialized && !this.isClosed;
|
|
242
220
|
}
|
|
243
221
|
/**
|
|
244
222
|
* Decode a packet to a frame.
|
|
@@ -253,6 +231,7 @@ export class Decoder {
|
|
|
253
231
|
* @returns Decoded frame or null if more data needed
|
|
254
232
|
*
|
|
255
233
|
* @throws {Error} If decoder is closed
|
|
234
|
+
*
|
|
256
235
|
* @throws {FFmpegError} If decoding fails
|
|
257
236
|
*
|
|
258
237
|
* @example
|
|
@@ -267,7 +246,7 @@ export class Decoder {
|
|
|
267
246
|
* @example
|
|
268
247
|
* ```typescript
|
|
269
248
|
* for await (const packet of input.packets()) {
|
|
270
|
-
* if (packet.streamIndex === decoder.
|
|
249
|
+
* if (packet.streamIndex === decoder.getStream().index) {
|
|
271
250
|
* const frame = await decoder.decode(packet);
|
|
272
251
|
* if (frame) {
|
|
273
252
|
* await processFrame(frame);
|
|
@@ -282,14 +261,14 @@ export class Decoder {
|
|
|
282
261
|
* @see {@link flush} For end-of-stream handling
|
|
283
262
|
*/
|
|
284
263
|
async decode(packet) {
|
|
285
|
-
if (
|
|
264
|
+
if (this.isClosed) {
|
|
286
265
|
throw new Error('Decoder is closed');
|
|
287
266
|
}
|
|
288
267
|
// Send packet to decoder
|
|
289
268
|
const sendRet = await this.codecContext.sendPacket(packet);
|
|
290
269
|
if (sendRet < 0 && sendRet !== AVERROR_EOF) {
|
|
291
270
|
// Decoder might be full, try to receive first
|
|
292
|
-
const frame = await this.
|
|
271
|
+
const frame = await this.receive();
|
|
293
272
|
if (frame) {
|
|
294
273
|
return frame;
|
|
295
274
|
}
|
|
@@ -299,78 +278,9 @@ export class Decoder {
|
|
|
299
278
|
}
|
|
300
279
|
}
|
|
301
280
|
// Try to receive frame
|
|
302
|
-
const frame = await this.
|
|
281
|
+
const frame = await this.receive();
|
|
303
282
|
return frame;
|
|
304
283
|
}
|
|
305
|
-
/**
|
|
306
|
-
* Flush decoder and get buffered frame.
|
|
307
|
-
*
|
|
308
|
-
* Signals end-of-stream and retrieves remaining frames.
|
|
309
|
-
* Call repeatedly until null to get all buffered frames.
|
|
310
|
-
* Essential for ensuring all frames are decoded.
|
|
311
|
-
*
|
|
312
|
-
* Direct mapping to avcodec_send_packet(NULL).
|
|
313
|
-
*
|
|
314
|
-
* @returns Buffered frame or null if none remaining
|
|
315
|
-
*
|
|
316
|
-
* @throws {Error} If decoder is closed
|
|
317
|
-
*
|
|
318
|
-
* @example
|
|
319
|
-
* ```typescript
|
|
320
|
-
* // After all packets processed
|
|
321
|
-
* let frame;
|
|
322
|
-
* while ((frame = await decoder.flush()) !== null) {
|
|
323
|
-
* console.log('Got buffered frame');
|
|
324
|
-
* await processFrame(frame);
|
|
325
|
-
* frame.free();
|
|
326
|
-
* }
|
|
327
|
-
* ```
|
|
328
|
-
*
|
|
329
|
-
* @see {@link flushFrames} For async iteration
|
|
330
|
-
* @see {@link frames} For complete decoding pipeline
|
|
331
|
-
*/
|
|
332
|
-
async flush() {
|
|
333
|
-
if (!this.isOpen) {
|
|
334
|
-
throw new Error('Decoder is closed');
|
|
335
|
-
}
|
|
336
|
-
// Send flush packet (null)
|
|
337
|
-
await this.codecContext.sendPacket(null);
|
|
338
|
-
// Receive frame
|
|
339
|
-
const frame = await this.receiveFrameInternal();
|
|
340
|
-
return frame;
|
|
341
|
-
}
|
|
342
|
-
/**
|
|
343
|
-
* Flush all buffered frames as async generator.
|
|
344
|
-
*
|
|
345
|
-
* Convenient async iteration over remaining frames.
|
|
346
|
-
* Automatically handles repeated flush calls.
|
|
347
|
-
* Useful for end-of-stream processing.
|
|
348
|
-
*
|
|
349
|
-
* @yields Buffered frames
|
|
350
|
-
* @throws {Error} If decoder is closed
|
|
351
|
-
*
|
|
352
|
-
* @example
|
|
353
|
-
* ```typescript
|
|
354
|
-
* // Flush at end of decoding
|
|
355
|
-
* for await (const frame of decoder.flushFrames()) {
|
|
356
|
-
* console.log('Processing buffered frame');
|
|
357
|
-
* await encoder.encode(frame);
|
|
358
|
-
* frame.free();
|
|
359
|
-
* }
|
|
360
|
-
* ```
|
|
361
|
-
*
|
|
362
|
-
* @see {@link flush} For single frame flush
|
|
363
|
-
* @see {@link frames} For complete pipeline
|
|
364
|
-
*/
|
|
365
|
-
async *flushFrames() {
|
|
366
|
-
if (!this.isOpen) {
|
|
367
|
-
throw new Error('Decoder is closed');
|
|
368
|
-
}
|
|
369
|
-
let frame;
|
|
370
|
-
while ((frame = await this.flush()) !== null) {
|
|
371
|
-
yield frame;
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
284
|
/**
|
|
375
285
|
* Decode packet stream to frame stream.
|
|
376
286
|
*
|
|
@@ -380,8 +290,9 @@ export class Decoder {
|
|
|
380
290
|
* Primary interface for stream-based decoding.
|
|
381
291
|
*
|
|
382
292
|
* @param packets - Async iterable of packets
|
|
383
|
-
* @yields Decoded frames
|
|
293
|
+
* @yields {Frame} Decoded frames
|
|
384
294
|
* @throws {Error} If decoder is closed
|
|
295
|
+
*
|
|
385
296
|
* @throws {FFmpegError} If decoding fails
|
|
386
297
|
*
|
|
387
298
|
* @example
|
|
@@ -399,7 +310,7 @@ export class Decoder {
|
|
|
399
310
|
* ```typescript
|
|
400
311
|
* for await (const frame of decoder.frames(input.packets())) {
|
|
401
312
|
* // Process frame
|
|
402
|
-
* await filter.
|
|
313
|
+
* await filter.process(frame);
|
|
403
314
|
*
|
|
404
315
|
* // Frame automatically freed
|
|
405
316
|
* frame.free();
|
|
@@ -423,14 +334,11 @@ export class Decoder {
|
|
|
423
334
|
* @see {@link MediaInput.packets} For packet source
|
|
424
335
|
*/
|
|
425
336
|
async *frames(packets) {
|
|
426
|
-
if (!this.isOpen) {
|
|
427
|
-
throw new Error('Decoder is closed');
|
|
428
|
-
}
|
|
429
337
|
// Process packets
|
|
430
338
|
for await (const packet of packets) {
|
|
431
339
|
try {
|
|
432
340
|
// Only process packets for our stream
|
|
433
|
-
if (packet.streamIndex === this.
|
|
341
|
+
if (packet.streamIndex === this.stream.index) {
|
|
434
342
|
const frame = await this.decode(packet);
|
|
435
343
|
if (frame) {
|
|
436
344
|
yield frame;
|
|
@@ -443,11 +351,137 @@ export class Decoder {
|
|
|
443
351
|
}
|
|
444
352
|
}
|
|
445
353
|
// Flush decoder after all packets
|
|
354
|
+
await this.flush();
|
|
355
|
+
while (true) {
|
|
356
|
+
const remaining = await this.receive();
|
|
357
|
+
if (!remaining)
|
|
358
|
+
break;
|
|
359
|
+
yield remaining;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Flush decoder and signal end-of-stream.
|
|
364
|
+
*
|
|
365
|
+
* Sends null packet to decoder to signal end-of-stream.
|
|
366
|
+
* Does nothing if decoder is closed.
|
|
367
|
+
* Must use receive() or flushFrames() to get remaining buffered frames.
|
|
368
|
+
*
|
|
369
|
+
* Direct mapping to avcodec_send_packet(NULL).
|
|
370
|
+
*
|
|
371
|
+
* @throws {FFmpegError} If flush fails
|
|
372
|
+
*
|
|
373
|
+
* @example
|
|
374
|
+
* ```typescript
|
|
375
|
+
* // Signal end of stream
|
|
376
|
+
* await decoder.flush();
|
|
377
|
+
*
|
|
378
|
+
* // Then get remaining frames
|
|
379
|
+
* let frame;
|
|
380
|
+
* while ((frame = await decoder.receive()) !== null) {
|
|
381
|
+
* console.log('Got buffered frame');
|
|
382
|
+
* frame.free();
|
|
383
|
+
* }
|
|
384
|
+
* ```
|
|
385
|
+
*
|
|
386
|
+
* @see {@link flushFrames} For convenient async iteration
|
|
387
|
+
* @see {@link receive} For getting buffered frames
|
|
388
|
+
*/
|
|
389
|
+
async flush() {
|
|
390
|
+
if (this.isClosed) {
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
// Send flush packet (null)
|
|
394
|
+
const ret = await this.codecContext.sendPacket(null);
|
|
395
|
+
if (ret < 0 && ret !== AVERROR_EOF) {
|
|
396
|
+
if (ret !== AVERROR_EAGAIN) {
|
|
397
|
+
FFmpegError.throwIfError(ret, 'Failed to flush decoder');
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Flush all buffered frames as async generator.
|
|
403
|
+
*
|
|
404
|
+
* Convenient async iteration over remaining frames.
|
|
405
|
+
* Automatically sends flush signal and retrieves buffered frames.
|
|
406
|
+
* Useful for end-of-stream processing.
|
|
407
|
+
*
|
|
408
|
+
* @yields {Frame} Buffered frames
|
|
409
|
+
*
|
|
410
|
+
* @example
|
|
411
|
+
* ```typescript
|
|
412
|
+
* // Flush at end of decoding
|
|
413
|
+
* for await (const frame of decoder.flushFrames()) {
|
|
414
|
+
* console.log('Processing buffered frame');
|
|
415
|
+
* await encoder.encode(frame);
|
|
416
|
+
* frame.free();
|
|
417
|
+
* }
|
|
418
|
+
* ```
|
|
419
|
+
*
|
|
420
|
+
* @see {@link flush} For signaling end-of-stream
|
|
421
|
+
* @see {@link frames} For complete pipeline
|
|
422
|
+
*/
|
|
423
|
+
async *flushFrames() {
|
|
424
|
+
// Send flush signal
|
|
425
|
+
await this.flush();
|
|
446
426
|
let frame;
|
|
447
|
-
while ((frame = await this.
|
|
427
|
+
while ((frame = await this.receive()) !== null) {
|
|
448
428
|
yield frame;
|
|
449
429
|
}
|
|
450
430
|
}
|
|
431
|
+
/**
|
|
432
|
+
* Receive frame from decoder.
|
|
433
|
+
*
|
|
434
|
+
* Gets decoded frames from the codec's internal buffer.
|
|
435
|
+
* Handles frame cloning and error checking.
|
|
436
|
+
* Hardware frames include hw_frames_ctx reference.
|
|
437
|
+
* Call repeatedly until null to drain all buffered frames.
|
|
438
|
+
*
|
|
439
|
+
* Direct mapping to avcodec_receive_frame().
|
|
440
|
+
*
|
|
441
|
+
* @returns Cloned frame or null if no frames available
|
|
442
|
+
*
|
|
443
|
+
* @throws {FFmpegError} If receive fails with error other than AVERROR_EAGAIN or AVERROR_EOF
|
|
444
|
+
*
|
|
445
|
+
* @example
|
|
446
|
+
* ```typescript
|
|
447
|
+
* const frame = await decoder.receive();
|
|
448
|
+
* if (frame) {
|
|
449
|
+
* console.log('Got decoded frame');
|
|
450
|
+
* frame.free();
|
|
451
|
+
* }
|
|
452
|
+
* ```
|
|
453
|
+
*
|
|
454
|
+
* @example
|
|
455
|
+
* ```typescript
|
|
456
|
+
* // Drain all buffered frames
|
|
457
|
+
* let frame;
|
|
458
|
+
* while ((frame = await decoder.receive()) !== null) {
|
|
459
|
+
* console.log(`Frame PTS: ${frame.pts}`);
|
|
460
|
+
* frame.free();
|
|
461
|
+
* }
|
|
462
|
+
* ```
|
|
463
|
+
*
|
|
464
|
+
* @see {@link decode} For sending packets and receiving frames
|
|
465
|
+
* @see {@link flush} For signaling end-of-stream
|
|
466
|
+
*/
|
|
467
|
+
async receive() {
|
|
468
|
+
// Clear previous frame data
|
|
469
|
+
this.frame.unref();
|
|
470
|
+
const ret = await this.codecContext.receiveFrame(this.frame);
|
|
471
|
+
if (ret === 0) {
|
|
472
|
+
// Got a frame, clone it for the user
|
|
473
|
+
return this.frame.clone();
|
|
474
|
+
}
|
|
475
|
+
else if (ret === AVERROR_EAGAIN || ret === AVERROR_EOF) {
|
|
476
|
+
// Need more data or end of stream
|
|
477
|
+
return null;
|
|
478
|
+
}
|
|
479
|
+
else {
|
|
480
|
+
// Error
|
|
481
|
+
FFmpegError.throwIfError(ret, 'Failed to receive frame');
|
|
482
|
+
return null;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
451
485
|
/**
|
|
452
486
|
* Close decoder and free resources.
|
|
453
487
|
*
|
|
@@ -468,32 +502,13 @@ export class Decoder {
|
|
|
468
502
|
* @see {@link Symbol.dispose} For automatic cleanup
|
|
469
503
|
*/
|
|
470
504
|
close() {
|
|
471
|
-
if (
|
|
505
|
+
if (this.isClosed) {
|
|
472
506
|
return;
|
|
473
507
|
}
|
|
508
|
+
this.isClosed = true;
|
|
474
509
|
this.frame.free();
|
|
475
510
|
this.codecContext.freeContext();
|
|
476
|
-
this.
|
|
477
|
-
}
|
|
478
|
-
/**
|
|
479
|
-
* Get stream index.
|
|
480
|
-
*
|
|
481
|
-
* Returns the index of the stream being decoded.
|
|
482
|
-
* Used for packet filtering in multi-stream files.
|
|
483
|
-
*
|
|
484
|
-
* @returns Stream index
|
|
485
|
-
*
|
|
486
|
-
* @example
|
|
487
|
-
* ```typescript
|
|
488
|
-
* if (packet.streamIndex === decoder.getStreamIndex()) {
|
|
489
|
-
* const frame = await decoder.decode(packet);
|
|
490
|
-
* }
|
|
491
|
-
* ```
|
|
492
|
-
*
|
|
493
|
-
* @see {@link getStream} For full stream object
|
|
494
|
-
*/
|
|
495
|
-
getStreamIndex() {
|
|
496
|
-
return this.streamIndex;
|
|
511
|
+
this.initialized = false;
|
|
497
512
|
}
|
|
498
513
|
/**
|
|
499
514
|
* Get stream object.
|
|
@@ -503,65 +518,43 @@ export class Decoder {
|
|
|
503
518
|
*
|
|
504
519
|
* @returns Stream object
|
|
505
520
|
*
|
|
506
|
-
* @
|
|
507
|
-
* ```typescript
|
|
508
|
-
* const stream = decoder.getStream();
|
|
509
|
-
* console.log(`Duration: ${stream.duration}`);
|
|
510
|
-
* console.log(`Time base: ${stream.timeBase.num}/${stream.timeBase.den}`);
|
|
511
|
-
* ```
|
|
521
|
+
* @internal
|
|
512
522
|
*
|
|
513
|
-
* @see {@link Stream} For stream
|
|
514
|
-
* @see {@link getStreamIndex} For index only
|
|
523
|
+
* @see {@link Stream} For stream details
|
|
515
524
|
*/
|
|
516
525
|
getStream() {
|
|
517
526
|
return this.stream;
|
|
518
527
|
}
|
|
519
528
|
/**
|
|
520
|
-
* Get
|
|
529
|
+
* Get decoder codec.
|
|
521
530
|
*
|
|
522
|
-
* Returns the
|
|
523
|
-
*
|
|
531
|
+
* Returns the codec used by this decoder.
|
|
532
|
+
* Useful for checking codec capabilities and properties.
|
|
524
533
|
*
|
|
525
|
-
* @returns Codec
|
|
534
|
+
* @returns Codec instance
|
|
526
535
|
*
|
|
527
536
|
* @internal
|
|
537
|
+
*
|
|
538
|
+
* @see {@link Codec} For codec details
|
|
528
539
|
*/
|
|
529
|
-
|
|
530
|
-
return this.
|
|
540
|
+
getCodec() {
|
|
541
|
+
return this.codec;
|
|
531
542
|
}
|
|
532
543
|
/**
|
|
533
|
-
*
|
|
534
|
-
*
|
|
535
|
-
* Internal method to get decoded frames from codec.
|
|
536
|
-
* Handles frame cloning and error checking.
|
|
537
|
-
* Hardware frames include hw_frames_ctx reference.
|
|
544
|
+
* Get underlying codec context.
|
|
538
545
|
*
|
|
539
|
-
*
|
|
546
|
+
* Returns the codec context for advanced operations.
|
|
547
|
+
* Useful for accessing low-level codec properties and settings.
|
|
548
|
+
* Returns null if decoder is closed.
|
|
540
549
|
*
|
|
541
|
-
* @returns
|
|
550
|
+
* @returns Codec context or null if closed
|
|
542
551
|
*
|
|
543
|
-
* @
|
|
552
|
+
* @internal
|
|
544
553
|
*
|
|
554
|
+
* @see {@link CodecContext} For context details
|
|
545
555
|
*/
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
this.frame.unref();
|
|
549
|
-
const ret = await this.codecContext.receiveFrame(this.frame);
|
|
550
|
-
if (ret === 0) {
|
|
551
|
-
// Note: hw_frames_ctx is now available in the frame
|
|
552
|
-
// Other components should get it directly from frames, not from HardwareContext
|
|
553
|
-
// Got a frame, clone it for the user
|
|
554
|
-
return this.frame.clone();
|
|
555
|
-
}
|
|
556
|
-
else if (ret === AVERROR_EAGAIN || ret === AVERROR_EOF) {
|
|
557
|
-
// Need more data or end of stream
|
|
558
|
-
return null;
|
|
559
|
-
}
|
|
560
|
-
else {
|
|
561
|
-
// Error
|
|
562
|
-
FFmpegError.throwIfError(ret, 'Failed to receive frame');
|
|
563
|
-
return null;
|
|
564
|
-
}
|
|
556
|
+
getCodecContext() {
|
|
557
|
+
return !this.isClosed && this.initialized ? this.codecContext : null;
|
|
565
558
|
}
|
|
566
559
|
/**
|
|
567
560
|
* Dispose of decoder.
|
package/dist/api/decoder.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decoder.js","sourceRoot":"","sources":["../../src/api/decoder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"decoder.js","sourceRoot":"","sources":["../../src/api/decoder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAMtF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,MAAM,OAAO,OAAO;IACV,YAAY,CAAe;IAC3B,KAAK,CAAQ;IACb,KAAK,CAAQ;IACb,MAAM,CAAS;IACf,WAAW,GAAG,IAAI,CAAC;IACnB,QAAQ,GAAG,KAAK,CAAC;IACjB,QAAQ,CAA0B;IAE1C;;;;;;;;OAQG;IACH,YAAoB,YAA0B,EAAE,KAAY,EAAE,MAAc,EAAE,QAAiC;QAC7G,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;QACjC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6CG;IACH,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAc,EAAE,UAA0B,EAAE;QAC9D,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;QACxC,CAAC;QAED,8BAA8B;QAC9B,MAAM,KAAK,GAAG,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACzD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CAAC,+BAA+B,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5E,CAAC;QAED,uCAAuC;QACvC,MAAM,YAAY,GAAG,IAAI,YAAY,EAAE,CAAC;QACxC,YAAY,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAElC,mCAAmC;QACnC,MAAM,GAAG,GAAG,YAAY,CAAC,mBAAmB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC9D,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;YACZ,YAAY,CAAC,WAAW,EAAE,CAAC;YAC3B,WAAW,CAAC,YAAY,CAAC,GAAG,EAAE,iCAAiC,CAAC,CAAC;QACnE,CAAC;QAED,uBAAuB;QACvB,YAAY,CAAC,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC;QAE3C,gBAAgB;QAChB,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YAClC,YAAY,CAAC,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;QAC7C,CAAC;QAED,uDAAuD;QACvD,8DAA8D;QAC9D,iDAAiD;QACjD,MAAM,WAAW,GAAG,KAAK,CAAC,4BAA4B,EAAE,CAAC;QACzD,IAAI,WAAW,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACpC,YAAY,CAAC,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC;QAC5D,CAAC;QAED,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAElF,aAAa;QACb,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QACtD,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;YAChB,YAAY,CAAC,WAAW,EAAE,CAAC;YAC3B,WAAW,CAAC,YAAY,CAAC,OAAO,EAAE,sBAAsB,CAAC,CAAC;QAC5D,CAAC;QAED,OAAO,IAAI,OAAO,CAAC,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAC9F,CAAC;IAED;;;;;;;;;;;OAWG;IACH,IAAI,aAAa;QACf,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC;IACxB,CAAC;IAED;;;;;;;;;;;;;;OAcG;IACH,IAAI,oBAAoB;QACtB,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;IAED;;;;;;;;;;;;;OAaG;IACH,UAAU;QACR,OAAO,CAAC,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,4BAA4B,EAAE,CAAC;IACtE,CAAC;IAED;;;;;;;;;;;OAWG;IACH,OAAO;QACL,OAAO,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;IAC5C,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAyCG;IACH,KAAK,CAAC,MAAM,CAAC,MAAc;QACzB,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACvC,CAAC;QAED,yBAAyB;QACzB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QAC3D,IAAI,OAAO,GAAG,CAAC,IAAI,OAAO,KAAK,WAAW,EAAE,CAAC;YAC3C,8CAA8C;YAC9C,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;YACnC,IAAI,KAAK,EAAE,CAAC;gBACV,OAAO,KAAK,CAAC;YACf,CAAC;YAED,kCAAkC;YAClC,IAAI,OAAO,KAAK,cAAc,EAAE,CAAC;gBAC/B,WAAW,CAAC,YAAY,CAAC,OAAO,EAAE,uBAAuB,CAAC,CAAC;YAC7D,CAAC;QACH,CAAC;QAED,uBAAuB;QACvB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACnC,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAmDG;IACH,KAAK,CAAC,CAAC,MAAM,CAAC,OAA8B;QAC1C,kBAAkB;QAClB,IAAI,KAAK,EAAE,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YACnC,IAAI,CAAC;gBACH,sCAAsC;gBACtC,IAAI,MAAM,CAAC,WAAW,KAAK,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;oBAC7C,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;oBACxC,IAAI,KAAK,EAAE,CAAC;wBACV,MAAM,KAAK,CAAC;oBACd,CAAC;gBACH,CAAC;YACH,CAAC;oBAAS,CAAC;gBACT,yCAAyC;gBACzC,MAAM,CAAC,IAAI,EAAE,CAAC;YAChB,CAAC;QACH,CAAC;QAED,kCAAkC;QAClC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QACnB,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;YACvC,IAAI,CAAC,SAAS;gBAAE,MAAM;YACtB,MAAM,SAAS,CAAC;QAClB,CAAC;IACH,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACH,KAAK,CAAC,KAAK;QACT,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,OAAO;QACT,CAAC;QAED,2BAA2B;QAC3B,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACrD,IAAI,GAAG,GAAG,CAAC,IAAI,GAAG,KAAK,WAAW,EAAE,CAAC;YACnC,IAAI,GAAG,KAAK,cAAc,EAAE,CAAC;gBAC3B,WAAW,CAAC,YAAY,CAAC,GAAG,EAAE,yBAAyB,CAAC,CAAC;YAC3D,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,KAAK,CAAC,CAAC,WAAW;QAChB,oBAAoB;QACpB,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QAEnB,IAAI,KAAK,CAAC;QACV,OAAO,CAAC,KAAK,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC;YAC/C,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAmCG;IACH,KAAK,CAAC,OAAO;QACX,4BAA4B;QAC5B,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QAEnB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAE7D,IAAI,GAAG,KAAK,CAAC,EAAE,CAAC;YACd,qCAAqC;YACrC,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QAC5B,CAAC;aAAM,IAAI,GAAG,KAAK,cAAc,IAAI,GAAG,KAAK,WAAW,EAAE,CAAC;YACzD,kCAAkC;YAClC,OAAO,IAAI,CAAC;QACd,CAAC;aAAM,CAAC;YACN,QAAQ;YACR,WAAW,CAAC,YAAY,CAAC,GAAG,EAAE,yBAAyB,CAAC,CAAC;YACzD,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED;;;;;;;;;;;;;;;;;;OAkBG;IACH,KAAK;QACH,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,OAAO;QACT,CAAC;QAED,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QAErB,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAClB,IAAI,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC;QAEhC,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;IAC3B,CAAC;IAED;;;;;;;;;;;OAWG;IACH,SAAS;QACP,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED;;;;;;;;;;;OAWG;IACH,QAAQ;QACN,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,eAAe;QACb,OAAO,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC;IACvE,CAAC;IAED;;;;;;;;;;;;;;;OAeG;IACH,CAAC,MAAM,CAAC,OAAO,CAAC;QACd,IAAI,CAAC,KAAK,EAAE,CAAC;IACf,CAAC;CACF"}
|