@remotion/webcodecs 4.0.210
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/LICENSE.md +49 -0
- package/README.md +18 -0
- package/dist/audio-decoder-config.d.ts +2 -0
- package/dist/audio-decoder-config.js +13 -0
- package/dist/audio-decoder.d.ts +15 -0
- package/dist/audio-decoder.js +85 -0
- package/dist/audio-encoder-config.d.ts +2 -0
- package/dist/audio-encoder-config.js +13 -0
- package/dist/audio-encoder.d.ts +16 -0
- package/dist/audio-encoder.js +90 -0
- package/dist/codec-id.d.ts +2 -0
- package/dist/codec-id.js +2 -0
- package/dist/convert-media.d.ts +26 -0
- package/dist/convert-media.js +86 -0
- package/dist/create-audio-decoder.d.ts +7 -0
- package/dist/create-audio-decoder.js +18 -0
- package/dist/create-decoder.d.ts +6 -0
- package/dist/create-decoder.js +32 -0
- package/dist/create-encoder.d.ts +9 -0
- package/dist/create-encoder.js +46 -0
- package/dist/create-video-decoder.d.ts +6 -0
- package/dist/create-video-decoder.js +18 -0
- package/dist/decoder.d.ts +7 -0
- package/dist/decoder.js +44 -0
- package/dist/encoder.d.ts +7 -0
- package/dist/encoder.js +43 -0
- package/dist/error-cause.d.ts +8 -0
- package/dist/error-cause.js +3 -0
- package/dist/esm/index.mjs +793 -0
- package/dist/get-config.d.ts +1 -0
- package/dist/get-config.js +21 -0
- package/dist/get-description.d.ts +6 -0
- package/dist/get-description.js +20 -0
- package/dist/get-samples.d.ts +6 -0
- package/dist/get-samples.js +24 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +13 -0
- package/dist/load-mp4-file.d.ts +8 -0
- package/dist/load-mp4-file.js +37 -0
- package/dist/on-audio-track.d.ts +15 -0
- package/dist/on-audio-track.js +105 -0
- package/dist/on-video-track.d.ts +15 -0
- package/dist/on-video-track.js +101 -0
- package/dist/reencode-video.d.ts +1 -0
- package/dist/reencode-video.js +68 -0
- package/dist/resolve-audio-action.d.ts +16 -0
- package/dist/resolve-audio-action.js +30 -0
- package/dist/resolve-video-action.d.ts +15 -0
- package/dist/resolve-video-action.js +30 -0
- package/dist/video-decoder-config.d.ts +1 -0
- package/dist/video-decoder-config.js +24 -0
- package/dist/video-decoder.d.ts +14 -0
- package/dist/video-decoder.js +87 -0
- package/dist/video-encoder-config.d.ts +1 -0
- package/dist/video-encoder-config.js +24 -0
- package/dist/video-encoder.d.ts +13 -0
- package/dist/video-encoder.js +90 -0
- package/dist/video-parser.d.ts +1 -0
- package/dist/video-parser.js +51 -0
- package/dist/wait-for-dequeue.d.ts +5 -0
- package/dist/wait-for-dequeue.js +51 -0
- package/dist/with-resolvers.d.ts +5 -0
- package/dist/with-resolvers.js +13 -0
- package/package.json +37 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createVideoDecoder = void 0;
|
|
4
|
+
const createVideoDecoder = ({ onFrame, onError, signal, config, }) => {
|
|
5
|
+
let outputQueue = Promise.resolve();
|
|
6
|
+
let outputQueueSize = 0;
|
|
7
|
+
let dequeueResolver = () => { };
|
|
8
|
+
const videoDecoder = new VideoDecoder({
|
|
9
|
+
output(inputFrame) {
|
|
10
|
+
outputQueueSize++;
|
|
11
|
+
outputQueue = outputQueue
|
|
12
|
+
.then(() => onFrame(inputFrame))
|
|
13
|
+
.then(() => {
|
|
14
|
+
outputQueueSize--;
|
|
15
|
+
dequeueResolver();
|
|
16
|
+
return Promise.resolve();
|
|
17
|
+
});
|
|
18
|
+
},
|
|
19
|
+
error(error) {
|
|
20
|
+
onError(error);
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
const close = () => {
|
|
24
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
25
|
+
signal.removeEventListener('abort', onAbort);
|
|
26
|
+
if (videoDecoder.state === 'closed') {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
videoDecoder.close();
|
|
30
|
+
};
|
|
31
|
+
const onAbort = () => {
|
|
32
|
+
close();
|
|
33
|
+
};
|
|
34
|
+
signal.addEventListener('abort', onAbort);
|
|
35
|
+
const getQueueSize = () => {
|
|
36
|
+
return videoDecoder.decodeQueueSize + outputQueueSize;
|
|
37
|
+
};
|
|
38
|
+
videoDecoder.configure(config);
|
|
39
|
+
const waitForDequeue = async () => {
|
|
40
|
+
await new Promise((r) => {
|
|
41
|
+
dequeueResolver = r;
|
|
42
|
+
videoDecoder.addEventListener('dequeue', () => r(), {
|
|
43
|
+
once: true,
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
const waitForFinish = async () => {
|
|
48
|
+
while (getQueueSize() > 0) {
|
|
49
|
+
await waitForDequeue();
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
const processSample = async (sample) => {
|
|
53
|
+
if (videoDecoder.state === 'closed') {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
while (getQueueSize() > 10) {
|
|
57
|
+
await waitForDequeue();
|
|
58
|
+
}
|
|
59
|
+
// @ts-expect-error - can have changed in the meanwhile
|
|
60
|
+
if (videoDecoder.state === 'closed') {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (sample.type === 'key') {
|
|
64
|
+
await videoDecoder.flush();
|
|
65
|
+
}
|
|
66
|
+
videoDecoder.decode(new EncodedVideoChunk(sample));
|
|
67
|
+
};
|
|
68
|
+
let inputQueue = Promise.resolve();
|
|
69
|
+
return {
|
|
70
|
+
processSample: (sample) => {
|
|
71
|
+
inputQueue = inputQueue.then(() => processSample(sample));
|
|
72
|
+
return inputQueue;
|
|
73
|
+
},
|
|
74
|
+
waitForFinish: async () => {
|
|
75
|
+
await videoDecoder.flush();
|
|
76
|
+
await waitForFinish();
|
|
77
|
+
await outputQueue;
|
|
78
|
+
await inputQueue;
|
|
79
|
+
},
|
|
80
|
+
close,
|
|
81
|
+
getQueueSize,
|
|
82
|
+
flush: async () => {
|
|
83
|
+
await videoDecoder.flush();
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
exports.createVideoDecoder = createVideoDecoder;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const getVideoEncoderConfig: (config: VideoEncoderConfig) => Promise<VideoEncoderConfig | null>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getVideoEncoderConfig = void 0;
|
|
4
|
+
const getVideoEncoderConfig = async (config) => {
|
|
5
|
+
if (typeof VideoEncoder === 'undefined') {
|
|
6
|
+
return null;
|
|
7
|
+
}
|
|
8
|
+
const hardware = {
|
|
9
|
+
...config,
|
|
10
|
+
hardwareAcceleration: 'prefer-hardware',
|
|
11
|
+
};
|
|
12
|
+
if ((await VideoEncoder.isConfigSupported(hardware)).supported) {
|
|
13
|
+
return hardware;
|
|
14
|
+
}
|
|
15
|
+
const software = {
|
|
16
|
+
...config,
|
|
17
|
+
hardwareAcceleration: 'prefer-software',
|
|
18
|
+
};
|
|
19
|
+
if ((await VideoEncoder.isConfigSupported(software)).supported) {
|
|
20
|
+
return software;
|
|
21
|
+
}
|
|
22
|
+
return null;
|
|
23
|
+
};
|
|
24
|
+
exports.getVideoEncoderConfig = getVideoEncoderConfig;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type WebCodecsVideoEncoder = {
|
|
2
|
+
encodeFrame: (videoFrame: VideoFrame) => Promise<void>;
|
|
3
|
+
waitForFinish: () => Promise<void>;
|
|
4
|
+
close: () => void;
|
|
5
|
+
getQueueSize: () => number;
|
|
6
|
+
flush: () => Promise<void>;
|
|
7
|
+
};
|
|
8
|
+
export declare const createVideoEncoder: ({ onChunk, onError, signal, config, }: {
|
|
9
|
+
onChunk: (chunk: EncodedVideoChunk) => Promise<void>;
|
|
10
|
+
onError: (error: DOMException) => void;
|
|
11
|
+
signal: AbortSignal;
|
|
12
|
+
config: VideoEncoderConfig;
|
|
13
|
+
}) => WebCodecsVideoEncoder;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createVideoEncoder = void 0;
|
|
4
|
+
const createVideoEncoder = ({ onChunk, onError, signal, config, }) => {
|
|
5
|
+
if (signal.aborted) {
|
|
6
|
+
throw new Error('Not creating video encoder, already aborted');
|
|
7
|
+
}
|
|
8
|
+
let outputQueue = Promise.resolve();
|
|
9
|
+
let outputQueueSize = 0;
|
|
10
|
+
let dequeueResolver = () => { };
|
|
11
|
+
const encoder = new VideoEncoder({
|
|
12
|
+
error(error) {
|
|
13
|
+
onError(error);
|
|
14
|
+
},
|
|
15
|
+
output(chunk) {
|
|
16
|
+
outputQueueSize++;
|
|
17
|
+
outputQueue = outputQueue
|
|
18
|
+
.then(() => onChunk(chunk))
|
|
19
|
+
.then(() => {
|
|
20
|
+
outputQueueSize--;
|
|
21
|
+
dequeueResolver();
|
|
22
|
+
return Promise.resolve();
|
|
23
|
+
});
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
const close = () => {
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
28
|
+
signal.removeEventListener('abort', onAbort);
|
|
29
|
+
if (encoder.state === 'closed') {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
encoder.close();
|
|
33
|
+
};
|
|
34
|
+
const onAbort = () => {
|
|
35
|
+
close();
|
|
36
|
+
};
|
|
37
|
+
signal.addEventListener('abort', onAbort);
|
|
38
|
+
const getQueueSize = () => {
|
|
39
|
+
return encoder.encodeQueueSize + outputQueueSize;
|
|
40
|
+
};
|
|
41
|
+
encoder.configure(config);
|
|
42
|
+
let framesProcessed = 0;
|
|
43
|
+
const waitForDequeue = async () => {
|
|
44
|
+
await new Promise((r) => {
|
|
45
|
+
dequeueResolver = r;
|
|
46
|
+
encoder.addEventListener('dequeue', () => r(), {
|
|
47
|
+
once: true,
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
const waitForFinish = async () => {
|
|
52
|
+
while (getQueueSize() > 0) {
|
|
53
|
+
await waitForDequeue();
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
const encodeFrame = async (frame) => {
|
|
57
|
+
if (encoder.state === 'closed') {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
while (getQueueSize() > 10) {
|
|
61
|
+
await waitForDequeue();
|
|
62
|
+
}
|
|
63
|
+
// @ts-expect-error - can have changed in the meanwhile
|
|
64
|
+
if (encoder.state === 'closed') {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
encoder.encode(frame, {
|
|
68
|
+
keyFrame: framesProcessed % 40 === 0,
|
|
69
|
+
});
|
|
70
|
+
framesProcessed++;
|
|
71
|
+
};
|
|
72
|
+
let inputQueue = Promise.resolve();
|
|
73
|
+
return {
|
|
74
|
+
encodeFrame: (frame) => {
|
|
75
|
+
inputQueue = inputQueue.then(() => encodeFrame(frame));
|
|
76
|
+
return inputQueue;
|
|
77
|
+
},
|
|
78
|
+
waitForFinish: async () => {
|
|
79
|
+
await encoder.flush();
|
|
80
|
+
await outputQueue;
|
|
81
|
+
await waitForFinish();
|
|
82
|
+
},
|
|
83
|
+
close,
|
|
84
|
+
getQueueSize,
|
|
85
|
+
flush: async () => {
|
|
86
|
+
await encoder.flush();
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
exports.createVideoEncoder = createVideoEncoder;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const parseVideo: (file: File) => Promise<void>;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseVideo = void 0;
|
|
4
|
+
const media_parser_1 = require("@remotion/media-parser");
|
|
5
|
+
const web_file_1 = require("@remotion/media-parser/web-file");
|
|
6
|
+
const parseVideo = async (file) => {
|
|
7
|
+
const videoDecoder = new VideoDecoder({
|
|
8
|
+
output(inputFrame) {
|
|
9
|
+
console.log('frame', inputFrame);
|
|
10
|
+
inputFrame.close();
|
|
11
|
+
},
|
|
12
|
+
error(error) {
|
|
13
|
+
console.error(error);
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
await (0, media_parser_1.parseMedia)({
|
|
17
|
+
src: file,
|
|
18
|
+
reader: web_file_1.webFileReader,
|
|
19
|
+
onVideoTrack: (track) => {
|
|
20
|
+
videoDecoder.configure({
|
|
21
|
+
...track,
|
|
22
|
+
hardwareAcceleration: 'no-preference',
|
|
23
|
+
});
|
|
24
|
+
return (chunk) => {
|
|
25
|
+
videoDecoder.decode(new EncodedVideoChunk(chunk));
|
|
26
|
+
};
|
|
27
|
+
},
|
|
28
|
+
onAudioTrack: (track) => {
|
|
29
|
+
const audioDecoder = new AudioDecoder({
|
|
30
|
+
output(inputFrame) {
|
|
31
|
+
console.log('audio frame', inputFrame);
|
|
32
|
+
inputFrame.close();
|
|
33
|
+
},
|
|
34
|
+
error(error) {
|
|
35
|
+
console.error(error);
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
audioDecoder.configure({
|
|
39
|
+
codec: track.codec,
|
|
40
|
+
sampleRate: track.sampleRate,
|
|
41
|
+
numberOfChannels: track.numberOfChannels,
|
|
42
|
+
description: track.description,
|
|
43
|
+
});
|
|
44
|
+
console.log('audio track', track);
|
|
45
|
+
return (audioSample) => {
|
|
46
|
+
audioDecoder.decode(new EncodedAudioChunk(audioSample));
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
exports.parseVideo = parseVideo;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/// <reference types="dom-webcodecs" />
|
|
2
|
+
export declare const decoderWaitForDequeue: (videoDecoder: VideoDecoder | AudioDecoder) => Promise<void>;
|
|
3
|
+
export declare const decoderWaitForFinish: (videoDecoder: VideoDecoder | AudioDecoder) => Promise<void>;
|
|
4
|
+
export declare const encoderWaitForDequeue: (videoEncoder: VideoEncoder | AudioEncoder) => Promise<void>;
|
|
5
|
+
export declare const encoderWaitForFinish: (videoEncoder: VideoEncoder | AudioEncoder) => Promise<void>;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.encoderWaitForFinish = exports.encoderWaitForDequeue = exports.decoderWaitForFinish = exports.decoderWaitForDequeue = void 0;
|
|
4
|
+
const decoderWaitForDequeue = async (videoDecoder) => {
|
|
5
|
+
while (videoDecoder.decodeQueueSize > 10) {
|
|
6
|
+
await new Promise((r) => {
|
|
7
|
+
// @ts-expect-error exists
|
|
8
|
+
videoDecoder.addEventListener('dequeue', () => r(), {
|
|
9
|
+
once: true,
|
|
10
|
+
});
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
exports.decoderWaitForDequeue = decoderWaitForDequeue;
|
|
15
|
+
const decoderWaitForFinish = async (videoDecoder) => {
|
|
16
|
+
while (videoDecoder.decodeQueueSize > 0) {
|
|
17
|
+
await new Promise((r) => {
|
|
18
|
+
// @ts-expect-error exists
|
|
19
|
+
videoDecoder.addEventListener('dequeue', () => r(), {
|
|
20
|
+
once: true,
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
await videoDecoder.flush();
|
|
25
|
+
};
|
|
26
|
+
exports.decoderWaitForFinish = decoderWaitForFinish;
|
|
27
|
+
// Queue goes way higher but this will eat more memory right?
|
|
28
|
+
// But if not done this way, quality is worse
|
|
29
|
+
const encoderWaitForDequeue = async (videoEncoder) => {
|
|
30
|
+
while (videoEncoder.encodeQueueSize > 10) {
|
|
31
|
+
await new Promise((r) => {
|
|
32
|
+
// @ts-expect-error exists
|
|
33
|
+
videoEncoder.addEventListener('dequeue', () => r(), {
|
|
34
|
+
once: true,
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
exports.encoderWaitForDequeue = encoderWaitForDequeue;
|
|
40
|
+
const encoderWaitForFinish = async (videoEncoder) => {
|
|
41
|
+
while (videoEncoder.encodeQueueSize > 0) {
|
|
42
|
+
await new Promise((r) => {
|
|
43
|
+
// @ts-expect-error exists
|
|
44
|
+
videoEncoder.addEventListener('dequeue', () => r(), {
|
|
45
|
+
once: true,
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
await videoEncoder.flush();
|
|
50
|
+
};
|
|
51
|
+
exports.encoderWaitForFinish = encoderWaitForFinish;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.withResolvers = void 0;
|
|
4
|
+
const withResolvers = function () {
|
|
5
|
+
let resolve;
|
|
6
|
+
let reject;
|
|
7
|
+
const promise = new Promise((res, rej) => {
|
|
8
|
+
resolve = res;
|
|
9
|
+
reject = rej;
|
|
10
|
+
});
|
|
11
|
+
return { promise, resolve: resolve, reject: reject };
|
|
12
|
+
};
|
|
13
|
+
exports.withResolvers = withResolvers;
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@remotion/webcodecs",
|
|
3
|
+
"version": "4.0.210",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"types": "dist/index.d.ts",
|
|
6
|
+
"module": "dist/esm/index.mjs",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"repository": {
|
|
9
|
+
"url": "https://github.com/remotion-dev/remotion/tree/main/packages/webcodecs"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/remotion-dev/remotion/issues"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"author": "Jonny Burger <jonny@remotion.dev>",
|
|
18
|
+
"license": "SEE LICENSE IN LICENSE.md",
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@remotion/media-parser": "4.0.210"
|
|
21
|
+
},
|
|
22
|
+
"peerDependencies": {},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@types/dom-webcodecs": "0.1.11"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [],
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public"
|
|
29
|
+
},
|
|
30
|
+
"description": "Media conversion in the browser",
|
|
31
|
+
"scripts": {
|
|
32
|
+
"formatting": "prettier src --check",
|
|
33
|
+
"lint": "eslint src --ext ts,tsx",
|
|
34
|
+
"build": "tsc -d && bun --env-file=../.env.bundle bundle.ts",
|
|
35
|
+
"watch": "tsc -w"
|
|
36
|
+
}
|
|
37
|
+
}
|