webcodecs-node 0.3.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/backends/types.d.ts +6 -3
- package/dist/backends/types.d.ts.map +1 -1
- package/dist/backends/types.js +2 -2
- package/dist/backends/types.js.map +1 -1
- package/dist/{ffmpeg → codec-utils}/audio-codecs.d.ts +13 -12
- package/dist/codec-utils/audio-codecs.d.ts.map +1 -0
- package/dist/{ffmpeg → codec-utils}/audio-codecs.js +29 -11
- package/dist/codec-utils/audio-codecs.js.map +1 -0
- package/dist/{ffmpeg → codec-utils}/formats.d.ts +7 -7
- package/dist/codec-utils/formats.d.ts.map +1 -0
- package/dist/{ffmpeg → codec-utils}/formats.js +7 -7
- package/dist/codec-utils/formats.js.map +1 -0
- package/dist/{ffmpeg → codec-utils}/index.d.ts +3 -3
- package/dist/codec-utils/index.d.ts.map +1 -0
- package/dist/{ffmpeg → codec-utils}/index.js +3 -4
- package/dist/codec-utils/index.js.map +1 -0
- package/dist/{ffmpeg → codec-utils}/types.d.ts +13 -11
- package/dist/codec-utils/types.d.ts.map +1 -0
- package/dist/{ffmpeg → codec-utils}/types.js +3 -1
- package/dist/codec-utils/types.js.map +1 -0
- package/dist/containers/Demuxer.d.ts +114 -0
- package/dist/containers/Demuxer.d.ts.map +1 -0
- package/dist/containers/Demuxer.js +256 -0
- package/dist/containers/Demuxer.js.map +1 -0
- package/dist/containers/Muxer.d.ts +142 -0
- package/dist/containers/Muxer.d.ts.map +1 -0
- package/dist/containers/Muxer.js +295 -0
- package/dist/containers/Muxer.js.map +1 -0
- package/dist/containers/extract.d.ts +25 -0
- package/dist/containers/extract.d.ts.map +1 -0
- package/dist/containers/extract.js +64 -0
- package/dist/containers/extract.js.map +1 -0
- package/dist/containers/index.d.ts +40 -0
- package/dist/containers/index.d.ts.map +1 -0
- package/dist/containers/index.js +41 -0
- package/dist/containers/index.js.map +1 -0
- package/dist/containers/transcode.d.ts +138 -0
- package/dist/containers/transcode.d.ts.map +1 -0
- package/dist/containers/transcode.js +536 -0
- package/dist/containers/transcode.js.map +1 -0
- package/dist/core/AudioData.d.ts +4 -0
- package/dist/core/AudioData.d.ts.map +1 -1
- package/dist/core/AudioData.js +56 -4
- package/dist/core/AudioData.js.map +1 -1
- package/dist/core/EncodedAudioChunk.d.ts +1 -1
- package/dist/core/EncodedAudioChunk.d.ts.map +1 -1
- package/dist/core/EncodedAudioChunk.js +1 -1
- package/dist/core/EncodedAudioChunk.js.map +1 -1
- package/dist/core/EncodedVideoChunk.d.ts.map +1 -1
- package/dist/core/EncodedVideoChunk.js +3 -19
- package/dist/core/EncodedVideoChunk.js.map +1 -1
- package/dist/core/VideoFrame.d.ts +6 -1
- package/dist/core/VideoFrame.d.ts.map +1 -1
- package/dist/core/VideoFrame.js +130 -17
- package/dist/core/VideoFrame.js.map +1 -1
- package/dist/decoders/AudioDecoder.d.ts +8 -0
- package/dist/decoders/AudioDecoder.d.ts.map +1 -1
- package/dist/decoders/AudioDecoder.js +62 -32
- package/dist/decoders/AudioDecoder.js.map +1 -1
- package/dist/decoders/ImageDecoder.d.ts +0 -3
- package/dist/decoders/ImageDecoder.d.ts.map +1 -1
- package/dist/decoders/ImageDecoder.js +13 -225
- package/dist/decoders/ImageDecoder.js.map +1 -1
- package/dist/decoders/VideoDecoder.d.ts +8 -0
- package/dist/decoders/VideoDecoder.d.ts.map +1 -1
- package/dist/decoders/VideoDecoder.js +76 -46
- package/dist/decoders/VideoDecoder.js.map +1 -1
- package/dist/demos/demo-1080p-transcode.d.ts +8 -0
- package/dist/demos/demo-1080p-transcode.d.ts.map +1 -0
- package/dist/demos/demo-1080p-transcode.js +188 -0
- package/dist/demos/demo-1080p-transcode.js.map +1 -0
- package/dist/demos/demo-containers.d.ts +7 -0
- package/dist/demos/demo-containers.d.ts.map +1 -0
- package/dist/demos/demo-containers.js +140 -0
- package/dist/demos/demo-containers.js.map +1 -0
- package/dist/demos/demo-four-corners.js +4 -4
- package/dist/demos/demo-four-corners.js.map +1 -1
- package/dist/demos/demo-hwaccel.js +1 -1
- package/dist/demos/demo-hwaccel.js.map +1 -1
- package/dist/demos/demo-samples.js +4 -4
- package/dist/demos/demo-samples.js.map +1 -1
- package/dist/demos/demo-streaming.js +6 -6
- package/dist/demos/demo-streaming.js.map +1 -1
- package/dist/encoders/AudioEncoder.d.ts +8 -0
- package/dist/encoders/AudioEncoder.d.ts.map +1 -1
- package/dist/encoders/AudioEncoder.js +68 -26
- package/dist/encoders/AudioEncoder.js.map +1 -1
- package/dist/encoders/VideoEncoder.d.ts +8 -0
- package/dist/encoders/VideoEncoder.d.ts.map +1 -1
- package/dist/encoders/VideoEncoder.js +64 -13
- package/dist/encoders/VideoEncoder.js.map +1 -1
- package/dist/formats/conversions/batch-converter.d.ts +61 -0
- package/dist/formats/conversions/batch-converter.d.ts.map +1 -0
- package/dist/formats/conversions/batch-converter.js +274 -0
- package/dist/formats/conversions/batch-converter.js.map +1 -0
- package/dist/formats/conversions/frame-converter.d.ts.map +1 -1
- package/dist/formats/conversions/frame-converter.js +17 -10
- package/dist/formats/conversions/frame-converter.js.map +1 -1
- package/dist/formats/conversions/index.d.ts +1 -0
- package/dist/formats/conversions/index.d.ts.map +1 -1
- package/dist/formats/conversions/index.js +2 -0
- package/dist/formats/conversions/index.js.map +1 -1
- package/dist/hardware/decoder-args.d.ts +2 -7
- package/dist/hardware/decoder-args.d.ts.map +1 -1
- package/dist/hardware/decoder-args.js +2 -32
- package/dist/hardware/decoder-args.js.map +1 -1
- package/dist/hardware/encoder-args.d.ts +2 -11
- package/dist/hardware/encoder-args.d.ts.map +1 -1
- package/dist/hardware/encoder-args.js +2 -71
- package/dist/hardware/encoder-args.js.map +1 -1
- package/dist/hardware/index.d.ts +2 -2
- package/dist/hardware/index.d.ts.map +1 -1
- package/dist/hardware/index.js +2 -2
- package/dist/hardware/index.js.map +1 -1
- package/dist/index.d.ts +5 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -6
- package/dist/index.js.map +1 -1
- package/dist/node-av/NodeAvAudioDecoder.d.ts +2 -2
- package/dist/node-av/NodeAvAudioDecoder.d.ts.map +1 -1
- package/dist/node-av/NodeAvAudioDecoder.js +63 -56
- package/dist/node-av/NodeAvAudioDecoder.js.map +1 -1
- package/dist/node-av/NodeAvAudioEncoder.d.ts +6 -0
- package/dist/node-av/NodeAvAudioEncoder.d.ts.map +1 -1
- package/dist/node-av/NodeAvAudioEncoder.js +166 -45
- package/dist/node-av/NodeAvAudioEncoder.js.map +1 -1
- package/dist/node-av/NodeAvImageDecoder.d.ts +28 -9
- package/dist/node-av/NodeAvImageDecoder.d.ts.map +1 -1
- package/dist/node-av/NodeAvImageDecoder.js +156 -37
- package/dist/node-av/NodeAvImageDecoder.js.map +1 -1
- package/dist/node-av/NodeAvVideoDecoder.d.ts +1 -1
- package/dist/node-av/NodeAvVideoDecoder.d.ts.map +1 -1
- package/dist/node-av/NodeAvVideoDecoder.js +20 -16
- package/dist/node-av/NodeAvVideoDecoder.js.map +1 -1
- package/dist/node-av/NodeAvVideoEncoder.d.ts +12 -0
- package/dist/node-av/NodeAvVideoEncoder.d.ts.map +1 -1
- package/dist/node-av/NodeAvVideoEncoder.js +175 -63
- package/dist/node-av/NodeAvVideoEncoder.js.map +1 -1
- package/dist/polyfill.d.ts.map +1 -1
- package/dist/polyfill.js +11 -9
- package/dist/polyfill.js.map +1 -1
- package/dist/utils/aac.d.ts.map +1 -1
- package/dist/utils/aac.js +6 -0
- package/dist/utils/aac.js.map +1 -1
- package/dist/utils/buffer-pool.d.ts +109 -0
- package/dist/utils/buffer-pool.d.ts.map +1 -0
- package/dist/utils/buffer-pool.js +278 -0
- package/dist/utils/buffer-pool.js.map +1 -0
- package/dist/utils/codec-cache.d.ts +65 -0
- package/dist/utils/codec-cache.d.ts.map +1 -0
- package/dist/utils/codec-cache.js +116 -0
- package/dist/utils/codec-cache.js.map +1 -0
- package/dist/utils/errors.d.ts +62 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +84 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/hardware-pool.d.ts +88 -0
- package/dist/utils/hardware-pool.d.ts.map +1 -0
- package/dist/utils/hardware-pool.js +266 -0
- package/dist/utils/hardware-pool.js.map +1 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +10 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/timeout.d.ts +44 -0
- package/dist/utils/timeout.d.ts.map +1 -0
- package/dist/utils/timeout.js +73 -0
- package/dist/utils/timeout.js.map +1 -0
- package/dist/utils/type-guards.d.ts +11 -1
- package/dist/utils/type-guards.d.ts.map +1 -1
- package/dist/utils/type-guards.js.map +1 -1
- package/package.json +13 -35
- package/dist/AudioData.d.ts +0 -6
- package/dist/AudioData.d.ts.map +0 -1
- package/dist/AudioData.js +0 -6
- package/dist/AudioData.js.map +0 -1
- package/dist/AudioDecoder.d.ts +0 -6
- package/dist/AudioDecoder.d.ts.map +0 -1
- package/dist/AudioDecoder.js +0 -6
- package/dist/AudioDecoder.js.map +0 -1
- package/dist/AudioEncoder.d.ts +0 -6
- package/dist/AudioEncoder.d.ts.map +0 -1
- package/dist/AudioEncoder.js +0 -6
- package/dist/AudioEncoder.js.map +0 -1
- package/dist/EncodedAudioChunk.d.ts +0 -6
- package/dist/EncodedAudioChunk.d.ts.map +0 -1
- package/dist/EncodedAudioChunk.js +0 -6
- package/dist/EncodedAudioChunk.js.map +0 -1
- package/dist/EncodedVideoChunk.d.ts +0 -6
- package/dist/EncodedVideoChunk.d.ts.map +0 -1
- package/dist/EncodedVideoChunk.js +0 -6
- package/dist/EncodedVideoChunk.js.map +0 -1
- package/dist/FFmpegProcess.d.ts +0 -6
- package/dist/FFmpegProcess.d.ts.map +0 -1
- package/dist/FFmpegProcess.js +0 -6
- package/dist/FFmpegProcess.js.map +0 -1
- package/dist/HardwareAcceleration.d.ts +0 -6
- package/dist/HardwareAcceleration.d.ts.map +0 -1
- package/dist/HardwareAcceleration.js +0 -6
- package/dist/HardwareAcceleration.js.map +0 -1
- package/dist/ImageDecoder.d.ts +0 -6
- package/dist/ImageDecoder.d.ts.map +0 -1
- package/dist/ImageDecoder.js +0 -6
- package/dist/ImageDecoder.js.map +0 -1
- package/dist/Logger.d.ts +0 -6
- package/dist/Logger.d.ts.map +0 -1
- package/dist/Logger.js +0 -6
- package/dist/Logger.js.map +0 -1
- package/dist/MediaCapabilities.d.ts +0 -9
- package/dist/MediaCapabilities.d.ts.map +0 -1
- package/dist/MediaCapabilities.js +0 -8
- package/dist/MediaCapabilities.js.map +0 -1
- package/dist/VideoDecoder.d.ts +0 -6
- package/dist/VideoDecoder.d.ts.map +0 -1
- package/dist/VideoDecoder.js +0 -6
- package/dist/VideoDecoder.js.map +0 -1
- package/dist/VideoEncoder.d.ts +0 -6
- package/dist/VideoEncoder.d.ts.map +0 -1
- package/dist/VideoEncoder.js +0 -6
- package/dist/VideoEncoder.js.map +0 -1
- package/dist/VideoFrame.d.ts +0 -10
- package/dist/VideoFrame.d.ts.map +0 -1
- package/dist/VideoFrame.js +0 -9
- package/dist/VideoFrame.js.map +0 -1
- package/dist/__tests__/AudioData.test.d.ts +0 -5
- package/dist/__tests__/AudioData.test.d.ts.map +0 -1
- package/dist/__tests__/AudioData.test.js +0 -179
- package/dist/__tests__/AudioData.test.js.map +0 -1
- package/dist/__tests__/AudioDecoder.test.d.ts +0 -5
- package/dist/__tests__/AudioDecoder.test.d.ts.map +0 -1
- package/dist/__tests__/AudioDecoder.test.js +0 -733
- package/dist/__tests__/AudioDecoder.test.js.map +0 -1
- package/dist/__tests__/AudioEncoder.test.d.ts +0 -5
- package/dist/__tests__/AudioEncoder.test.d.ts.map +0 -1
- package/dist/__tests__/AudioEncoder.test.js +0 -247
- package/dist/__tests__/AudioEncoder.test.js.map +0 -1
- package/dist/__tests__/EncodedChunks.test.d.ts +0 -5
- package/dist/__tests__/EncodedChunks.test.d.ts.map +0 -1
- package/dist/__tests__/EncodedChunks.test.js +0 -99
- package/dist/__tests__/EncodedChunks.test.js.map +0 -1
- package/dist/__tests__/HardwareAcceleration.test.d.ts +0 -5
- package/dist/__tests__/HardwareAcceleration.test.d.ts.map +0 -1
- package/dist/__tests__/HardwareAcceleration.test.js +0 -84
- package/dist/__tests__/HardwareAcceleration.test.js.map +0 -1
- package/dist/__tests__/ImageDecoder.test.d.ts +0 -5
- package/dist/__tests__/ImageDecoder.test.d.ts.map +0 -1
- package/dist/__tests__/ImageDecoder.test.js +0 -587
- package/dist/__tests__/ImageDecoder.test.js.map +0 -1
- package/dist/__tests__/ImageDecoder.wpt.test.d.ts +0 -8
- package/dist/__tests__/ImageDecoder.wpt.test.d.ts.map +0 -1
- package/dist/__tests__/ImageDecoder.wpt.test.js +0 -135
- package/dist/__tests__/ImageDecoder.wpt.test.js.map +0 -1
- package/dist/__tests__/MediaCapabilities.test.d.ts +0 -5
- package/dist/__tests__/MediaCapabilities.test.d.ts.map +0 -1
- package/dist/__tests__/MediaCapabilities.test.js +0 -346
- package/dist/__tests__/MediaCapabilities.test.js.map +0 -1
- package/dist/__tests__/NodeAvDecoder.test.d.ts +0 -2
- package/dist/__tests__/NodeAvDecoder.test.d.ts.map +0 -1
- package/dist/__tests__/NodeAvDecoder.test.js +0 -199
- package/dist/__tests__/NodeAvDecoder.test.js.map +0 -1
- package/dist/__tests__/NodeAvEncoder.test.d.ts +0 -2
- package/dist/__tests__/NodeAvEncoder.test.d.ts.map +0 -1
- package/dist/__tests__/NodeAvEncoder.test.js +0 -176
- package/dist/__tests__/NodeAvEncoder.test.js.map +0 -1
- package/dist/__tests__/VideoDecoder.test.d.ts +0 -5
- package/dist/__tests__/VideoDecoder.test.d.ts.map +0 -1
- package/dist/__tests__/VideoDecoder.test.js +0 -675
- package/dist/__tests__/VideoDecoder.test.js.map +0 -1
- package/dist/__tests__/VideoEncoder.test.d.ts +0 -5
- package/dist/__tests__/VideoEncoder.test.d.ts.map +0 -1
- package/dist/__tests__/VideoEncoder.test.js +0 -468
- package/dist/__tests__/VideoEncoder.test.js.map +0 -1
- package/dist/__tests__/VideoFrame.test.d.ts +0 -5
- package/dist/__tests__/VideoFrame.test.d.ts.map +0 -1
- package/dist/__tests__/VideoFrame.test.js +0 -243
- package/dist/__tests__/VideoFrame.test.js.map +0 -1
- package/dist/__tests__/aac-utils.test.d.ts +0 -2
- package/dist/__tests__/aac-utils.test.d.ts.map +0 -1
- package/dist/__tests__/aac-utils.test.js +0 -37
- package/dist/__tests__/aac-utils.test.js.map +0 -1
- package/dist/__tests__/avc-utils.test.d.ts +0 -2
- package/dist/__tests__/avc-utils.test.d.ts.map +0 -1
- package/dist/__tests__/avc-utils.test.js +0 -63
- package/dist/__tests__/avc-utils.test.js.map +0 -1
- package/dist/__tests__/hevc-utils.test.d.ts +0 -2
- package/dist/__tests__/hevc-utils.test.d.ts.map +0 -1
- package/dist/__tests__/hevc-utils.test.js +0 -78
- package/dist/__tests__/hevc-utils.test.js.map +0 -1
- package/dist/demos/demo-conversion.d.ts +0 -13
- package/dist/demos/demo-conversion.d.ts.map +0 -1
- package/dist/demos/demo-conversion.js +0 -301
- package/dist/demos/demo-conversion.js.map +0 -1
- package/dist/demos/demo-hwaccel-conversion.d.ts +0 -8
- package/dist/demos/demo-hwaccel-conversion.d.ts.map +0 -1
- package/dist/demos/demo-hwaccel-conversion.js +0 -161
- package/dist/demos/demo-hwaccel-conversion.js.map +0 -1
- package/dist/demos/demo-mediabunny.d.ts +0 -7
- package/dist/demos/demo-mediabunny.d.ts.map +0 -1
- package/dist/demos/demo-mediabunny.js +0 -78
- package/dist/demos/demo-mediabunny.js.map +0 -1
- package/dist/ffmpeg/FFmpegProcess.d.ts +0 -111
- package/dist/ffmpeg/FFmpegProcess.d.ts.map +0 -1
- package/dist/ffmpeg/FFmpegProcess.js +0 -543
- package/dist/ffmpeg/FFmpegProcess.js.map +0 -1
- package/dist/ffmpeg/audio-codecs.d.ts.map +0 -1
- package/dist/ffmpeg/audio-codecs.js.map +0 -1
- package/dist/ffmpeg/formats.d.ts.map +0 -1
- package/dist/ffmpeg/formats.js.map +0 -1
- package/dist/ffmpeg/index.d.ts.map +0 -1
- package/dist/ffmpeg/index.js.map +0 -1
- package/dist/ffmpeg/parsers/annexb.d.ts +0 -88
- package/dist/ffmpeg/parsers/annexb.d.ts.map +0 -1
- package/dist/ffmpeg/parsers/annexb.js +0 -201
- package/dist/ffmpeg/parsers/annexb.js.map +0 -1
- package/dist/ffmpeg/parsers/index.d.ts +0 -6
- package/dist/ffmpeg/parsers/index.d.ts.map +0 -1
- package/dist/ffmpeg/parsers/index.js +0 -8
- package/dist/ffmpeg/parsers/index.js.map +0 -1
- package/dist/ffmpeg/parsers/ivf.d.ts +0 -54
- package/dist/ffmpeg/parsers/ivf.d.ts.map +0 -1
- package/dist/ffmpeg/parsers/ivf.js +0 -109
- package/dist/ffmpeg/parsers/ivf.js.map +0 -1
- package/dist/ffmpeg/types.d.ts.map +0 -1
- package/dist/ffmpeg/types.js.map +0 -1
- package/dist/mediabunny/FFmpegAudioDecoder.d.ts +0 -23
- package/dist/mediabunny/FFmpegAudioDecoder.d.ts.map +0 -1
- package/dist/mediabunny/FFmpegAudioDecoder.js +0 -129
- package/dist/mediabunny/FFmpegAudioDecoder.js.map +0 -1
- package/dist/mediabunny/FFmpegAudioEncoder.d.ts +0 -43
- package/dist/mediabunny/FFmpegAudioEncoder.d.ts.map +0 -1
- package/dist/mediabunny/FFmpegAudioEncoder.js +0 -220
- package/dist/mediabunny/FFmpegAudioEncoder.js.map +0 -1
- package/dist/mediabunny/FFmpegVideoDecoder.d.ts +0 -24
- package/dist/mediabunny/FFmpegVideoDecoder.d.ts.map +0 -1
- package/dist/mediabunny/FFmpegVideoDecoder.js +0 -125
- package/dist/mediabunny/FFmpegVideoDecoder.js.map +0 -1
- package/dist/mediabunny/FFmpegVideoEncoder.d.ts +0 -48
- package/dist/mediabunny/FFmpegVideoEncoder.d.ts.map +0 -1
- package/dist/mediabunny/FFmpegVideoEncoder.js +0 -263
- package/dist/mediabunny/FFmpegVideoEncoder.js.map +0 -1
- package/dist/mediabunny/index.d.ts +0 -21
- package/dist/mediabunny/index.d.ts.map +0 -1
- package/dist/mediabunny/index.js +0 -33
- package/dist/mediabunny/index.js.map +0 -1
- package/dist/types.d.ts +0 -6
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -6
- package/dist/types.js.map +0 -1
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* FFmpegProcess - Manages FFmpeg child process for encoding/decoding
|
|
3
|
-
*/
|
|
4
|
-
import { EventEmitter } from 'events';
|
|
5
|
-
import { type FFmpegConfig, type FFmpegInputConfig, type FFmpegOutputConfig, type DecoderConfig, type EncoderConfig } from './types.js';
|
|
6
|
-
export type { FFmpegConfig, FFmpegInputConfig, FFmpegOutputConfig };
|
|
7
|
-
export declare class FFmpegProcess extends EventEmitter {
|
|
8
|
-
private ffmpegPath;
|
|
9
|
-
private process;
|
|
10
|
-
private _isRunning;
|
|
11
|
-
private _isShuttingDown;
|
|
12
|
-
private outputBuffer;
|
|
13
|
-
private frameSize;
|
|
14
|
-
private accumulatedData;
|
|
15
|
-
private _useIvf;
|
|
16
|
-
private _useAnnexB;
|
|
17
|
-
private _codec;
|
|
18
|
-
private _ivfState;
|
|
19
|
-
private _annexBState;
|
|
20
|
-
constructor(ffmpegPath?: string);
|
|
21
|
-
get isRunning(): boolean;
|
|
22
|
-
/**
|
|
23
|
-
* Check if the process is healthy and can accept data
|
|
24
|
-
*/
|
|
25
|
-
get isHealthy(): boolean;
|
|
26
|
-
/**
|
|
27
|
-
* Start FFmpeg process for decoding (encoded data -> raw frames)
|
|
28
|
-
*/
|
|
29
|
-
startDecoder(config: DecoderConfig): void;
|
|
30
|
-
/**
|
|
31
|
-
* Start FFmpeg process for encoding (raw frames -> encoded data)
|
|
32
|
-
*/
|
|
33
|
-
startEncoder(config: EncoderConfig): void;
|
|
34
|
-
/**
|
|
35
|
-
* Check if a codec supports alpha channel
|
|
36
|
-
*/
|
|
37
|
-
private _codecSupportsAlpha;
|
|
38
|
-
/**
|
|
39
|
-
* Check if a pixel format has alpha channel
|
|
40
|
-
*/
|
|
41
|
-
private _formatHasAlpha;
|
|
42
|
-
/**
|
|
43
|
-
* Add codec-specific FFmpeg options
|
|
44
|
-
*/
|
|
45
|
-
private _addCodecOptions;
|
|
46
|
-
/**
|
|
47
|
-
* Add bitrate control options based on bitrateMode
|
|
48
|
-
*/
|
|
49
|
-
private _addBitrateOptions;
|
|
50
|
-
private _startProcess;
|
|
51
|
-
/**
|
|
52
|
-
* Handle stdout data from FFmpeg
|
|
53
|
-
*/
|
|
54
|
-
private _handleStdoutData;
|
|
55
|
-
/**
|
|
56
|
-
* Parse IVF output and emit encoded frames
|
|
57
|
-
*/
|
|
58
|
-
private _parseIvfOutput;
|
|
59
|
-
/**
|
|
60
|
-
* Parse Annex B output and emit encoded frames
|
|
61
|
-
*/
|
|
62
|
-
private _parseAnnexBOutput;
|
|
63
|
-
/**
|
|
64
|
-
* Handle process close event
|
|
65
|
-
*/
|
|
66
|
-
private _handleProcessClose;
|
|
67
|
-
/**
|
|
68
|
-
* Write data to FFmpeg stdin
|
|
69
|
-
* @returns true if write was queued successfully, false if process is not healthy
|
|
70
|
-
*/
|
|
71
|
-
write(data: Buffer | Uint8Array): boolean;
|
|
72
|
-
/**
|
|
73
|
-
* Signal end of input data
|
|
74
|
-
*/
|
|
75
|
-
end(): void;
|
|
76
|
-
/**
|
|
77
|
-
* Gracefully shutdown the FFmpeg process with timeout
|
|
78
|
-
*/
|
|
79
|
-
shutdown(timeout?: number): Promise<void>;
|
|
80
|
-
/**
|
|
81
|
-
* Kill the FFmpeg process immediately
|
|
82
|
-
*/
|
|
83
|
-
kill(): void;
|
|
84
|
-
/**
|
|
85
|
-
* Clean up internal state
|
|
86
|
-
*/
|
|
87
|
-
private _cleanup;
|
|
88
|
-
/**
|
|
89
|
-
* Map WebCodecs codec string to FFmpeg codec
|
|
90
|
-
*/
|
|
91
|
-
private _getFFmpegCodec;
|
|
92
|
-
/**
|
|
93
|
-
* Map WebCodecs codec to container format
|
|
94
|
-
*/
|
|
95
|
-
private _getContainerFormat;
|
|
96
|
-
/**
|
|
97
|
-
* Map pixel format names
|
|
98
|
-
* @deprecated Use pixelFormatToFFmpeg from './formats.js' instead
|
|
99
|
-
*/
|
|
100
|
-
static pixelFormatToFFmpeg(format: string): string;
|
|
101
|
-
/**
|
|
102
|
-
* @deprecated Use ffmpegToPixelFormat from './formats.js' instead
|
|
103
|
-
*/
|
|
104
|
-
static ffmpegToPixelFormat(format: string): string;
|
|
105
|
-
/**
|
|
106
|
-
* Calculate frame size in bytes
|
|
107
|
-
* @deprecated Use calculateFrameSize from './formats.js' instead
|
|
108
|
-
*/
|
|
109
|
-
static calculateFrameSize(format: string, width: number, height: number): number;
|
|
110
|
-
}
|
|
111
|
-
//# sourceMappingURL=FFmpegProcess.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"FFmpegProcess.d.ts","sourceRoot":"","sources":["../../src/ffmpeg/FFmpegProcess.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EAEvB,KAAK,aAAa,EAClB,KAAK,aAAa,EAInB,MAAM,YAAY,CAAC;AAoBpB,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,CAAC;AAEpE,qBAAa,aAAc,SAAQ,YAAY;IAejC,OAAO,CAAC,UAAU;IAd9B,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,YAAY,CAAgB;IACpC,OAAO,CAAC,SAAS,CAAa;IAC9B,OAAO,CAAC,eAAe,CAA2B;IAClD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,MAAM,CAAM;IAGpB,OAAO,CAAC,SAAS,CAA+B;IAChD,OAAO,CAAC,YAAY,CAAkC;gBAElC,UAAU,GAAE,MAAiB;IAIjD,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED;;OAEG;IACH,IAAI,SAAS,IAAI,OAAO,CAKvB;IAED;;OAEG;IACH,YAAY,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI;IA6BzC;;OAEG;IACH,YAAY,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI;IAqEzC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAK3B;;OAEG;IACH,OAAO,CAAC,eAAe;IAKvB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IA2DxB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAkE1B,OAAO,CAAC,aAAa;IA6BrB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAqBzB;;OAEG;IACH,OAAO,CAAC,eAAe;IAgBvB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAY1B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAmB3B;;;OAGG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,OAAO;IAYzC;;OAEG;IACH,GAAG,IAAI,IAAI;IAUX;;OAEG;IACG,QAAQ,CAAC,OAAO,GAAE,MAAiC,GAAG,OAAO,CAAC,IAAI,CAAC;IAyCzE;;OAEG;IACH,IAAI,IAAI,IAAI;IAmBZ;;OAEG;IACH,OAAO,CAAC,QAAQ;IAUhB;;OAEG;IACH,OAAO,CAAC,eAAe;IAkBvB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAkB3B;;;OAGG;IACH,MAAM,CAAC,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAelD;;OAEG;IACH,MAAM,CAAC,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAelD;;;OAGG;IACH,MAAM,CAAC,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM;CAGjF"}
|
|
@@ -1,543 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* FFmpegProcess - Manages FFmpeg child process for encoding/decoding
|
|
3
|
-
*/
|
|
4
|
-
import { spawn } from 'child_process';
|
|
5
|
-
import { EventEmitter } from 'events';
|
|
6
|
-
import { DEFAULT_SHUTDOWN_TIMEOUT, } from './types.js';
|
|
7
|
-
import { createIvfParserState, parseIvfFrames, isVP9KeyFrame, } from './parsers/ivf.js';
|
|
8
|
-
import { createAnnexBParserState, parseAnnexBFrames, flushAnnexBParser, } from './parsers/annexb.js';
|
|
9
|
-
import { calculateFrameSize } from './formats.js';
|
|
10
|
-
export class FFmpegProcess extends EventEmitter {
|
|
11
|
-
ffmpegPath;
|
|
12
|
-
process = null;
|
|
13
|
-
_isRunning = false;
|
|
14
|
-
_isShuttingDown = false;
|
|
15
|
-
outputBuffer = [];
|
|
16
|
-
frameSize = 0;
|
|
17
|
-
accumulatedData = Buffer.alloc(0);
|
|
18
|
-
_useIvf = false;
|
|
19
|
-
_useAnnexB = false;
|
|
20
|
-
_codec = '';
|
|
21
|
-
// Parser states
|
|
22
|
-
_ivfState = null;
|
|
23
|
-
_annexBState = null;
|
|
24
|
-
constructor(ffmpegPath = 'ffmpeg') {
|
|
25
|
-
super();
|
|
26
|
-
this.ffmpegPath = ffmpegPath;
|
|
27
|
-
}
|
|
28
|
-
get isRunning() {
|
|
29
|
-
return this._isRunning && !this._isShuttingDown;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Check if the process is healthy and can accept data
|
|
33
|
-
*/
|
|
34
|
-
get isHealthy() {
|
|
35
|
-
return this._isRunning &&
|
|
36
|
-
!this._isShuttingDown &&
|
|
37
|
-
this.process !== null &&
|
|
38
|
-
this.process.stdin?.writable === true;
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Start FFmpeg process for decoding (encoded data -> raw frames)
|
|
42
|
-
*/
|
|
43
|
-
startDecoder(config) {
|
|
44
|
-
const outputFormat = config.outputPixelFormat || 'rgba';
|
|
45
|
-
// Calculate frame size based on output pixel format
|
|
46
|
-
this.frameSize = calculateFrameSize(outputFormat, config.width, config.height);
|
|
47
|
-
const args = [
|
|
48
|
-
'-hide_banner',
|
|
49
|
-
'-loglevel', 'error',
|
|
50
|
-
...(config.hardwareDecoderArgs ?? []),
|
|
51
|
-
// Input from pipe
|
|
52
|
-
'-f', this._getContainerFormat(config.codec),
|
|
53
|
-
'-i', 'pipe:0',
|
|
54
|
-
];
|
|
55
|
-
if (config.hardwareDownloadFilter) {
|
|
56
|
-
args.push('-vf', config.hardwareDownloadFilter);
|
|
57
|
-
}
|
|
58
|
-
args.push('-vsync', 'passthrough', // Don't duplicate or drop frames
|
|
59
|
-
'-f', 'rawvideo', '-pix_fmt', outputFormat, 'pipe:1');
|
|
60
|
-
this._startProcess(args);
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Start FFmpeg process for encoding (raw frames -> encoded data)
|
|
64
|
-
*/
|
|
65
|
-
startEncoder(config) {
|
|
66
|
-
const inputFormat = config.inputPixelFormat || 'rgba';
|
|
67
|
-
const framerate = config.framerate || 30;
|
|
68
|
-
const containerFormat = this._getContainerFormat(config.codec);
|
|
69
|
-
const codecBase = config.codec.split('.')[0].toLowerCase();
|
|
70
|
-
const isRealtime = config.latencyMode === 'realtime';
|
|
71
|
-
const alphaOption = config.alpha || 'discard';
|
|
72
|
-
// Track codec for frame parsing
|
|
73
|
-
this._codec = codecBase;
|
|
74
|
-
// Use IVF for VP8/VP9/AV1 - it has per-frame headers we can parse
|
|
75
|
-
this._useIvf = containerFormat === 'ivf';
|
|
76
|
-
// Use Annex B parsing for H.264/HEVC
|
|
77
|
-
this._useAnnexB = containerFormat === 'h264' || containerFormat === 'hevc';
|
|
78
|
-
// Check if codec supports alpha
|
|
79
|
-
const codecSupportsAlpha = this._codecSupportsAlpha(codecBase);
|
|
80
|
-
const inputHasAlpha = this._formatHasAlpha(inputFormat);
|
|
81
|
-
const keepAlpha = alphaOption === 'keep' && codecSupportsAlpha && inputHasAlpha;
|
|
82
|
-
// Initialize parser state
|
|
83
|
-
if (this._useIvf) {
|
|
84
|
-
this._ivfState = createIvfParserState();
|
|
85
|
-
}
|
|
86
|
-
else if (this._useAnnexB) {
|
|
87
|
-
const annexBCodec = (codecBase === 'hev1' || codecBase === 'hvc1') ? 'hevc' : 'h264';
|
|
88
|
-
this._annexBState = createAnnexBParserState(annexBCodec);
|
|
89
|
-
}
|
|
90
|
-
const args = [
|
|
91
|
-
'-hide_banner',
|
|
92
|
-
'-loglevel', 'error',
|
|
93
|
-
// Input raw video from pipe
|
|
94
|
-
'-f', 'rawvideo',
|
|
95
|
-
'-pix_fmt', inputFormat,
|
|
96
|
-
'-s', `${config.width}x${config.height}`,
|
|
97
|
-
'-r', String(framerate),
|
|
98
|
-
'-i', 'pipe:0',
|
|
99
|
-
];
|
|
100
|
-
// Handle alpha channel
|
|
101
|
-
if (inputHasAlpha && !keepAlpha) {
|
|
102
|
-
// Strip alpha channel using video filter
|
|
103
|
-
args.push('-vf', 'format=yuv420p');
|
|
104
|
-
}
|
|
105
|
-
else if (keepAlpha) {
|
|
106
|
-
// Keep alpha - use yuva420p for encoding
|
|
107
|
-
args.push('-pix_fmt', 'yuva420p');
|
|
108
|
-
}
|
|
109
|
-
const hasHardwareArgs = Array.isArray(config.hardwareEncoderArgs) && config.hardwareEncoderArgs.length > 0;
|
|
110
|
-
if (hasHardwareArgs) {
|
|
111
|
-
args.push(...(config.hardwareEncoderArgs ?? []));
|
|
112
|
-
}
|
|
113
|
-
else {
|
|
114
|
-
// Output encoded video
|
|
115
|
-
args.push('-c:v', this._getFFmpegCodec(config.codec));
|
|
116
|
-
// Codec-specific options based on latency mode and bitrate mode
|
|
117
|
-
const bitrateMode = config.bitrateMode || 'variable';
|
|
118
|
-
this._addCodecOptions(args, codecBase, isRealtime, bitrateMode, config.bitrate);
|
|
119
|
-
}
|
|
120
|
-
// Output format
|
|
121
|
-
args.push('-f', containerFormat);
|
|
122
|
-
args.push('pipe:1');
|
|
123
|
-
this._startProcess(args);
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* Check if a codec supports alpha channel
|
|
127
|
-
*/
|
|
128
|
-
_codecSupportsAlpha(codecBase) {
|
|
129
|
-
// VP9 and AV1 support alpha via yuva420p
|
|
130
|
-
return ['vp9', 'vp09', 'av01', 'av1'].includes(codecBase);
|
|
131
|
-
}
|
|
132
|
-
/**
|
|
133
|
-
* Check if a pixel format has alpha channel
|
|
134
|
-
*/
|
|
135
|
-
_formatHasAlpha(format) {
|
|
136
|
-
const alphaFormats = ['rgba', 'bgra', 'yuva420p', 'argb', 'abgr'];
|
|
137
|
-
return alphaFormats.includes(format.toLowerCase());
|
|
138
|
-
}
|
|
139
|
-
/**
|
|
140
|
-
* Add codec-specific FFmpeg options
|
|
141
|
-
*/
|
|
142
|
-
_addCodecOptions(args, codecBase, isRealtime, bitrateMode, bitrate) {
|
|
143
|
-
// Add bitrate control based on mode
|
|
144
|
-
this._addBitrateOptions(args, codecBase, bitrateMode, bitrate);
|
|
145
|
-
// Add latency/quality options per codec
|
|
146
|
-
if (codecBase === 'avc1' || codecBase === 'avc3') {
|
|
147
|
-
if (isRealtime) {
|
|
148
|
-
args.push('-preset', 'ultrafast');
|
|
149
|
-
args.push('-tune', 'zerolatency');
|
|
150
|
-
args.push('-x264-params', 'aud=1:bframes=0:rc-lookahead=0:threads=1:sliced-threads=0:sync-lookahead=0:intra-refresh=1');
|
|
151
|
-
}
|
|
152
|
-
else {
|
|
153
|
-
args.push('-preset', 'medium');
|
|
154
|
-
args.push('-x264-params', 'aud=1:bframes=2:rc-lookahead=20');
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
else if (codecBase === 'hev1' || codecBase === 'hvc1') {
|
|
158
|
-
if (isRealtime) {
|
|
159
|
-
args.push('-preset', 'ultrafast');
|
|
160
|
-
args.push('-x265-params', 'aud=1:bframes=0:rc-lookahead=0');
|
|
161
|
-
}
|
|
162
|
-
else {
|
|
163
|
-
args.push('-preset', 'medium');
|
|
164
|
-
args.push('-x265-params', 'aud=1:bframes=2:rc-lookahead=20');
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
else if (codecBase === 'vp8') {
|
|
168
|
-
if (isRealtime) {
|
|
169
|
-
args.push('-deadline', 'realtime');
|
|
170
|
-
args.push('-cpu-used', '8');
|
|
171
|
-
args.push('-lag-in-frames', '0');
|
|
172
|
-
}
|
|
173
|
-
else {
|
|
174
|
-
args.push('-deadline', 'good');
|
|
175
|
-
args.push('-cpu-used', '2');
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
else if (codecBase === 'vp09' || codecBase === 'vp9') {
|
|
179
|
-
if (isRealtime) {
|
|
180
|
-
args.push('-deadline', 'realtime');
|
|
181
|
-
args.push('-cpu-used', '8');
|
|
182
|
-
args.push('-lag-in-frames', '0');
|
|
183
|
-
args.push('-row-mt', '1');
|
|
184
|
-
}
|
|
185
|
-
else {
|
|
186
|
-
args.push('-deadline', 'good');
|
|
187
|
-
args.push('-cpu-used', '2');
|
|
188
|
-
args.push('-lag-in-frames', '25');
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
else if (codecBase === 'av01' || codecBase === 'av1') {
|
|
192
|
-
if (isRealtime) {
|
|
193
|
-
args.push('-cpu-used', '8');
|
|
194
|
-
args.push('-usage', 'realtime');
|
|
195
|
-
}
|
|
196
|
-
else {
|
|
197
|
-
args.push('-cpu-used', '4');
|
|
198
|
-
args.push('-usage', 'good');
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
/**
|
|
203
|
-
* Add bitrate control options based on bitrateMode
|
|
204
|
-
*/
|
|
205
|
-
_addBitrateOptions(args, codecBase, bitrateMode, bitrate) {
|
|
206
|
-
const isH264 = codecBase === 'avc1' || codecBase === 'avc3';
|
|
207
|
-
const isHEVC = codecBase === 'hev1' || codecBase === 'hvc1';
|
|
208
|
-
const isVP = codecBase === 'vp8' || codecBase === 'vp9' || codecBase === 'vp09';
|
|
209
|
-
const isAV1 = codecBase === 'av01' || codecBase === 'av1';
|
|
210
|
-
switch (bitrateMode) {
|
|
211
|
-
case 'constant':
|
|
212
|
-
// CBR - Constant Bitrate
|
|
213
|
-
if (bitrate) {
|
|
214
|
-
args.push('-b:v', String(bitrate));
|
|
215
|
-
if (isH264 || isHEVC) {
|
|
216
|
-
// Force CBR by setting maxrate and bufsize
|
|
217
|
-
args.push('-maxrate', String(bitrate));
|
|
218
|
-
args.push('-bufsize', String(bitrate * 2));
|
|
219
|
-
}
|
|
220
|
-
else if (isVP) {
|
|
221
|
-
// VP8/VP9 CBR
|
|
222
|
-
args.push('-minrate', String(bitrate));
|
|
223
|
-
args.push('-maxrate', String(bitrate));
|
|
224
|
-
}
|
|
225
|
-
else if (isAV1) {
|
|
226
|
-
// AV1 CBR mode
|
|
227
|
-
args.push('-strict', 'experimental');
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
break;
|
|
231
|
-
case 'quantizer':
|
|
232
|
-
// CRF/CQ - Constant Quality mode
|
|
233
|
-
if (isH264 || isHEVC) {
|
|
234
|
-
// Use CRF for x264/x265 (23 is default, lower = better quality)
|
|
235
|
-
args.push('-crf', '23');
|
|
236
|
-
if (bitrate) {
|
|
237
|
-
// Use bitrate as max if specified
|
|
238
|
-
args.push('-maxrate', String(bitrate));
|
|
239
|
-
args.push('-bufsize', String(bitrate * 2));
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
else if (isVP) {
|
|
243
|
-
// VP8/VP9 CQ mode
|
|
244
|
-
args.push('-crf', '31');
|
|
245
|
-
args.push('-b:v', '0'); // Required for pure CRF mode in VP9
|
|
246
|
-
}
|
|
247
|
-
else if (isAV1) {
|
|
248
|
-
// AV1 CQ mode
|
|
249
|
-
args.push('-crf', '30');
|
|
250
|
-
}
|
|
251
|
-
break;
|
|
252
|
-
case 'variable':
|
|
253
|
-
default:
|
|
254
|
-
// VBR - Variable Bitrate (default behavior)
|
|
255
|
-
if (bitrate) {
|
|
256
|
-
args.push('-b:v', String(bitrate));
|
|
257
|
-
if (isH264 || isHEVC) {
|
|
258
|
-
// Allow variation around target
|
|
259
|
-
args.push('-maxrate', String(Math.floor(bitrate * 1.5)));
|
|
260
|
-
args.push('-bufsize', String(bitrate * 2));
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
break;
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
_startProcess(args) {
|
|
267
|
-
if (this.process) {
|
|
268
|
-
throw new Error('FFmpeg process already running');
|
|
269
|
-
}
|
|
270
|
-
this.process = spawn(this.ffmpegPath, args, {
|
|
271
|
-
stdio: ['pipe', 'pipe', 'pipe']
|
|
272
|
-
});
|
|
273
|
-
this._isRunning = true;
|
|
274
|
-
this.process.stdout?.on('data', (data) => {
|
|
275
|
-
this._handleStdoutData(data);
|
|
276
|
-
});
|
|
277
|
-
this.process.stderr?.on('data', (data) => {
|
|
278
|
-
this.emit('error', new Error(`FFmpeg: ${data.toString()}`));
|
|
279
|
-
});
|
|
280
|
-
this.process.on('close', (code) => {
|
|
281
|
-
this._handleProcessClose(code);
|
|
282
|
-
});
|
|
283
|
-
this.process.on('error', (err) => {
|
|
284
|
-
this._isRunning = false;
|
|
285
|
-
this.emit('error', err);
|
|
286
|
-
});
|
|
287
|
-
}
|
|
288
|
-
/**
|
|
289
|
-
* Handle stdout data from FFmpeg
|
|
290
|
-
*/
|
|
291
|
-
_handleStdoutData(data) {
|
|
292
|
-
this.accumulatedData = Buffer.concat([this.accumulatedData, data]);
|
|
293
|
-
// Emit complete frames when we have enough data (for decoder - raw frames)
|
|
294
|
-
while (this.frameSize > 0 && this.accumulatedData.length >= this.frameSize) {
|
|
295
|
-
const frame = this.accumulatedData.subarray(0, this.frameSize);
|
|
296
|
-
this.accumulatedData = this.accumulatedData.subarray(this.frameSize);
|
|
297
|
-
this.emit('frame', frame);
|
|
298
|
-
}
|
|
299
|
-
// For encoded output, parse container format
|
|
300
|
-
if (this.frameSize === 0 && this._useIvf && this._ivfState) {
|
|
301
|
-
this._parseIvfOutput(data);
|
|
302
|
-
}
|
|
303
|
-
else if (this.frameSize === 0 && this._useAnnexB && this._annexBState) {
|
|
304
|
-
this._parseAnnexBOutput(data);
|
|
305
|
-
}
|
|
306
|
-
else if (this.frameSize === 0) {
|
|
307
|
-
// For other formats, emit raw data
|
|
308
|
-
this.emit('data', data);
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
/**
|
|
312
|
-
* Parse IVF output and emit encoded frames
|
|
313
|
-
*/
|
|
314
|
-
_parseIvfOutput(data) {
|
|
315
|
-
if (!this._ivfState)
|
|
316
|
-
return;
|
|
317
|
-
try {
|
|
318
|
-
// Reset accumulated data since IVF parser manages its own buffer
|
|
319
|
-
this.accumulatedData = Buffer.alloc(0);
|
|
320
|
-
const frames = parseIvfFrames(this._ivfState, data, isVP9KeyFrame);
|
|
321
|
-
for (const frame of frames) {
|
|
322
|
-
this.emit('encodedFrame', frame);
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
catch (err) {
|
|
326
|
-
this.emit('error', err);
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
/**
|
|
330
|
-
* Parse Annex B output and emit encoded frames
|
|
331
|
-
*/
|
|
332
|
-
_parseAnnexBOutput(data) {
|
|
333
|
-
if (!this._annexBState)
|
|
334
|
-
return;
|
|
335
|
-
// Reset accumulated data since Annex B parser manages its own buffer
|
|
336
|
-
this.accumulatedData = Buffer.alloc(0);
|
|
337
|
-
const frames = parseAnnexBFrames(this._annexBState, data);
|
|
338
|
-
for (const frame of frames) {
|
|
339
|
-
this.emit('encodedFrame', frame);
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
/**
|
|
343
|
-
* Handle process close event
|
|
344
|
-
*/
|
|
345
|
-
_handleProcessClose(code) {
|
|
346
|
-
this._isRunning = false;
|
|
347
|
-
this.process = null;
|
|
348
|
-
// Emit any remaining Annex B frame
|
|
349
|
-
if (this._useAnnexB && this._annexBState) {
|
|
350
|
-
const finalFrame = flushAnnexBParser(this._annexBState);
|
|
351
|
-
if (finalFrame) {
|
|
352
|
-
this.emit('encodedFrame', finalFrame);
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
else if (this.accumulatedData.length > 0) {
|
|
356
|
-
// Emit any remaining raw data
|
|
357
|
-
this.emit('data', this.accumulatedData);
|
|
358
|
-
this.accumulatedData = Buffer.alloc(0);
|
|
359
|
-
}
|
|
360
|
-
this.emit('close', code);
|
|
361
|
-
}
|
|
362
|
-
/**
|
|
363
|
-
* Write data to FFmpeg stdin
|
|
364
|
-
* @returns true if write was queued successfully, false if process is not healthy
|
|
365
|
-
*/
|
|
366
|
-
write(data) {
|
|
367
|
-
if (!this.isHealthy) {
|
|
368
|
-
return false;
|
|
369
|
-
}
|
|
370
|
-
try {
|
|
371
|
-
this.process.stdin.write(data);
|
|
372
|
-
return true;
|
|
373
|
-
}
|
|
374
|
-
catch {
|
|
375
|
-
return false;
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
/**
|
|
379
|
-
* Signal end of input data
|
|
380
|
-
*/
|
|
381
|
-
end() {
|
|
382
|
-
if (this.process?.stdin && !this._isShuttingDown) {
|
|
383
|
-
try {
|
|
384
|
-
this.process.stdin.end();
|
|
385
|
-
}
|
|
386
|
-
catch {
|
|
387
|
-
// Ignore errors when ending stdin
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
/**
|
|
392
|
-
* Gracefully shutdown the FFmpeg process with timeout
|
|
393
|
-
*/
|
|
394
|
-
async shutdown(timeout = DEFAULT_SHUTDOWN_TIMEOUT) {
|
|
395
|
-
if (!this.process || this._isShuttingDown) {
|
|
396
|
-
return;
|
|
397
|
-
}
|
|
398
|
-
this._isShuttingDown = true;
|
|
399
|
-
return new Promise((resolve) => {
|
|
400
|
-
const forceKillTimeout = setTimeout(() => {
|
|
401
|
-
if (this.process) {
|
|
402
|
-
this.process.kill('SIGKILL');
|
|
403
|
-
}
|
|
404
|
-
this._cleanup();
|
|
405
|
-
resolve();
|
|
406
|
-
}, timeout);
|
|
407
|
-
const onExit = () => {
|
|
408
|
-
clearTimeout(forceKillTimeout);
|
|
409
|
-
this._cleanup();
|
|
410
|
-
resolve();
|
|
411
|
-
};
|
|
412
|
-
if (this.process) {
|
|
413
|
-
this.process.once('exit', onExit);
|
|
414
|
-
this.process.once('error', onExit);
|
|
415
|
-
try {
|
|
416
|
-
this.process.stdin?.destroy();
|
|
417
|
-
}
|
|
418
|
-
catch {
|
|
419
|
-
// Ignore stdin destroy errors
|
|
420
|
-
}
|
|
421
|
-
this.process.kill('SIGTERM');
|
|
422
|
-
}
|
|
423
|
-
else {
|
|
424
|
-
clearTimeout(forceKillTimeout);
|
|
425
|
-
this._cleanup();
|
|
426
|
-
resolve();
|
|
427
|
-
}
|
|
428
|
-
});
|
|
429
|
-
}
|
|
430
|
-
/**
|
|
431
|
-
* Kill the FFmpeg process immediately
|
|
432
|
-
*/
|
|
433
|
-
kill() {
|
|
434
|
-
if (this.process) {
|
|
435
|
-
this._isShuttingDown = true;
|
|
436
|
-
try {
|
|
437
|
-
this.process.stdin?.destroy();
|
|
438
|
-
}
|
|
439
|
-
catch {
|
|
440
|
-
// Ignore stdin destroy errors
|
|
441
|
-
}
|
|
442
|
-
this.process.kill('SIGTERM');
|
|
443
|
-
setTimeout(() => {
|
|
444
|
-
if (this.process) {
|
|
445
|
-
this.process.kill('SIGKILL');
|
|
446
|
-
this._cleanup();
|
|
447
|
-
}
|
|
448
|
-
}, 1000);
|
|
449
|
-
}
|
|
450
|
-
this._cleanup();
|
|
451
|
-
}
|
|
452
|
-
/**
|
|
453
|
-
* Clean up internal state
|
|
454
|
-
*/
|
|
455
|
-
_cleanup() {
|
|
456
|
-
this.process = null;
|
|
457
|
-
this._isRunning = false;
|
|
458
|
-
this._isShuttingDown = false;
|
|
459
|
-
this.accumulatedData = Buffer.alloc(0);
|
|
460
|
-
this.outputBuffer = [];
|
|
461
|
-
this._ivfState = null;
|
|
462
|
-
this._annexBState = null;
|
|
463
|
-
}
|
|
464
|
-
/**
|
|
465
|
-
* Map WebCodecs codec string to FFmpeg codec
|
|
466
|
-
*/
|
|
467
|
-
_getFFmpegCodec(webCodec) {
|
|
468
|
-
const codecBase = webCodec.split('.')[0].toLowerCase();
|
|
469
|
-
const codecMap = {
|
|
470
|
-
'avc1': 'libx264',
|
|
471
|
-
'avc3': 'libx264',
|
|
472
|
-
'hev1': 'libx265',
|
|
473
|
-
'hvc1': 'libx265',
|
|
474
|
-
'vp8': 'libvpx',
|
|
475
|
-
'vp09': 'libvpx-vp9',
|
|
476
|
-
'vp9': 'libvpx-vp9',
|
|
477
|
-
'av01': 'libaom-av1',
|
|
478
|
-
'av1': 'libaom-av1',
|
|
479
|
-
};
|
|
480
|
-
return codecMap[codecBase] || codecBase;
|
|
481
|
-
}
|
|
482
|
-
/**
|
|
483
|
-
* Map WebCodecs codec to container format
|
|
484
|
-
*/
|
|
485
|
-
_getContainerFormat(webCodec) {
|
|
486
|
-
const codecBase = webCodec.split('.')[0].toLowerCase();
|
|
487
|
-
const formatMap = {
|
|
488
|
-
'avc1': 'h264',
|
|
489
|
-
'avc3': 'h264',
|
|
490
|
-
'hev1': 'hevc',
|
|
491
|
-
'hvc1': 'hevc',
|
|
492
|
-
'vp8': 'ivf',
|
|
493
|
-
'vp09': 'ivf',
|
|
494
|
-
'vp9': 'ivf',
|
|
495
|
-
'av01': 'ivf',
|
|
496
|
-
'av1': 'ivf',
|
|
497
|
-
};
|
|
498
|
-
return formatMap[codecBase] || 'rawvideo';
|
|
499
|
-
}
|
|
500
|
-
/**
|
|
501
|
-
* Map pixel format names
|
|
502
|
-
* @deprecated Use pixelFormatToFFmpeg from './formats.js' instead
|
|
503
|
-
*/
|
|
504
|
-
static pixelFormatToFFmpeg(format) {
|
|
505
|
-
const formatMap = {
|
|
506
|
-
'I420': 'yuv420p',
|
|
507
|
-
'I420A': 'yuva420p',
|
|
508
|
-
'I422': 'yuv422p',
|
|
509
|
-
'I444': 'yuv444p',
|
|
510
|
-
'NV12': 'nv12',
|
|
511
|
-
'RGBA': 'rgba',
|
|
512
|
-
'RGBX': 'rgb0',
|
|
513
|
-
'BGRA': 'bgra',
|
|
514
|
-
'BGRX': 'bgr0',
|
|
515
|
-
};
|
|
516
|
-
return formatMap[format] || format.toLowerCase();
|
|
517
|
-
}
|
|
518
|
-
/**
|
|
519
|
-
* @deprecated Use ffmpegToPixelFormat from './formats.js' instead
|
|
520
|
-
*/
|
|
521
|
-
static ffmpegToPixelFormat(format) {
|
|
522
|
-
const formatMap = {
|
|
523
|
-
'yuv420p': 'I420',
|
|
524
|
-
'yuva420p': 'I420A',
|
|
525
|
-
'yuv422p': 'I422',
|
|
526
|
-
'yuv444p': 'I444',
|
|
527
|
-
'nv12': 'NV12',
|
|
528
|
-
'rgba': 'RGBA',
|
|
529
|
-
'rgb0': 'RGBX',
|
|
530
|
-
'bgra': 'BGRA',
|
|
531
|
-
'bgr0': 'BGRX',
|
|
532
|
-
};
|
|
533
|
-
return formatMap[format] || format.toUpperCase();
|
|
534
|
-
}
|
|
535
|
-
/**
|
|
536
|
-
* Calculate frame size in bytes
|
|
537
|
-
* @deprecated Use calculateFrameSize from './formats.js' instead
|
|
538
|
-
*/
|
|
539
|
-
static calculateFrameSize(format, width, height) {
|
|
540
|
-
return calculateFrameSize(format, width, height);
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
//# sourceMappingURL=FFmpegProcess.js.map
|