@remotion/webcodecs 4.0.266 → 4.0.268
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.
|
@@ -19,7 +19,7 @@ export type EbmlParsedOrUint8Array<T extends Ebml> = {
|
|
|
19
19
|
value: EbmlValueOrUint8Array<T>;
|
|
20
20
|
minVintWidth: number | null;
|
|
21
21
|
};
|
|
22
|
-
export declare const measureEBMLVarInt: (value: number) => 2 | 1 |
|
|
22
|
+
export declare const measureEBMLVarInt: (value: number) => 2 | 1 | 5 | 4 | 3 | 6;
|
|
23
23
|
export declare const getVariableInt: (value: number, minWidth: number | null) => Uint8Array;
|
|
24
24
|
export declare const makeMatroskaBytes: (fields: PossibleEbmlOrUint8Array) => BytesAndOffset;
|
|
25
25
|
export type PossibleEbmlOrUint8Array = Prettify<{
|
package/dist/esm/index.mjs
CHANGED
|
@@ -1954,6 +1954,59 @@ var onFrame = async ({
|
|
|
1954
1954
|
}
|
|
1955
1955
|
};
|
|
1956
1956
|
|
|
1957
|
+
// src/sort-video-frames.ts
|
|
1958
|
+
var MAX_QUEUE_SIZE = 5;
|
|
1959
|
+
var videoFrameSorter = ({
|
|
1960
|
+
onRelease,
|
|
1961
|
+
controller
|
|
1962
|
+
}) => {
|
|
1963
|
+
const frames = [];
|
|
1964
|
+
const releaseFrame = async () => {
|
|
1965
|
+
await controller._internals.checkForAbortAndPause();
|
|
1966
|
+
const frame = frames.shift();
|
|
1967
|
+
if (frame) {
|
|
1968
|
+
await onRelease(frame);
|
|
1969
|
+
}
|
|
1970
|
+
};
|
|
1971
|
+
const sortFrames = () => {
|
|
1972
|
+
frames.sort((a, b) => a.timestamp - b.timestamp);
|
|
1973
|
+
};
|
|
1974
|
+
const releaseIfQueueFull = async () => {
|
|
1975
|
+
if (frames.length >= MAX_QUEUE_SIZE) {
|
|
1976
|
+
sortFrames();
|
|
1977
|
+
await releaseFrame();
|
|
1978
|
+
}
|
|
1979
|
+
};
|
|
1980
|
+
const addFrame = (frame) => {
|
|
1981
|
+
frames.push(frame);
|
|
1982
|
+
};
|
|
1983
|
+
const inputFrame = async (frame) => {
|
|
1984
|
+
addFrame(frame);
|
|
1985
|
+
await releaseIfQueueFull();
|
|
1986
|
+
};
|
|
1987
|
+
const onAbort = () => {
|
|
1988
|
+
while (frames.length > 0) {
|
|
1989
|
+
const frame = frames.shift();
|
|
1990
|
+
if (frame) {
|
|
1991
|
+
frame.close();
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1994
|
+
frames.length = 0;
|
|
1995
|
+
};
|
|
1996
|
+
const flush = async () => {
|
|
1997
|
+
sortFrames();
|
|
1998
|
+
while (frames.length > 0) {
|
|
1999
|
+
await releaseFrame();
|
|
2000
|
+
}
|
|
2001
|
+
controller._internals.signal.removeEventListener("abort", onAbort);
|
|
2002
|
+
};
|
|
2003
|
+
controller._internals.signal.addEventListener("abort", onAbort);
|
|
2004
|
+
return {
|
|
2005
|
+
inputFrame,
|
|
2006
|
+
flush
|
|
2007
|
+
};
|
|
2008
|
+
};
|
|
2009
|
+
|
|
1957
2010
|
// src/video-decoder.ts
|
|
1958
2011
|
var createVideoDecoder = ({
|
|
1959
2012
|
onFrame: onFrame2,
|
|
@@ -1969,28 +2022,38 @@ var createVideoDecoder = ({
|
|
|
1969
2022
|
progress
|
|
1970
2023
|
});
|
|
1971
2024
|
let outputQueue = Promise.resolve();
|
|
2025
|
+
const addToQueue = (frame) => {
|
|
2026
|
+
const cleanup = () => {
|
|
2027
|
+
frame.close();
|
|
2028
|
+
};
|
|
2029
|
+
controller._internals.signal.addEventListener("abort", cleanup, {
|
|
2030
|
+
once: true
|
|
2031
|
+
});
|
|
2032
|
+
outputQueue = outputQueue.then(() => {
|
|
2033
|
+
if (controller._internals.signal.aborted) {
|
|
2034
|
+
return;
|
|
2035
|
+
}
|
|
2036
|
+
return onFrame2(frame);
|
|
2037
|
+
}).then(() => {
|
|
2038
|
+
ioSynchronizer.onProcessed();
|
|
2039
|
+
}).catch((err) => {
|
|
2040
|
+
onError(err);
|
|
2041
|
+
}).finally(() => {
|
|
2042
|
+
controller._internals.signal.removeEventListener("abort", cleanup);
|
|
2043
|
+
cleanup();
|
|
2044
|
+
});
|
|
2045
|
+
return outputQueue;
|
|
2046
|
+
};
|
|
2047
|
+
const frameSorter = videoFrameSorter({
|
|
2048
|
+
controller,
|
|
2049
|
+
onRelease: async (frame) => {
|
|
2050
|
+
await addToQueue(frame);
|
|
2051
|
+
}
|
|
2052
|
+
});
|
|
1972
2053
|
const videoDecoder = new VideoDecoder({
|
|
1973
|
-
output(
|
|
1974
|
-
ioSynchronizer.onOutput(
|
|
1975
|
-
|
|
1976
|
-
inputFrame.close();
|
|
1977
|
-
};
|
|
1978
|
-
controller._internals.signal.addEventListener("abort", abortHandler, {
|
|
1979
|
-
once: true
|
|
1980
|
-
});
|
|
1981
|
-
outputQueue = outputQueue.then(() => {
|
|
1982
|
-
if (controller._internals.signal.aborted) {
|
|
1983
|
-
return;
|
|
1984
|
-
}
|
|
1985
|
-
return onFrame2(inputFrame);
|
|
1986
|
-
}).then(() => {
|
|
1987
|
-
ioSynchronizer.onProcessed();
|
|
1988
|
-
controller._internals.signal.removeEventListener("abort", abortHandler);
|
|
1989
|
-
return Promise.resolve();
|
|
1990
|
-
}).catch((err) => {
|
|
1991
|
-
inputFrame.close();
|
|
1992
|
-
onError(err);
|
|
1993
|
-
});
|
|
2054
|
+
output(frame) {
|
|
2055
|
+
ioSynchronizer.onOutput(frame.timestamp);
|
|
2056
|
+
frameSorter.inputFrame(frame);
|
|
1994
2057
|
},
|
|
1995
2058
|
error(error) {
|
|
1996
2059
|
onError(error);
|
|
@@ -2018,13 +2081,10 @@ var createVideoDecoder = ({
|
|
|
2018
2081
|
progress.setPossibleLowestTimestamp(Math.min(sample.timestamp, sample.dts ?? Infinity, sample.cts ?? Infinity));
|
|
2019
2082
|
await ioSynchronizer.waitFor({
|
|
2020
2083
|
unemitted: 20,
|
|
2021
|
-
unprocessed:
|
|
2084
|
+
unprocessed: 10,
|
|
2022
2085
|
minimumProgress: sample.timestamp - 1e7,
|
|
2023
2086
|
controller
|
|
2024
2087
|
});
|
|
2025
|
-
if (sample.type === "key") {
|
|
2026
|
-
await videoDecoder.flush();
|
|
2027
|
-
}
|
|
2028
2088
|
videoDecoder.decode(new EncodedVideoChunk(sample));
|
|
2029
2089
|
ioSynchronizer.inputItem(sample.timestamp, sample.type === "key");
|
|
2030
2090
|
};
|
|
@@ -2037,6 +2097,8 @@ var createVideoDecoder = ({
|
|
|
2037
2097
|
waitForFinish: async () => {
|
|
2038
2098
|
await videoDecoder.flush();
|
|
2039
2099
|
Log.verbose(logLevel, "Flushed video decoder");
|
|
2100
|
+
await frameSorter.flush();
|
|
2101
|
+
Log.verbose(logLevel, "Frame sorter flushed");
|
|
2040
2102
|
await ioSynchronizer.waitForFinish(controller);
|
|
2041
2103
|
Log.verbose(logLevel, "IO synchro finished");
|
|
2042
2104
|
await outputQueue;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { WebCodecsController } from './webcodecs-controller';
|
|
2
|
+
export declare const videoFrameSorter: ({ onRelease, controller, }: {
|
|
3
|
+
onRelease: (frame: VideoFrame) => Promise<void>;
|
|
4
|
+
controller: WebCodecsController;
|
|
5
|
+
}) => {
|
|
6
|
+
inputFrame: (frame: VideoFrame) => Promise<void>;
|
|
7
|
+
flush: () => Promise<void>;
|
|
8
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.videoFrameSorter = void 0;
|
|
4
|
+
const MAX_QUEUE_SIZE = 5;
|
|
5
|
+
const videoFrameSorter = ({ onRelease, controller, }) => {
|
|
6
|
+
const frames = [];
|
|
7
|
+
const releaseFrame = async () => {
|
|
8
|
+
await controller._internals.checkForAbortAndPause();
|
|
9
|
+
const frame = frames.shift();
|
|
10
|
+
if (frame) {
|
|
11
|
+
await onRelease(frame);
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
const sortFrames = () => {
|
|
15
|
+
frames.sort((a, b) => a.timestamp - b.timestamp);
|
|
16
|
+
};
|
|
17
|
+
const releaseIfQueueFull = async () => {
|
|
18
|
+
if (frames.length >= MAX_QUEUE_SIZE) {
|
|
19
|
+
sortFrames();
|
|
20
|
+
await releaseFrame();
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
const addFrame = (frame) => {
|
|
24
|
+
frames.push(frame);
|
|
25
|
+
};
|
|
26
|
+
const inputFrame = async (frame) => {
|
|
27
|
+
addFrame(frame);
|
|
28
|
+
await releaseIfQueueFull();
|
|
29
|
+
};
|
|
30
|
+
const onAbort = () => {
|
|
31
|
+
while (frames.length > 0) {
|
|
32
|
+
const frame = frames.shift();
|
|
33
|
+
if (frame) {
|
|
34
|
+
frame.close();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
frames.length = 0;
|
|
38
|
+
};
|
|
39
|
+
const flush = async () => {
|
|
40
|
+
sortFrames();
|
|
41
|
+
while (frames.length > 0) {
|
|
42
|
+
await releaseFrame();
|
|
43
|
+
}
|
|
44
|
+
controller._internals.signal.removeEventListener('abort', onAbort);
|
|
45
|
+
};
|
|
46
|
+
controller._internals.signal.addEventListener('abort', onAbort);
|
|
47
|
+
return {
|
|
48
|
+
inputFrame,
|
|
49
|
+
flush,
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
exports.videoFrameSorter = videoFrameSorter;
|
package/dist/video-decoder.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.createVideoDecoder = void 0;
|
|
4
4
|
const io_synchronizer_1 = require("./io-manager/io-synchronizer");
|
|
5
5
|
const log_1 = require("./log");
|
|
6
|
+
const sort_video_frames_1 = require("./sort-video-frames");
|
|
6
7
|
const createVideoDecoder = ({ onFrame, onError, controller, config, logLevel, progress, }) => {
|
|
7
8
|
const ioSynchronizer = (0, io_synchronizer_1.makeIoSynchronizer)({
|
|
8
9
|
logLevel,
|
|
@@ -10,31 +11,42 @@ const createVideoDecoder = ({ onFrame, onError, controller, config, logLevel, pr
|
|
|
10
11
|
progress,
|
|
11
12
|
});
|
|
12
13
|
let outputQueue = Promise.resolve();
|
|
14
|
+
const addToQueue = (frame) => {
|
|
15
|
+
const cleanup = () => {
|
|
16
|
+
frame.close();
|
|
17
|
+
};
|
|
18
|
+
controller._internals.signal.addEventListener('abort', cleanup, {
|
|
19
|
+
once: true,
|
|
20
|
+
});
|
|
21
|
+
outputQueue = outputQueue
|
|
22
|
+
.then(() => {
|
|
23
|
+
if (controller._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.signal.removeEventListener('abort', cleanup);
|
|
36
|
+
cleanup();
|
|
37
|
+
});
|
|
38
|
+
return outputQueue;
|
|
39
|
+
};
|
|
40
|
+
const frameSorter = (0, sort_video_frames_1.videoFrameSorter)({
|
|
41
|
+
controller,
|
|
42
|
+
onRelease: async (frame) => {
|
|
43
|
+
await addToQueue(frame);
|
|
44
|
+
},
|
|
45
|
+
});
|
|
13
46
|
const videoDecoder = new VideoDecoder({
|
|
14
|
-
output(
|
|
15
|
-
ioSynchronizer.onOutput(
|
|
16
|
-
|
|
17
|
-
inputFrame.close();
|
|
18
|
-
};
|
|
19
|
-
controller._internals.signal.addEventListener('abort', abortHandler, {
|
|
20
|
-
once: true,
|
|
21
|
-
});
|
|
22
|
-
outputQueue = outputQueue
|
|
23
|
-
.then(() => {
|
|
24
|
-
if (controller._internals.signal.aborted) {
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
return onFrame(inputFrame);
|
|
28
|
-
})
|
|
29
|
-
.then(() => {
|
|
30
|
-
ioSynchronizer.onProcessed();
|
|
31
|
-
controller._internals.signal.removeEventListener('abort', abortHandler);
|
|
32
|
-
return Promise.resolve();
|
|
33
|
-
})
|
|
34
|
-
.catch((err) => {
|
|
35
|
-
inputFrame.close();
|
|
36
|
-
onError(err);
|
|
37
|
-
});
|
|
47
|
+
output(frame) {
|
|
48
|
+
ioSynchronizer.onOutput(frame.timestamp);
|
|
49
|
+
frameSorter.inputFrame(frame);
|
|
38
50
|
},
|
|
39
51
|
error(error) {
|
|
40
52
|
onError(error);
|
|
@@ -65,13 +77,14 @@ const createVideoDecoder = ({ onFrame, onError, controller, config, logLevel, pr
|
|
|
65
77
|
progress.setPossibleLowestTimestamp(Math.min(sample.timestamp, (_a = sample.dts) !== null && _a !== void 0 ? _a : Infinity, (_b = sample.cts) !== null && _b !== void 0 ? _b : Infinity));
|
|
66
78
|
await ioSynchronizer.waitFor({
|
|
67
79
|
unemitted: 20,
|
|
68
|
-
unprocessed:
|
|
80
|
+
unprocessed: 10,
|
|
69
81
|
minimumProgress: sample.timestamp - 10000000,
|
|
70
82
|
controller,
|
|
71
83
|
});
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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.
|
|
75
88
|
videoDecoder.decode(new EncodedVideoChunk(sample));
|
|
76
89
|
ioSynchronizer.inputItem(sample.timestamp, sample.type === 'key');
|
|
77
90
|
};
|
|
@@ -84,6 +97,8 @@ const createVideoDecoder = ({ onFrame, onError, controller, config, logLevel, pr
|
|
|
84
97
|
waitForFinish: async () => {
|
|
85
98
|
await videoDecoder.flush();
|
|
86
99
|
log_1.Log.verbose(logLevel, 'Flushed video decoder');
|
|
100
|
+
await frameSorter.flush();
|
|
101
|
+
log_1.Log.verbose(logLevel, 'Frame sorter flushed');
|
|
87
102
|
await ioSynchronizer.waitForFinish(controller);
|
|
88
103
|
log_1.Log.verbose(logLevel, 'IO synchro finished');
|
|
89
104
|
await outputQueue;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remotion/webcodecs",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.268",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"module": "dist/esm/index.mjs",
|
|
@@ -17,15 +17,15 @@
|
|
|
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.
|
|
21
|
-
"@remotion/licensing": "4.0.
|
|
20
|
+
"@remotion/media-parser": "4.0.268",
|
|
21
|
+
"@remotion/licensing": "4.0.268"
|
|
22
22
|
},
|
|
23
23
|
"peerDependencies": {},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@types/dom-webcodecs": "0.1.11",
|
|
26
26
|
"eslint": "9.19.0",
|
|
27
|
-
"@remotion/eslint-config-internal": "4.0.
|
|
28
|
-
"@remotion/example-videos": "4.0.
|
|
27
|
+
"@remotion/eslint-config-internal": "4.0.268",
|
|
28
|
+
"@remotion/example-videos": "4.0.268"
|
|
29
29
|
},
|
|
30
30
|
"keywords": [],
|
|
31
31
|
"publishConfig": {
|