@remotion/webcodecs 4.0.237 → 4.0.239
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.js +11 -7
- package/dist/audio-encoder.js +4 -2
- package/dist/auto-select-writer.d.ts +1 -1
- package/dist/auto-select-writer.js +22 -5
- package/dist/can-copy-audio-track.d.ts +4 -3
- package/dist/can-copy-audio-track.js +7 -6
- package/dist/can-copy-video-track.d.ts +4 -3
- package/dist/can-copy-video-track.js +7 -6
- package/dist/convert-media.js +2 -2
- package/dist/default-on-audio-track-handler.js +9 -11
- package/dist/default-on-video-track-handler.js +6 -15
- package/dist/esm/index.mjs +188 -140
- package/dist/io-manager/io-synchronizer.d.ts +4 -3
- package/dist/io-manager/io-synchronizer.js +25 -10
- package/dist/on-audio-track-handler.d.ts +4 -2
- package/dist/on-audio-track.d.ts +2 -2
- package/dist/on-audio-track.js +13 -6
- package/dist/on-frame.js +4 -1
- package/dist/on-video-track-handler.d.ts +4 -2
- package/dist/on-video-track.d.ts +2 -2
- package/dist/on-video-track.js +15 -6
- package/dist/video-decoder.js +5 -2
- package/dist/video-encoder.js +4 -2
- package/package.json +4 -4
- package/dist/codec-id.d.ts +0 -10
- package/dist/codec-id.js +0 -38
- package/dist/create-aac-codecprivate.d.ts +0 -14
- package/dist/create-aac-codecprivate.js +0 -72
- package/dist/io-manager/event-emitter.d.ts +0 -31
- package/dist/io-manager/event-emitter.js +0 -25
- package/dist/rotate-video.d.ts +0 -4
- package/dist/rotate-video.js +0 -43
- package/dist/test/aac-codecprivate.test.js +0 -12
- package/dist/with-resolvers.d.ts +0 -10
- package/dist/with-resolvers.js +0 -28
- /package/dist/test/{aac-codecprivate.test.d.ts → avi-to-mp4.test.d.ts} +0 -0
|
@@ -14,8 +14,8 @@ const makeIoSynchronizer = ({ logLevel, label, progress, }) => {
|
|
|
14
14
|
let keyframes = [];
|
|
15
15
|
// Once WebCodecs emits items, the user has to handle them
|
|
16
16
|
// Let's keep count of how many items are unprocessed
|
|
17
|
-
let
|
|
18
|
-
const getUnprocessed = () =>
|
|
17
|
+
let _unprocessed = 0;
|
|
18
|
+
const getUnprocessed = () => _unprocessed;
|
|
19
19
|
const getUnemittedItems = () => {
|
|
20
20
|
inputs = inputs.filter((input) => Math.floor(input) > Math.floor(lastOutput));
|
|
21
21
|
return inputs.length;
|
|
@@ -47,7 +47,7 @@ const makeIoSynchronizer = ({ logLevel, label, progress, }) => {
|
|
|
47
47
|
eventEmitter.dispatchEvent('output', {
|
|
48
48
|
timestamp,
|
|
49
49
|
});
|
|
50
|
-
|
|
50
|
+
_unprocessed++;
|
|
51
51
|
printState('Got output');
|
|
52
52
|
};
|
|
53
53
|
const waitForOutput = () => {
|
|
@@ -68,8 +68,17 @@ const makeIoSynchronizer = ({ logLevel, label, progress, }) => {
|
|
|
68
68
|
eventEmitter.addEventListener('processed', on);
|
|
69
69
|
return promise;
|
|
70
70
|
};
|
|
71
|
-
const waitFor = async ({
|
|
72
|
-
const { timeoutPromise, clear } = (0, make_timeout_promise_1.makeTimeoutPromise)(
|
|
71
|
+
const waitFor = async ({ unprocessed, unemitted, minimumProgress, signal, }) => {
|
|
72
|
+
const { timeoutPromise, clear } = (0, make_timeout_promise_1.makeTimeoutPromise)([
|
|
73
|
+
`Waited too long for ${label}:`,
|
|
74
|
+
`${getUnemittedItems()} unemitted items`,
|
|
75
|
+
`${getUnprocessed()} unprocessed items`,
|
|
76
|
+
`minimum progress ${minimumProgress}`,
|
|
77
|
+
`smallest progress: ${progress.getSmallestProgress()}`,
|
|
78
|
+
`inputs: ${JSON.stringify(inputs)}`,
|
|
79
|
+
`last output: ${lastOutput}`,
|
|
80
|
+
].join('\n'), 10000);
|
|
81
|
+
signal.addEventListener('abort', clear);
|
|
73
82
|
await Promise.race([
|
|
74
83
|
timeoutPromise,
|
|
75
84
|
Promise.all([
|
|
@@ -79,11 +88,11 @@ const makeIoSynchronizer = ({ logLevel, label, progress, }) => {
|
|
|
79
88
|
}
|
|
80
89
|
})(),
|
|
81
90
|
(async () => {
|
|
82
|
-
while (getUnprocessed() >
|
|
91
|
+
while (getUnprocessed() > unprocessed) {
|
|
83
92
|
await waitForProcessed();
|
|
84
93
|
}
|
|
85
94
|
})(),
|
|
86
|
-
minimumProgress === null
|
|
95
|
+
minimumProgress === null || progress.getSmallestProgress() === null
|
|
87
96
|
? Promise.resolve()
|
|
88
97
|
: (async () => {
|
|
89
98
|
while (progress.getSmallestProgress() < minimumProgress) {
|
|
@@ -92,13 +101,19 @@ const makeIoSynchronizer = ({ logLevel, label, progress, }) => {
|
|
|
92
101
|
})(),
|
|
93
102
|
]),
|
|
94
103
|
]).finally(() => clear());
|
|
104
|
+
signal.removeEventListener('abort', clear);
|
|
95
105
|
};
|
|
96
|
-
const waitForFinish = async () => {
|
|
97
|
-
await waitFor({
|
|
106
|
+
const waitForFinish = async (signal) => {
|
|
107
|
+
await waitFor({
|
|
108
|
+
unprocessed: 0,
|
|
109
|
+
unemitted: 0,
|
|
110
|
+
minimumProgress: null,
|
|
111
|
+
signal,
|
|
112
|
+
});
|
|
98
113
|
};
|
|
99
114
|
const onProcessed = () => {
|
|
100
115
|
eventEmitter.dispatchEvent('processed', {});
|
|
101
|
-
|
|
116
|
+
_unprocessed--;
|
|
102
117
|
};
|
|
103
118
|
return {
|
|
104
119
|
inputItem,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AudioTrack, LogLevel } from '@remotion/media-parser';
|
|
1
|
+
import type { AudioTrack, LogLevel, ParseMediaContainer } from '@remotion/media-parser';
|
|
2
2
|
import type { ConvertMediaAudioCodec } from './get-available-audio-codecs';
|
|
3
3
|
import type { ConvertMediaContainer } from './get-available-containers';
|
|
4
4
|
export type AudioOperation = {
|
|
@@ -16,5 +16,7 @@ export type ConvertMediaOnAudioTrackHandler = (options: {
|
|
|
16
16
|
track: AudioTrack;
|
|
17
17
|
defaultAudioCodec: ConvertMediaAudioCodec | null;
|
|
18
18
|
logLevel: LogLevel;
|
|
19
|
-
|
|
19
|
+
outputContainer: ConvertMediaContainer;
|
|
20
|
+
inputContainer: ParseMediaContainer;
|
|
21
|
+
canCopyTrack: boolean;
|
|
20
22
|
}) => AudioOperation | Promise<AudioOperation>;
|
package/dist/on-audio-track.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import type { ConvertMediaAudioCodec } from './get-available-audio-codecs';
|
|
|
4
4
|
import type { ConvertMediaContainer } from './get-available-containers';
|
|
5
5
|
import type { ConvertMediaOnAudioTrackHandler } from './on-audio-track-handler';
|
|
6
6
|
import type { ConvertMediaProgressFn } from './throttled-state-update';
|
|
7
|
-
export declare const makeAudioTrackHandler: ({ state, defaultAudioCodec: audioCodec, controller, abortConversion, onMediaStateUpdate, onAudioTrack, logLevel,
|
|
7
|
+
export declare const makeAudioTrackHandler: ({ state, defaultAudioCodec: audioCodec, controller, abortConversion, onMediaStateUpdate, onAudioTrack, logLevel, outputContainer, progressTracker, }: {
|
|
8
8
|
state: MediaFn;
|
|
9
9
|
defaultAudioCodec: ConvertMediaAudioCodec | null;
|
|
10
10
|
controller: AbortController;
|
|
@@ -12,6 +12,6 @@ export declare const makeAudioTrackHandler: ({ state, defaultAudioCodec: audioCo
|
|
|
12
12
|
onMediaStateUpdate: null | ConvertMediaProgressFn;
|
|
13
13
|
onAudioTrack: ConvertMediaOnAudioTrackHandler | null;
|
|
14
14
|
logLevel: LogLevel;
|
|
15
|
-
|
|
15
|
+
outputContainer: ConvertMediaContainer;
|
|
16
16
|
progressTracker: ProgressTracker;
|
|
17
17
|
}) => OnAudioTrack;
|
package/dist/on-audio-track.js
CHANGED
|
@@ -9,22 +9,31 @@ const audio_decoder_1 = require("./audio-decoder");
|
|
|
9
9
|
const audio_decoder_config_1 = require("./audio-decoder-config");
|
|
10
10
|
const audio_encoder_1 = require("./audio-encoder");
|
|
11
11
|
const audio_encoder_config_1 = require("./audio-encoder-config");
|
|
12
|
+
const can_copy_audio_track_1 = require("./can-copy-audio-track");
|
|
12
13
|
const convert_encoded_chunk_1 = require("./convert-encoded-chunk");
|
|
13
14
|
const default_on_audio_track_handler_1 = require("./default-on-audio-track-handler");
|
|
14
15
|
const error_cause_1 = __importDefault(require("./error-cause"));
|
|
16
|
+
const get_default_audio_codec_1 = require("./get-default-audio-codec");
|
|
15
17
|
const log_1 = require("./log");
|
|
16
|
-
const makeAudioTrackHandler = ({ state, defaultAudioCodec: audioCodec, controller, abortConversion, onMediaStateUpdate, onAudioTrack, logLevel,
|
|
18
|
+
const makeAudioTrackHandler = ({ state, defaultAudioCodec: audioCodec, controller, abortConversion, onMediaStateUpdate, onAudioTrack, logLevel, outputContainer, progressTracker, }) => async ({ track, container: inputContainer }) => {
|
|
19
|
+
const canCopyTrack = (0, can_copy_audio_track_1.canCopyAudioTrack)({
|
|
20
|
+
inputCodec: track.codecWithoutConfig,
|
|
21
|
+
outputContainer,
|
|
22
|
+
inputContainer,
|
|
23
|
+
});
|
|
17
24
|
const audioOperation = await (onAudioTrack !== null && onAudioTrack !== void 0 ? onAudioTrack : default_on_audio_track_handler_1.defaultOnAudioTrackHandler)({
|
|
18
|
-
defaultAudioCodec: audioCodec,
|
|
25
|
+
defaultAudioCodec: audioCodec !== null && audioCodec !== void 0 ? audioCodec : (0, get_default_audio_codec_1.getDefaultAudioCodec)({ container: outputContainer }),
|
|
19
26
|
track,
|
|
20
27
|
logLevel,
|
|
21
|
-
|
|
28
|
+
outputContainer,
|
|
29
|
+
inputContainer,
|
|
30
|
+
canCopyTrack,
|
|
22
31
|
});
|
|
23
32
|
if (audioOperation.type === 'drop') {
|
|
24
33
|
return null;
|
|
25
34
|
}
|
|
26
35
|
if (audioOperation.type === 'fail') {
|
|
27
|
-
throw new error_cause_1.default(`Audio track with ID ${track.trackId}
|
|
36
|
+
throw new error_cause_1.default(`Audio track with ID ${track.trackId} resolved with {"type": "fail"}. This could mean that this audio track could neither be copied to the output container or re-encoded. You have the option to drop the track instead of failing it: https://remotion.dev/docs/webcodecs/track-transformation`);
|
|
28
37
|
}
|
|
29
38
|
if (audioOperation.type === 'copy') {
|
|
30
39
|
const addedTrack = await state.addTrack({
|
|
@@ -41,7 +50,6 @@ const makeAudioTrackHandler = ({ state, defaultAudioCodec: audioCodec, controlle
|
|
|
41
50
|
chunk: audioSample,
|
|
42
51
|
trackNumber: addedTrack.trackNumber,
|
|
43
52
|
isVideo: false,
|
|
44
|
-
timescale: track.timescale,
|
|
45
53
|
codecPrivate: track.codecPrivate,
|
|
46
54
|
});
|
|
47
55
|
onMediaStateUpdate === null || onMediaStateUpdate === void 0 ? void 0 : onMediaStateUpdate((prevState) => {
|
|
@@ -102,7 +110,6 @@ const makeAudioTrackHandler = ({ state, defaultAudioCodec: audioCodec, controlle
|
|
|
102
110
|
chunk: (0, convert_encoded_chunk_1.convertEncodedChunk)(chunk, trackNumber),
|
|
103
111
|
trackNumber,
|
|
104
112
|
isVideo: false,
|
|
105
|
-
timescale: track.timescale,
|
|
106
113
|
codecPrivate,
|
|
107
114
|
});
|
|
108
115
|
onMediaStateUpdate === null || onMediaStateUpdate === void 0 ? void 0 : onMediaStateUpdate((prevState) => {
|
package/dist/on-frame.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.onFrame = void 0;
|
|
4
|
+
const browser_quirks_1 = require("./browser-quirks");
|
|
4
5
|
const convert_to_correct_videoframe_1 = require("./convert-to-correct-videoframe");
|
|
5
6
|
const rotate_video_frame_1 = require("./rotate-video-frame");
|
|
6
7
|
const onFrame = async ({ frame: unrotatedFrame, onVideoFrame, videoEncoder, track, outputCodec, rotation, }) => {
|
|
@@ -21,7 +22,9 @@ const onFrame = async ({ frame: unrotatedFrame, onVideoFrame, videoEncoder, trac
|
|
|
21
22
|
if (userProcessedFrame.displayHeight !== rotated.displayHeight) {
|
|
22
23
|
throw new Error(`Returned VideoFrame of track ${track.trackId} has different displayHeight (${userProcessedFrame.displayHeight}) than the input frame (${userProcessedFrame.displayHeight})`);
|
|
23
24
|
}
|
|
24
|
-
|
|
25
|
+
// In Safari, calling new VideoFrame() might change the timestamp
|
|
26
|
+
// In flipVideo test from 803000 to 803299
|
|
27
|
+
if (userProcessedFrame.timestamp !== rotated.timestamp && !(0, browser_quirks_1.isSafari)()) {
|
|
25
28
|
throw new Error(`Returned VideoFrame of track ${track.trackId} has different timestamp (${userProcessedFrame.timestamp}) than the input frame (${rotated.timestamp}). When calling new VideoFrame(), pass {timestamp: frame.timestamp} as second argument`);
|
|
26
29
|
}
|
|
27
30
|
if (((_a = userProcessedFrame.duration) !== null && _a !== void 0 ? _a : 0) !== ((_b = rotated.duration) !== null && _b !== void 0 ? _b : 0)) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { LogLevel, VideoTrack } from '@remotion/media-parser';
|
|
1
|
+
import type { LogLevel, ParseMediaContainer, VideoTrack } from '@remotion/media-parser';
|
|
2
2
|
import type { ConvertMediaContainer } from './get-available-containers';
|
|
3
3
|
import type { ConvertMediaVideoCodec } from './get-available-video-codecs';
|
|
4
4
|
export type VideoOperation = {
|
|
@@ -16,6 +16,8 @@ export type ConvertMediaOnVideoTrackHandler = (options: {
|
|
|
16
16
|
defaultVideoCodec: ConvertMediaVideoCodec | null;
|
|
17
17
|
track: VideoTrack;
|
|
18
18
|
logLevel: LogLevel;
|
|
19
|
-
|
|
19
|
+
outputContainer: ConvertMediaContainer;
|
|
20
20
|
rotate: number;
|
|
21
|
+
inputContainer: ParseMediaContainer;
|
|
22
|
+
canCopyTrack: boolean;
|
|
21
23
|
}) => VideoOperation | Promise<VideoOperation>;
|
package/dist/on-video-track.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import type { ConvertMediaContainer } from './get-available-containers';
|
|
|
5
5
|
import type { ConvertMediaVideoCodec } from './get-available-video-codecs';
|
|
6
6
|
import type { ConvertMediaOnVideoTrackHandler } from './on-video-track-handler';
|
|
7
7
|
import type { ConvertMediaProgressFn } from './throttled-state-update';
|
|
8
|
-
export declare const makeVideoTrackHandler: ({ state, onVideoFrame, onMediaStateUpdate, abortConversion, controller, defaultVideoCodec, onVideoTrack, logLevel,
|
|
8
|
+
export declare const makeVideoTrackHandler: ({ state, onVideoFrame, onMediaStateUpdate, abortConversion, controller, defaultVideoCodec, onVideoTrack, logLevel, outputContainer, rotate, progress, }: {
|
|
9
9
|
state: MediaFn;
|
|
10
10
|
onVideoFrame: null | ConvertMediaOnVideoFrame;
|
|
11
11
|
onMediaStateUpdate: null | ConvertMediaProgressFn;
|
|
@@ -14,7 +14,7 @@ export declare const makeVideoTrackHandler: ({ state, onVideoFrame, onMediaState
|
|
|
14
14
|
defaultVideoCodec: ConvertMediaVideoCodec | null;
|
|
15
15
|
onVideoTrack: ConvertMediaOnVideoTrackHandler | null;
|
|
16
16
|
logLevel: LogLevel;
|
|
17
|
-
|
|
17
|
+
outputContainer: ConvertMediaContainer;
|
|
18
18
|
rotate: number;
|
|
19
19
|
progress: ProgressTracker;
|
|
20
20
|
}) => OnVideoTrack;
|
package/dist/on-video-track.js
CHANGED
|
@@ -5,9 +5,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.makeVideoTrackHandler = void 0;
|
|
7
7
|
const arraybuffer_to_uint8_array_1 = require("./arraybuffer-to-uint8-array");
|
|
8
|
+
const can_copy_video_track_1 = require("./can-copy-video-track");
|
|
8
9
|
const convert_encoded_chunk_1 = require("./convert-encoded-chunk");
|
|
9
10
|
const default_on_video_track_handler_1 = require("./default-on-video-track-handler");
|
|
10
11
|
const error_cause_1 = __importDefault(require("./error-cause"));
|
|
12
|
+
const get_default_video_codec_1 = require("./get-default-video-codec");
|
|
11
13
|
const log_1 = require("./log");
|
|
12
14
|
const on_frame_1 = require("./on-frame");
|
|
13
15
|
const rotation_1 = require("./rotation");
|
|
@@ -15,23 +17,32 @@ const video_decoder_1 = require("./video-decoder");
|
|
|
15
17
|
const video_decoder_config_1 = require("./video-decoder-config");
|
|
16
18
|
const video_encoder_1 = require("./video-encoder");
|
|
17
19
|
const video_encoder_config_1 = require("./video-encoder-config");
|
|
18
|
-
const makeVideoTrackHandler = ({ state, onVideoFrame, onMediaStateUpdate, abortConversion, controller, defaultVideoCodec, onVideoTrack, logLevel,
|
|
20
|
+
const makeVideoTrackHandler = ({ state, onVideoFrame, onMediaStateUpdate, abortConversion, controller, defaultVideoCodec, onVideoTrack, logLevel, outputContainer, rotate, progress, }) => async ({ track, container: inputContainer }) => {
|
|
19
21
|
var _a;
|
|
20
22
|
if (controller.signal.aborted) {
|
|
21
23
|
throw new error_cause_1.default('Aborted');
|
|
22
24
|
}
|
|
25
|
+
const canCopyTrack = (0, can_copy_video_track_1.canCopyVideoTrack)({
|
|
26
|
+
inputCodec: track.codecWithoutConfig,
|
|
27
|
+
inputContainer,
|
|
28
|
+
inputRotation: track.rotation,
|
|
29
|
+
outputContainer,
|
|
30
|
+
rotationToApply: rotate,
|
|
31
|
+
});
|
|
23
32
|
const videoOperation = await (onVideoTrack !== null && onVideoTrack !== void 0 ? onVideoTrack : default_on_video_track_handler_1.defaultOnVideoTrackHandler)({
|
|
24
33
|
track,
|
|
25
|
-
defaultVideoCodec,
|
|
34
|
+
defaultVideoCodec: defaultVideoCodec !== null && defaultVideoCodec !== void 0 ? defaultVideoCodec : (0, get_default_video_codec_1.getDefaultVideoCodec)({ container: outputContainer }),
|
|
26
35
|
logLevel,
|
|
27
|
-
|
|
36
|
+
outputContainer,
|
|
28
37
|
rotate,
|
|
38
|
+
inputContainer,
|
|
39
|
+
canCopyTrack,
|
|
29
40
|
});
|
|
30
41
|
if (videoOperation.type === 'drop') {
|
|
31
42
|
return null;
|
|
32
43
|
}
|
|
33
44
|
if (videoOperation.type === 'fail') {
|
|
34
|
-
throw new error_cause_1.default(`Video track with ID ${track.trackId} could
|
|
45
|
+
throw new error_cause_1.default(`Video track with ID ${track.trackId} could with {"type": "fail"}. This could mean that this video track could neither be copied to the output container or re-encoded. You have the option to drop the track instead of failing it: https://remotion.dev/docs/webcodecs/track-transformation`);
|
|
35
46
|
}
|
|
36
47
|
if (videoOperation.type === 'copy') {
|
|
37
48
|
log_1.Log.verbose(logLevel, `Copying video track with codec ${track.codec} and timescale ${track.timescale}`);
|
|
@@ -49,7 +60,6 @@ const makeVideoTrackHandler = ({ state, onVideoFrame, onMediaStateUpdate, abortC
|
|
|
49
60
|
chunk: sample,
|
|
50
61
|
trackNumber: videoTrack.trackNumber,
|
|
51
62
|
isVideo: true,
|
|
52
|
-
timescale: track.timescale,
|
|
53
63
|
codecPrivate: track.codecPrivate,
|
|
54
64
|
});
|
|
55
65
|
onMediaStateUpdate === null || onMediaStateUpdate === void 0 ? void 0 : onMediaStateUpdate((prevState) => {
|
|
@@ -101,7 +111,6 @@ const makeVideoTrackHandler = ({ state, onVideoFrame, onMediaStateUpdate, abortC
|
|
|
101
111
|
chunk: (0, convert_encoded_chunk_1.convertEncodedChunk)(chunk, trackNumber),
|
|
102
112
|
trackNumber,
|
|
103
113
|
isVideo: true,
|
|
104
|
-
timescale: track.timescale,
|
|
105
114
|
codecPrivate: (0, arraybuffer_to_uint8_array_1.arrayBufferToUint8Array)(((_b = (_a = metadata === null || metadata === void 0 ? void 0 : metadata.decoderConfig) === null || _a === void 0 ? void 0 : _a.description) !== null && _b !== void 0 ? _b : null)),
|
|
106
115
|
});
|
|
107
116
|
onMediaStateUpdate === null || onMediaStateUpdate === void 0 ? void 0 : onMediaStateUpdate((prevState) => {
|
package/dist/video-decoder.js
CHANGED
|
@@ -52,6 +52,7 @@ const createVideoDecoder = ({ onFrame, onError, signal, config, logLevel, progre
|
|
|
52
52
|
signal.addEventListener('abort', onAbort);
|
|
53
53
|
videoDecoder.configure(config);
|
|
54
54
|
const processSample = async (sample) => {
|
|
55
|
+
var _a, _b;
|
|
55
56
|
if (videoDecoder.state === 'closed') {
|
|
56
57
|
return;
|
|
57
58
|
}
|
|
@@ -59,10 +60,12 @@ const createVideoDecoder = ({ onFrame, onError, signal, config, logLevel, progre
|
|
|
59
60
|
if (videoDecoder.state === 'closed') {
|
|
60
61
|
return;
|
|
61
62
|
}
|
|
63
|
+
progress.setPossibleLowestTimestamp(Math.min(sample.timestamp, (_a = sample.dts) !== null && _a !== void 0 ? _a : Infinity, (_b = sample.cts) !== null && _b !== void 0 ? _b : Infinity));
|
|
62
64
|
await ioSynchronizer.waitFor({
|
|
63
65
|
unemitted: 20,
|
|
64
|
-
|
|
66
|
+
unprocessed: 2,
|
|
65
67
|
minimumProgress: sample.timestamp - 5000000,
|
|
68
|
+
signal,
|
|
66
69
|
});
|
|
67
70
|
if (sample.type === 'key') {
|
|
68
71
|
await videoDecoder.flush();
|
|
@@ -79,7 +82,7 @@ const createVideoDecoder = ({ onFrame, onError, signal, config, logLevel, progre
|
|
|
79
82
|
waitForFinish: async () => {
|
|
80
83
|
await videoDecoder.flush();
|
|
81
84
|
log_1.Log.verbose(logLevel, 'Flushed video decoder');
|
|
82
|
-
await ioSynchronizer.waitForFinish();
|
|
85
|
+
await ioSynchronizer.waitForFinish(signal);
|
|
83
86
|
log_1.Log.verbose(logLevel, 'IO synchro finished');
|
|
84
87
|
await outputQueue;
|
|
85
88
|
log_1.Log.verbose(logLevel, 'Output queue finished');
|
package/dist/video-encoder.js
CHANGED
|
@@ -57,11 +57,13 @@ const createVideoEncoder = ({ onChunk, onError, signal, config, logLevel, output
|
|
|
57
57
|
if (encoder.state === 'closed') {
|
|
58
58
|
return;
|
|
59
59
|
}
|
|
60
|
+
progress.setPossibleLowestTimestamp(frame.timestamp);
|
|
60
61
|
await ioSynchronizer.waitFor({
|
|
61
62
|
// Firefox stalls if too few frames are passed
|
|
62
63
|
unemitted: 10,
|
|
63
|
-
|
|
64
|
+
unprocessed: 10,
|
|
64
65
|
minimumProgress: frame.timestamp - 5000000,
|
|
66
|
+
signal,
|
|
65
67
|
});
|
|
66
68
|
// @ts-expect-error - can have changed in the meanwhile
|
|
67
69
|
if (encoder.state === 'closed') {
|
|
@@ -83,7 +85,7 @@ const createVideoEncoder = ({ onChunk, onError, signal, config, logLevel, output
|
|
|
83
85
|
waitForFinish: async () => {
|
|
84
86
|
await encoder.flush();
|
|
85
87
|
await outputQueue;
|
|
86
|
-
await ioSynchronizer.waitForFinish();
|
|
88
|
+
await ioSynchronizer.waitForFinish(signal);
|
|
87
89
|
},
|
|
88
90
|
close,
|
|
89
91
|
flush: async () => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remotion/webcodecs",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.239",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"module": "dist/esm/index.mjs",
|
|
@@ -17,14 +17,14 @@
|
|
|
17
17
|
"author": "Jonny Burger <jonny@remotion.dev>",
|
|
18
18
|
"license": "Remotion License (See https://remotion.dev/docs/webcodecs#license)",
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@remotion/media-parser": "4.0.
|
|
20
|
+
"@remotion/media-parser": "4.0.239"
|
|
21
21
|
},
|
|
22
22
|
"peerDependencies": {},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@types/dom-webcodecs": "0.1.11",
|
|
25
25
|
"eslint": "9.14.0",
|
|
26
|
-
"@remotion/
|
|
27
|
-
"@remotion/
|
|
26
|
+
"@remotion/eslint-config-internal": "4.0.239",
|
|
27
|
+
"@remotion/example-videos": "4.0.239"
|
|
28
28
|
},
|
|
29
29
|
"keywords": [],
|
|
30
30
|
"publishConfig": {
|
package/dist/codec-id.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
declare const availableContainers: readonly ["webm", "mp4", "wav"];
|
|
2
|
-
export type ConvertMediaContainer = (typeof availableContainers)[number];
|
|
3
|
-
export declare const getAvailableContainers: () => readonly ConvertMediaContainer[];
|
|
4
|
-
declare const availableVideoCodecs: readonly ["vp8", "vp9", "h264"];
|
|
5
|
-
export type ConvertMediaVideoCodec = (typeof availableVideoCodecs)[number];
|
|
6
|
-
export declare const getAvailableVideoCodecs: (container: ConvertMediaContainer) => ConvertMediaVideoCodec[];
|
|
7
|
-
declare const availableAudioCodecs: readonly ["opus", "aac", "wav"];
|
|
8
|
-
export declare const getAvailableAudioCodecs: (container: ConvertMediaContainer) => ConvertMediaAudioCodec[];
|
|
9
|
-
export type ConvertMediaAudioCodec = (typeof availableAudioCodecs)[number];
|
|
10
|
-
export {};
|
package/dist/codec-id.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getAvailableAudioCodecs = exports.getAvailableVideoCodecs = exports.getAvailableContainers = void 0;
|
|
4
|
-
const availableContainers = ['webm', 'mp4', 'wav'];
|
|
5
|
-
const getAvailableContainers = () => {
|
|
6
|
-
return availableContainers;
|
|
7
|
-
};
|
|
8
|
-
exports.getAvailableContainers = getAvailableContainers;
|
|
9
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
10
|
-
const availableVideoCodecs = ['vp8', 'vp9', 'h264'];
|
|
11
|
-
const getAvailableVideoCodecs = (container) => {
|
|
12
|
-
if (container === 'mp4') {
|
|
13
|
-
return ['h264'];
|
|
14
|
-
}
|
|
15
|
-
if (container === 'webm') {
|
|
16
|
-
return ['vp8', 'vp9'];
|
|
17
|
-
}
|
|
18
|
-
if (container === 'wav') {
|
|
19
|
-
return [];
|
|
20
|
-
}
|
|
21
|
-
throw new Error(`Unsupported container: ${container}`);
|
|
22
|
-
};
|
|
23
|
-
exports.getAvailableVideoCodecs = getAvailableVideoCodecs;
|
|
24
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
25
|
-
const availableAudioCodecs = ['opus', 'aac', 'wav'];
|
|
26
|
-
const getAvailableAudioCodecs = (container) => {
|
|
27
|
-
if (container === 'mp4') {
|
|
28
|
-
return ['aac'];
|
|
29
|
-
}
|
|
30
|
-
if (container === 'webm') {
|
|
31
|
-
return ['opus'];
|
|
32
|
-
}
|
|
33
|
-
if (container === 'wav') {
|
|
34
|
-
return ['wav'];
|
|
35
|
-
}
|
|
36
|
-
throw new Error(`Unsupported container: ${container}`);
|
|
37
|
-
};
|
|
38
|
-
exports.getAvailableAudioCodecs = getAvailableAudioCodecs;
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* bytes 17,144: 00010 001 | 1 0010 000
|
|
3
|
-
^^^^^ ^^^ ^ ^^^^ ^
|
|
4
|
-
| | | | padding
|
|
5
|
-
| | |
|
|
6
|
-
| | +-- channelConfiguration (2)
|
|
7
|
-
| +-- samplingFrequencyIndex (3)
|
|
8
|
-
+-- audioConfigType (2)
|
|
9
|
-
*/
|
|
10
|
-
export declare const createAacCodecPrivate: ({ audioObjectType, sampleRate, channelConfiguration, }: {
|
|
11
|
-
audioObjectType: number;
|
|
12
|
-
sampleRate: number;
|
|
13
|
-
channelConfiguration: number;
|
|
14
|
-
}) => Uint8Array;
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
// codec private, for example [17, 144]
|
|
3
|
-
// audioObjectType = 2 = 'AAC LC'
|
|
4
|
-
// samplingFrequencyIndex = 3 = '48000 Hz'
|
|
5
|
-
// channelConfiguration = 2 = '2 channels'
|
|
6
|
-
/**
|
|
7
|
-
* bytes 17,144: 00010 001 | 1 0010 000
|
|
8
|
-
^^^^^ ^^^ ^ ^^^^ ^
|
|
9
|
-
| | | | padding
|
|
10
|
-
| | |
|
|
11
|
-
| | +-- channelConfiguration (2)
|
|
12
|
-
| +-- samplingFrequencyIndex (3)
|
|
13
|
-
+-- audioConfigType (2)
|
|
14
|
-
*/
|
|
15
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
-
exports.createAacCodecPrivate = void 0;
|
|
17
|
-
// https://wiki.multimedia.cx/index.php/MPEG-4_Audio#Channel_Configurations
|
|
18
|
-
const getConfigForSampleRate = (sampleRate) => {
|
|
19
|
-
if (sampleRate === 96000) {
|
|
20
|
-
return 0;
|
|
21
|
-
}
|
|
22
|
-
if (sampleRate === 88200) {
|
|
23
|
-
return 1;
|
|
24
|
-
}
|
|
25
|
-
if (sampleRate === 64000) {
|
|
26
|
-
return 2;
|
|
27
|
-
}
|
|
28
|
-
if (sampleRate === 48000) {
|
|
29
|
-
return 3;
|
|
30
|
-
}
|
|
31
|
-
if (sampleRate === 44100) {
|
|
32
|
-
return 4;
|
|
33
|
-
}
|
|
34
|
-
if (sampleRate === 32000) {
|
|
35
|
-
return 5;
|
|
36
|
-
}
|
|
37
|
-
if (sampleRate === 24000) {
|
|
38
|
-
return 6;
|
|
39
|
-
}
|
|
40
|
-
if (sampleRate === 22050) {
|
|
41
|
-
return 7;
|
|
42
|
-
}
|
|
43
|
-
if (sampleRate === 16000) {
|
|
44
|
-
return 8;
|
|
45
|
-
}
|
|
46
|
-
if (sampleRate === 12000) {
|
|
47
|
-
return 9;
|
|
48
|
-
}
|
|
49
|
-
if (sampleRate === 11025) {
|
|
50
|
-
return 10;
|
|
51
|
-
}
|
|
52
|
-
if (sampleRate === 8000) {
|
|
53
|
-
return 11;
|
|
54
|
-
}
|
|
55
|
-
if (sampleRate === 7350) {
|
|
56
|
-
return 12;
|
|
57
|
-
}
|
|
58
|
-
throw new Error(`Unexpected sample rate ${sampleRate}`);
|
|
59
|
-
};
|
|
60
|
-
const createAacCodecPrivate = ({ audioObjectType, sampleRate, channelConfiguration, }) => {
|
|
61
|
-
const bits = `${audioObjectType.toString(2).padStart(5, '0')}${getConfigForSampleRate(sampleRate).toString(2).padStart(4, '0')}${channelConfiguration.toString(2).padStart(4, '0')}000`;
|
|
62
|
-
if (bits.length !== 16) {
|
|
63
|
-
throw new Error('Invalid AAC codec private ' + bits.length);
|
|
64
|
-
}
|
|
65
|
-
if (channelConfiguration === 0 || channelConfiguration > 7) {
|
|
66
|
-
throw new Error('Invalid channel configuration ' + channelConfiguration);
|
|
67
|
-
}
|
|
68
|
-
const firstByte = parseInt(bits.slice(0, 8), 2);
|
|
69
|
-
const secondByte = parseInt(bits.slice(8, 16), 2);
|
|
70
|
-
return new Uint8Array([firstByte, secondByte]);
|
|
71
|
-
};
|
|
72
|
-
exports.createAacCodecPrivate = createAacCodecPrivate;
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
type Input = {
|
|
2
|
-
timestamp: number;
|
|
3
|
-
keyFrame: boolean;
|
|
4
|
-
};
|
|
5
|
-
type Output = {
|
|
6
|
-
timestamp: number;
|
|
7
|
-
};
|
|
8
|
-
type Processed = {};
|
|
9
|
-
type Progress = {
|
|
10
|
-
smallestProgress: number;
|
|
11
|
-
};
|
|
12
|
-
type IoEventMap = {
|
|
13
|
-
input: Input;
|
|
14
|
-
output: Output;
|
|
15
|
-
processed: Processed;
|
|
16
|
-
progress: Progress;
|
|
17
|
-
};
|
|
18
|
-
export type IoEventTypes = keyof IoEventMap;
|
|
19
|
-
export type CallbackListener<T extends IoEventTypes> = (data: {
|
|
20
|
-
detail: IoEventMap[T];
|
|
21
|
-
}) => void;
|
|
22
|
-
type IoListeners = {
|
|
23
|
-
[EventType in IoEventTypes]: CallbackListener<EventType>[];
|
|
24
|
-
};
|
|
25
|
-
export declare class IoEventEmitter {
|
|
26
|
-
listeners: IoListeners;
|
|
27
|
-
addEventListener<Q extends IoEventTypes>(name: Q, callback: CallbackListener<Q>): void;
|
|
28
|
-
removeEventListener<Q extends IoEventTypes>(name: Q, callback: CallbackListener<Q>): void;
|
|
29
|
-
dispatchEvent<T extends IoEventTypes>(dispatchName: T, context: IoEventMap[T]): void;
|
|
30
|
-
}
|
|
31
|
-
export {};
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.IoEventEmitter = void 0;
|
|
4
|
-
class IoEventEmitter {
|
|
5
|
-
constructor() {
|
|
6
|
-
this.listeners = {
|
|
7
|
-
input: [],
|
|
8
|
-
output: [],
|
|
9
|
-
processed: [],
|
|
10
|
-
progress: [],
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
addEventListener(name, callback) {
|
|
14
|
-
this.listeners[name].push(callback);
|
|
15
|
-
}
|
|
16
|
-
removeEventListener(name, callback) {
|
|
17
|
-
this.listeners[name] = this.listeners[name].filter((l) => l !== callback);
|
|
18
|
-
}
|
|
19
|
-
dispatchEvent(dispatchName, context) {
|
|
20
|
-
this.listeners[dispatchName].forEach((callback) => {
|
|
21
|
-
callback({ detail: context });
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
exports.IoEventEmitter = IoEventEmitter;
|
package/dist/rotate-video.d.ts
DELETED
package/dist/rotate-video.js
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.rotateVideo = void 0;
|
|
4
|
-
const rotation_1 = require("./rotation");
|
|
5
|
-
const rotateVideo = ({ frame, rotation, }) => {
|
|
6
|
-
const normalized = ((rotation % 360) + 360) % 360;
|
|
7
|
-
if (normalized % 360 === 0) {
|
|
8
|
-
return frame;
|
|
9
|
-
}
|
|
10
|
-
if (normalized % 90 !== 0) {
|
|
11
|
-
throw new Error('Only 90 degree rotations are supported');
|
|
12
|
-
}
|
|
13
|
-
const { height, width } = (0, rotation_1.calculateNewDimensionsFromDimensions)({
|
|
14
|
-
height: frame.displayHeight,
|
|
15
|
-
width: frame.displayWidth,
|
|
16
|
-
rotation,
|
|
17
|
-
});
|
|
18
|
-
const canvas = new OffscreenCanvas(width, height);
|
|
19
|
-
const ctx = canvas.getContext('2d');
|
|
20
|
-
if (!ctx) {
|
|
21
|
-
throw new Error('Could not get 2d context');
|
|
22
|
-
}
|
|
23
|
-
canvas.width = width;
|
|
24
|
-
canvas.height = height;
|
|
25
|
-
if (normalized === 90) {
|
|
26
|
-
ctx.translate(width, 0);
|
|
27
|
-
}
|
|
28
|
-
else if (normalized === 180) {
|
|
29
|
-
ctx.translate(width, height);
|
|
30
|
-
}
|
|
31
|
-
else if (normalized === 270) {
|
|
32
|
-
ctx.translate(0, height);
|
|
33
|
-
}
|
|
34
|
-
ctx.rotate(normalized * (Math.PI / 180));
|
|
35
|
-
ctx.drawImage(frame, 0, 0);
|
|
36
|
-
return new VideoFrame(canvas, {
|
|
37
|
-
displayHeight: height,
|
|
38
|
-
displayWidth: width,
|
|
39
|
-
duration: frame.duration,
|
|
40
|
-
timestamp: frame.timestamp,
|
|
41
|
-
});
|
|
42
|
-
};
|
|
43
|
-
exports.rotateVideo = rotateVideo;
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const bun_test_1 = require("bun:test");
|
|
4
|
-
const create_aac_codecprivate_1 = require("../create-aac-codecprivate");
|
|
5
|
-
(0, bun_test_1.test)('AACCodecPrivate', () => {
|
|
6
|
-
const codecPrivate = (0, create_aac_codecprivate_1.createAacCodecPrivate)({
|
|
7
|
-
audioObjectType: 2,
|
|
8
|
-
sampleRate: 48000,
|
|
9
|
-
channelConfiguration: 2,
|
|
10
|
-
});
|
|
11
|
-
(0, bun_test_1.expect)(codecPrivate).toEqual(new Uint8Array([17, 144]));
|
|
12
|
-
});
|
package/dist/with-resolvers.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export declare const withResolvers: <T>() => {
|
|
2
|
-
promise: Promise<T>;
|
|
3
|
-
resolve: (value: T | PromiseLike<T>) => void;
|
|
4
|
-
reject: (reason?: any) => void;
|
|
5
|
-
};
|
|
6
|
-
export declare const withResolversAndWaitForReturn: <T>() => {
|
|
7
|
-
getPromiseToImmediatelyReturn: () => Promise<T>;
|
|
8
|
-
reject: (reason: unknown) => void;
|
|
9
|
-
resolve: (value: T | PromiseLike<T>) => void;
|
|
10
|
-
};
|