@remotion/webcodecs 4.0.304 → 4.0.306
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/audio-decoder.d.ts +15 -10
- package/dist/audio-decoder.js +49 -52
- package/dist/audio-encoder.d.ts +5 -5
- package/dist/audio-encoder.js +20 -42
- package/dist/convert-encoded-chunk.d.ts +1 -1
- package/dist/convert-encoded-chunk.js +2 -5
- package/dist/convert-media.js +2 -2
- package/dist/copy-audio-track.d.ts +11 -0
- package/dist/copy-audio-track.js +31 -0
- package/dist/copy-video-track.d.ts +11 -0
- package/dist/copy-video-track.js +32 -0
- package/dist/create/event-emitter.d.ts +0 -1
- package/dist/create/iso-base-media/create-iso-base-media.js +3 -3
- package/dist/create/iso-base-media/example-stts.js +620 -620
- package/dist/create/iso-base-media/trak/mdia/minf/create-stbl.js +3 -1
- package/dist/create/iso-base-media/trak/mdia/minf/stbl/create-ctts.js +1 -1
- package/dist/create/iso-base-media/trak/mdia/minf/stbl/create-stts.js +3 -2
- package/dist/create/matroska/create-matroska-media.js +1 -1
- package/dist/create/progress-tracker.d.ts +0 -2
- package/dist/create/progress-tracker.js +3 -20
- package/dist/esm/index.mjs +583 -496
- package/dist/get-wave-audio-decoder.d.ts +6 -1
- package/dist/get-wave-audio-decoder.js +16 -11
- package/dist/io-manager/io-synchronizer.d.ts +6 -13
- package/dist/io-manager/io-synchronizer.js +31 -72
- package/dist/io-manager/make-timeout-promise.d.ts +1 -1
- package/dist/io-manager/make-timeout-promise.js +8 -4
- package/dist/on-audio-track.d.ts +2 -2
- package/dist/on-audio-track.js +15 -150
- package/dist/on-frame.d.ts +2 -4
- package/dist/on-frame.js +8 -9
- package/dist/on-video-track.d.ts +2 -2
- package/dist/on-video-track.js +18 -129
- package/dist/processing-queue.d.ts +19 -0
- package/dist/processing-queue.js +47 -0
- package/dist/reencode-audio-track.d.ts +18 -0
- package/dist/reencode-audio-track.js +164 -0
- package/dist/reencode-video-track.d.ts +19 -0
- package/dist/reencode-video-track.js +151 -0
- package/dist/sort-video-frames.d.ts +4 -3
- package/dist/sort-video-frames.js +7 -3
- package/dist/video-decoder.d.ts +14 -8
- package/dist/video-decoder.js +37 -72
- package/dist/video-encoder.d.ts +6 -5
- package/dist/video-encoder.js +16 -40
- package/dist/wav-audio-encoder.d.ts +4 -1
- package/dist/wav-audio-encoder.js +3 -2
- package/package.json +5 -5
package/dist/video-decoder.js
CHANGED
|
@@ -1,61 +1,35 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createVideoDecoder = void 0;
|
|
3
|
+
exports.createVideoDecoder = exports.internalCreateVideoDecoder = void 0;
|
|
4
4
|
const io_synchronizer_1 = require("./io-manager/io-synchronizer");
|
|
5
5
|
const log_1 = require("./log");
|
|
6
|
-
const
|
|
7
|
-
const createVideoDecoder = ({ onFrame, onError, controller, config, logLevel, progress, }) => {
|
|
6
|
+
const internalCreateVideoDecoder = ({ onFrame, onError, controller, config, logLevel, }) => {
|
|
8
7
|
const ioSynchronizer = (0, io_synchronizer_1.makeIoSynchronizer)({
|
|
9
8
|
logLevel,
|
|
10
9
|
label: 'Video decoder',
|
|
11
|
-
progress,
|
|
12
|
-
});
|
|
13
|
-
let outputQueue = Promise.resolve();
|
|
14
|
-
const addToQueue = (frame) => {
|
|
15
|
-
const cleanup = () => {
|
|
16
|
-
frame.close();
|
|
17
|
-
};
|
|
18
|
-
controller._internals._mediaParserController._internals.signal.addEventListener('abort', cleanup, {
|
|
19
|
-
once: true,
|
|
20
|
-
});
|
|
21
|
-
outputQueue = outputQueue
|
|
22
|
-
.then(() => {
|
|
23
|
-
if (controller._internals._mediaParserController._internals.signal.aborted) {
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
return onFrame(frame);
|
|
27
|
-
})
|
|
28
|
-
.then(() => {
|
|
29
|
-
ioSynchronizer.onProcessed();
|
|
30
|
-
})
|
|
31
|
-
.catch((err) => {
|
|
32
|
-
onError(err);
|
|
33
|
-
})
|
|
34
|
-
.finally(() => {
|
|
35
|
-
controller._internals._mediaParserController._internals.signal.removeEventListener('abort', cleanup);
|
|
36
|
-
cleanup();
|
|
37
|
-
});
|
|
38
|
-
return outputQueue;
|
|
39
|
-
};
|
|
40
|
-
const frameSorter = (0, sort_video_frames_1.videoFrameSorter)({
|
|
41
10
|
controller,
|
|
42
|
-
onRelease: async (frame) => {
|
|
43
|
-
await addToQueue(frame);
|
|
44
|
-
},
|
|
45
11
|
});
|
|
46
12
|
const videoDecoder = new VideoDecoder({
|
|
47
|
-
output(frame) {
|
|
13
|
+
async output(frame) {
|
|
14
|
+
try {
|
|
15
|
+
await onFrame(frame);
|
|
16
|
+
}
|
|
17
|
+
catch (err) {
|
|
18
|
+
onError(err);
|
|
19
|
+
frame.close();
|
|
20
|
+
}
|
|
48
21
|
ioSynchronizer.onOutput(frame.timestamp);
|
|
49
|
-
frameSorter.inputFrame(frame);
|
|
50
22
|
},
|
|
51
23
|
error(error) {
|
|
52
24
|
onError(error);
|
|
53
25
|
},
|
|
54
26
|
});
|
|
55
27
|
const close = () => {
|
|
56
|
-
controller
|
|
57
|
-
|
|
58
|
-
|
|
28
|
+
if (controller) {
|
|
29
|
+
controller._internals._mediaParserController._internals.signal.removeEventListener('abort',
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
31
|
+
onAbort);
|
|
32
|
+
}
|
|
59
33
|
if (videoDecoder.state === 'closed') {
|
|
60
34
|
return;
|
|
61
35
|
}
|
|
@@ -64,52 +38,43 @@ const createVideoDecoder = ({ onFrame, onError, controller, config, logLevel, pr
|
|
|
64
38
|
const onAbort = () => {
|
|
65
39
|
close();
|
|
66
40
|
};
|
|
67
|
-
controller
|
|
41
|
+
if (controller) {
|
|
42
|
+
controller._internals._mediaParserController._internals.signal.addEventListener('abort', onAbort);
|
|
43
|
+
}
|
|
68
44
|
videoDecoder.configure(config);
|
|
69
|
-
const
|
|
45
|
+
const decode = (sample) => {
|
|
70
46
|
if (videoDecoder.state === 'closed') {
|
|
71
47
|
return;
|
|
72
48
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
await ioSynchronizer.waitFor({
|
|
79
|
-
unemitted: 20,
|
|
80
|
-
unprocessed: 10,
|
|
81
|
-
minimumProgress: sample.timestamp - 10000000,
|
|
82
|
-
controller,
|
|
83
|
-
});
|
|
84
|
-
// Don't flush here.
|
|
85
|
-
// We manually keep track of the memory with the IO synchornizer.
|
|
86
|
-
// Example of flushing breaking things:
|
|
87
|
-
// IMG_2310.MOV has B-frames, and if we flush on a keyframe, we discard some frames that are yet to come.
|
|
88
|
-
videoDecoder.decode(new EncodedVideoChunk(sample));
|
|
89
|
-
ioSynchronizer.inputItem(sample.timestamp, sample.type === 'key');
|
|
49
|
+
const encodedChunk = sample instanceof EncodedVideoChunk
|
|
50
|
+
? sample
|
|
51
|
+
: new EncodedVideoChunk(sample);
|
|
52
|
+
videoDecoder.decode(encodedChunk);
|
|
53
|
+
ioSynchronizer.inputItem(sample.timestamp);
|
|
90
54
|
};
|
|
91
|
-
let inputQueue = Promise.resolve();
|
|
92
55
|
return {
|
|
93
|
-
|
|
94
|
-
inputQueue = inputQueue.then(() => processSample(sample));
|
|
95
|
-
return inputQueue;
|
|
96
|
-
},
|
|
56
|
+
decode,
|
|
97
57
|
waitForFinish: async () => {
|
|
98
58
|
await videoDecoder.flush();
|
|
99
59
|
log_1.Log.verbose(logLevel, 'Flushed video decoder');
|
|
100
|
-
await
|
|
101
|
-
log_1.Log.verbose(logLevel, 'Frame sorter flushed');
|
|
102
|
-
await ioSynchronizer.waitForFinish(controller);
|
|
60
|
+
await ioSynchronizer.waitForFinish();
|
|
103
61
|
log_1.Log.verbose(logLevel, 'IO synchro finished');
|
|
104
|
-
await outputQueue;
|
|
105
|
-
log_1.Log.verbose(logLevel, 'Output queue finished');
|
|
106
|
-
await inputQueue;
|
|
107
|
-
log_1.Log.verbose(logLevel, 'Input queue finished');
|
|
108
62
|
},
|
|
109
63
|
close,
|
|
110
64
|
flush: async () => {
|
|
111
65
|
await videoDecoder.flush();
|
|
112
66
|
},
|
|
67
|
+
waitForQueueToBeLessThan: ioSynchronizer.waitForQueueSize,
|
|
113
68
|
};
|
|
114
69
|
};
|
|
70
|
+
exports.internalCreateVideoDecoder = internalCreateVideoDecoder;
|
|
71
|
+
const createVideoDecoder = ({ onFrame, onError, controller, track, logLevel, }) => {
|
|
72
|
+
return (0, exports.internalCreateVideoDecoder)({
|
|
73
|
+
onFrame,
|
|
74
|
+
onError,
|
|
75
|
+
controller: controller ?? null,
|
|
76
|
+
config: track,
|
|
77
|
+
logLevel: logLevel ?? 'info',
|
|
78
|
+
});
|
|
79
|
+
};
|
|
115
80
|
exports.createVideoDecoder = createVideoDecoder;
|
package/dist/video-encoder.d.ts
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import { type MediaParserLogLevel } from '@remotion/media-parser';
|
|
2
|
-
import type { ProgressTracker } from './create/progress-tracker';
|
|
3
2
|
import type { ConvertMediaVideoCodec } from './get-available-video-codecs';
|
|
3
|
+
import type { IoSynchronizer } from './io-manager/io-synchronizer';
|
|
4
4
|
import type { WebCodecsController } from './webcodecs-controller';
|
|
5
5
|
export type WebCodecsVideoEncoder = {
|
|
6
|
-
|
|
6
|
+
encode: (videoFrame: VideoFrame) => void;
|
|
7
7
|
waitForFinish: () => Promise<void>;
|
|
8
8
|
close: () => void;
|
|
9
9
|
flush: () => Promise<void>;
|
|
10
|
+
ioSynchronizer: IoSynchronizer;
|
|
10
11
|
};
|
|
11
|
-
export declare const createVideoEncoder: ({ onChunk, onError, controller, config, logLevel, outputCodec,
|
|
12
|
+
export declare const createVideoEncoder: ({ onChunk, onError, controller, config, logLevel, outputCodec, keyframeInterval, }: {
|
|
12
13
|
onChunk: (chunk: EncodedVideoChunk, metadata: EncodedVideoChunkMetadata | null) => Promise<void>;
|
|
13
|
-
onError: (error:
|
|
14
|
+
onError: (error: Error) => void;
|
|
14
15
|
controller: WebCodecsController;
|
|
15
16
|
config: VideoEncoderConfig;
|
|
16
17
|
logLevel: MediaParserLogLevel;
|
|
17
18
|
outputCodec: ConvertMediaVideoCodec;
|
|
18
|
-
|
|
19
|
+
keyframeInterval: number;
|
|
19
20
|
}) => WebCodecsVideoEncoder;
|
package/dist/video-encoder.js
CHANGED
|
@@ -5,38 +5,28 @@ const media_parser_1 = require("@remotion/media-parser");
|
|
|
5
5
|
const convert_to_correct_videoframe_1 = require("./convert-to-correct-videoframe");
|
|
6
6
|
const io_synchronizer_1 = require("./io-manager/io-synchronizer");
|
|
7
7
|
const log_1 = require("./log");
|
|
8
|
-
const createVideoEncoder = ({ onChunk, onError, controller, config, logLevel, outputCodec,
|
|
8
|
+
const createVideoEncoder = ({ onChunk, onError, controller, config, logLevel, outputCodec, keyframeInterval, }) => {
|
|
9
9
|
if (controller._internals._mediaParserController._internals.signal.aborted) {
|
|
10
10
|
throw new media_parser_1.MediaParserAbortError('Not creating video encoder, already aborted');
|
|
11
11
|
}
|
|
12
12
|
const ioSynchronizer = (0, io_synchronizer_1.makeIoSynchronizer)({
|
|
13
13
|
logLevel,
|
|
14
14
|
label: 'Video encoder',
|
|
15
|
-
|
|
15
|
+
controller,
|
|
16
16
|
});
|
|
17
|
-
let outputQueue = Promise.resolve();
|
|
18
17
|
const encoder = new VideoEncoder({
|
|
19
18
|
error(error) {
|
|
20
19
|
onError(error);
|
|
21
20
|
},
|
|
22
|
-
output(chunk, metadata) {
|
|
21
|
+
async output(chunk, metadata) {
|
|
23
22
|
const timestamp = chunk.timestamp + (chunk.duration ?? 0);
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
.aborted) {
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
return onChunk(chunk, metadata ?? null);
|
|
32
|
-
})
|
|
33
|
-
.then(() => {
|
|
34
|
-
ioSynchronizer.onProcessed();
|
|
35
|
-
return Promise.resolve();
|
|
36
|
-
})
|
|
37
|
-
.catch((err) => {
|
|
23
|
+
try {
|
|
24
|
+
await onChunk(chunk, metadata ?? null);
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
38
27
|
onError(err);
|
|
39
|
-
}
|
|
28
|
+
}
|
|
29
|
+
ioSynchronizer.onOutput(timestamp);
|
|
40
30
|
},
|
|
41
31
|
});
|
|
42
32
|
const close = () => {
|
|
@@ -55,23 +45,11 @@ const createVideoEncoder = ({ onChunk, onError, controller, config, logLevel, ou
|
|
|
55
45
|
log_1.Log.verbose(logLevel, 'Configuring video encoder', config);
|
|
56
46
|
encoder.configure(config);
|
|
57
47
|
let framesProcessed = 0;
|
|
58
|
-
const encodeFrame =
|
|
59
|
-
if (encoder.state === 'closed') {
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
progress.setPossibleLowestTimestamp(frame.timestamp);
|
|
63
|
-
await ioSynchronizer.waitFor({
|
|
64
|
-
// Firefox stalls if too few frames are passed
|
|
65
|
-
unemitted: 10,
|
|
66
|
-
unprocessed: 10,
|
|
67
|
-
minimumProgress: frame.timestamp - 10000000,
|
|
68
|
-
controller,
|
|
69
|
-
});
|
|
70
|
-
// @ts-expect-error - can have changed in the meanwhile
|
|
48
|
+
const encodeFrame = (frame) => {
|
|
71
49
|
if (encoder.state === 'closed') {
|
|
72
50
|
return;
|
|
73
51
|
}
|
|
74
|
-
const keyFrame = framesProcessed %
|
|
52
|
+
const keyFrame = framesProcessed % keyframeInterval === 0;
|
|
75
53
|
encoder.encode((0, convert_to_correct_videoframe_1.convertToCorrectVideoFrame)({ videoFrame: frame, outputCodec }), {
|
|
76
54
|
keyFrame,
|
|
77
55
|
// @ts-expect-error
|
|
@@ -79,24 +57,22 @@ const createVideoEncoder = ({ onChunk, onError, controller, config, logLevel, ou
|
|
|
79
57
|
quantizer: 36,
|
|
80
58
|
},
|
|
81
59
|
});
|
|
82
|
-
ioSynchronizer.inputItem(frame.timestamp
|
|
60
|
+
ioSynchronizer.inputItem(frame.timestamp);
|
|
83
61
|
framesProcessed++;
|
|
84
62
|
};
|
|
85
|
-
let inputQueue = Promise.resolve();
|
|
86
63
|
return {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
return inputQueue;
|
|
64
|
+
encode: (frame) => {
|
|
65
|
+
encodeFrame(frame);
|
|
90
66
|
},
|
|
91
67
|
waitForFinish: async () => {
|
|
92
68
|
await encoder.flush();
|
|
93
|
-
await
|
|
94
|
-
await ioSynchronizer.waitForFinish(controller);
|
|
69
|
+
await ioSynchronizer.waitForFinish();
|
|
95
70
|
},
|
|
96
71
|
close,
|
|
97
72
|
flush: async () => {
|
|
98
73
|
await encoder.flush();
|
|
99
74
|
},
|
|
75
|
+
ioSynchronizer,
|
|
100
76
|
};
|
|
101
77
|
};
|
|
102
78
|
exports.createVideoEncoder = createVideoEncoder;
|
|
@@ -1,2 +1,5 @@
|
|
|
1
1
|
import type { AudioEncoderInit, WebCodecsAudioEncoder } from './audio-encoder';
|
|
2
|
-
|
|
2
|
+
import type { IoSynchronizer } from './io-manager/io-synchronizer';
|
|
3
|
+
export declare const getWaveAudioEncoder: ({ onChunk, controller, config, ioSynchronizer, }: Pick<AudioEncoderInit, "onChunk" | "controller" | "config"> & {
|
|
4
|
+
ioSynchronizer: IoSynchronizer;
|
|
5
|
+
}) => WebCodecsAudioEncoder;
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getWaveAudioEncoder = void 0;
|
|
4
4
|
const convert_audiodata_1 = require("./convert-audiodata");
|
|
5
|
-
const getWaveAudioEncoder = ({ onChunk, controller, config, }) => {
|
|
5
|
+
const getWaveAudioEncoder = ({ onChunk, controller, config, ioSynchronizer, }) => {
|
|
6
6
|
return {
|
|
7
7
|
close: () => {
|
|
8
8
|
return Promise.resolve();
|
|
9
9
|
},
|
|
10
|
-
|
|
10
|
+
encode: (unconvertedAudioData) => {
|
|
11
11
|
if (controller._internals._mediaParserController._internals.signal.aborted) {
|
|
12
12
|
return Promise.resolve();
|
|
13
13
|
}
|
|
@@ -28,6 +28,7 @@ const getWaveAudioEncoder = ({ onChunk, controller, config, }) => {
|
|
|
28
28
|
},
|
|
29
29
|
flush: () => Promise.resolve(),
|
|
30
30
|
waitForFinish: () => Promise.resolve(),
|
|
31
|
+
ioSynchronizer,
|
|
31
32
|
};
|
|
32
33
|
};
|
|
33
34
|
exports.getWaveAudioEncoder = getWaveAudioEncoder;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remotion/webcodecs",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.306",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"module": "dist/esm/index.mjs",
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
"author": "Jonny Burger <jonny@remotion.dev>",
|
|
20
20
|
"license": "Remotion License (See https://remotion.dev/docs/webcodecs#license)",
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@remotion/media-parser": "4.0.
|
|
23
|
-
"@remotion/licensing": "4.0.
|
|
22
|
+
"@remotion/media-parser": "4.0.306",
|
|
23
|
+
"@remotion/licensing": "4.0.306"
|
|
24
24
|
},
|
|
25
25
|
"peerDependencies": {},
|
|
26
26
|
"devDependencies": {
|
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
"playwright": "1.51.1",
|
|
29
29
|
"@playwright/test": "1.51.1",
|
|
30
30
|
"eslint": "9.19.0",
|
|
31
|
-
"@remotion/
|
|
32
|
-
"@remotion/
|
|
31
|
+
"@remotion/example-videos": "4.0.306",
|
|
32
|
+
"@remotion/eslint-config-internal": "4.0.306"
|
|
33
33
|
},
|
|
34
34
|
"keywords": [],
|
|
35
35
|
"publishConfig": {
|