remotion 4.0.85 → 4.0.87
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/cjs/buffering.d.ts +1 -1
- package/dist/cjs/buffering.js +29 -26
- package/dist/cjs/get-timeline-clip-name.d.ts +1 -0
- package/dist/cjs/get-timeline-clip-name.js +25 -0
- package/dist/cjs/use-buffer.js +2 -2
- package/dist/cjs/use-media-playback.js +1 -3
- package/dist/cjs/version.d.ts +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/cjs/video/VideoForRendering.js +12 -28
- package/dist/cjs/video/get-current-time.d.ts +1 -3
- package/dist/cjs/video/get-current-time.js +2 -15
- package/dist/cjs/video/seek-until-right.d.ts +8 -0
- package/dist/cjs/video/seek-until-right.js +78 -0
- package/dist/esm/index.mjs +89 -46
- package/dist/esm/version.mjs +1 -1
- package/package.json +1 -1
package/dist/cjs/buffering.d.ts
CHANGED
|
@@ -14,10 +14,10 @@ type AddBlock = (block: Block) => {
|
|
|
14
14
|
unblock: () => void;
|
|
15
15
|
};
|
|
16
16
|
type BufferManager = {
|
|
17
|
-
blocks: Block[];
|
|
18
17
|
addBlock: AddBlock;
|
|
19
18
|
listenForBuffering: ListenForBuffering;
|
|
20
19
|
listenForResume: ListenForResume;
|
|
20
|
+
buffering: React.MutableRefObject<boolean>;
|
|
21
21
|
};
|
|
22
22
|
export declare const BufferingContextReact: React.Context<BufferManager | null>;
|
|
23
23
|
export declare const BufferingProvider: React.FC<{
|
package/dist/cjs/buffering.js
CHANGED
|
@@ -26,47 +26,50 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
26
26
|
exports.BufferingProvider = exports.BufferingContextReact = void 0;
|
|
27
27
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
28
28
|
const react_1 = __importStar(require("react"));
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
29
|
+
const useBufferManager = () => {
|
|
30
|
+
const [blocks, setBlocks] = (0, react_1.useState)([]);
|
|
31
|
+
const [onBufferingCallbacks, setOnBufferingCallbacks] = (0, react_1.useState)([]);
|
|
32
|
+
const [onResumeCallbacks, setOnResumeCallbacks] = (0, react_1.useState)([]);
|
|
33
|
+
const buffering = (0, react_1.useRef)(false);
|
|
34
|
+
const addBlock = (0, react_1.useCallback)((block) => {
|
|
35
|
+
setBlocks((b) => [...b, block]);
|
|
36
36
|
return {
|
|
37
37
|
unblock: () => {
|
|
38
|
-
|
|
38
|
+
setBlocks((b) => b.filter((bx) => bx !== block));
|
|
39
39
|
},
|
|
40
40
|
};
|
|
41
|
-
};
|
|
42
|
-
const listenForBuffering = (callback) => {
|
|
43
|
-
|
|
41
|
+
}, []);
|
|
42
|
+
const listenForBuffering = (0, react_1.useCallback)((callback) => {
|
|
43
|
+
setOnBufferingCallbacks((c) => [...c, callback]);
|
|
44
44
|
return {
|
|
45
45
|
remove: () => {
|
|
46
|
-
|
|
46
|
+
setOnBufferingCallbacks((c) => c.filter((cb) => cb !== callback));
|
|
47
47
|
},
|
|
48
48
|
};
|
|
49
|
-
};
|
|
50
|
-
const listenForResume = (callback) => {
|
|
51
|
-
|
|
49
|
+
}, []);
|
|
50
|
+
const listenForResume = (0, react_1.useCallback)((callback) => {
|
|
51
|
+
setOnResumeCallbacks((c) => [...c, callback]);
|
|
52
52
|
return {
|
|
53
53
|
remove: () => {
|
|
54
|
-
|
|
54
|
+
setOnResumeCallbacks((c) => c.filter((cb) => cb !== callback));
|
|
55
55
|
},
|
|
56
56
|
};
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
blocks
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
57
|
+
}, []);
|
|
58
|
+
(0, react_1.useEffect)(() => {
|
|
59
|
+
if (blocks.length > 0) {
|
|
60
|
+
onBufferingCallbacks.forEach((c) => c());
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
onResumeCallbacks.forEach((c) => c());
|
|
64
|
+
}
|
|
65
|
+
}, [blocks, onBufferingCallbacks, onResumeCallbacks]);
|
|
66
|
+
return (0, react_1.useMemo)(() => {
|
|
67
|
+
return { addBlock, listenForBuffering, listenForResume, buffering };
|
|
68
|
+
}, [addBlock, buffering, listenForBuffering, listenForResume]);
|
|
64
69
|
};
|
|
65
70
|
exports.BufferingContextReact = react_1.default.createContext(null);
|
|
66
71
|
const BufferingProvider = ({ children }) => {
|
|
67
|
-
const
|
|
68
|
-
return createBufferManager();
|
|
69
|
-
});
|
|
72
|
+
const bufferManager = useBufferManager();
|
|
70
73
|
return ((0, jsx_runtime_1.jsx)(exports.BufferingContextReact.Provider, { value: bufferManager, children: children }));
|
|
71
74
|
};
|
|
72
75
|
exports.BufferingProvider = BufferingProvider;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const getTimelineClipName: (children: React.ReactNode) => string;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getTimelineClipName = void 0;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
const HIDDEN_NAMES = ['__WEBPACK_DEFAULT_EXPORT__'];
|
|
6
|
+
const getTimelineClipName = (children) => {
|
|
7
|
+
var _a;
|
|
8
|
+
const tree = (_a = react_1.Children.map(children, (ch) => {
|
|
9
|
+
if (!(0, react_1.isValidElement)(ch)) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
// Must be name, not ID
|
|
13
|
+
const name = typeof ch.type !== 'string' && ch.type.name;
|
|
14
|
+
if (name && !HIDDEN_NAMES.includes(name)) {
|
|
15
|
+
return name;
|
|
16
|
+
}
|
|
17
|
+
if (ch.props.children) {
|
|
18
|
+
const chName = (0, exports.getTimelineClipName)(ch.props.children);
|
|
19
|
+
return chName;
|
|
20
|
+
}
|
|
21
|
+
return null;
|
|
22
|
+
})) === null || _a === void 0 ? void 0 : _a.filter(Boolean);
|
|
23
|
+
return (tree === null || tree === void 0 ? void 0 : tree.length) ? tree[0] : '';
|
|
24
|
+
};
|
|
25
|
+
exports.getTimelineClipName = getTimelineClipName;
|
package/dist/cjs/use-buffer.js
CHANGED
|
@@ -8,13 +8,13 @@ const useBuffer = () => {
|
|
|
8
8
|
if (!buffer) {
|
|
9
9
|
throw new TypeError('Can only use useBuffer() inside a Remotion composition');
|
|
10
10
|
}
|
|
11
|
-
return {
|
|
11
|
+
return (0, react_1.useMemo)(() => ({
|
|
12
12
|
delayPlayback: () => {
|
|
13
13
|
const { unblock } = buffer.addBlock({
|
|
14
14
|
id: String(Math.random()),
|
|
15
15
|
});
|
|
16
16
|
return { unblock };
|
|
17
17
|
},
|
|
18
|
-
};
|
|
18
|
+
}), [buffer]);
|
|
19
19
|
};
|
|
20
20
|
exports.useBuffer = useBuffer;
|
|
@@ -57,12 +57,10 @@ const useMediaPlayback = ({ mediaRef, src, mediaType, playbackRate: localPlaybac
|
|
|
57
57
|
mediaRef.current.playbackRate = playbackRateToSet;
|
|
58
58
|
}
|
|
59
59
|
const desiredUnclampedTime = (0, get_current_time_js_1.getMediaTime)({
|
|
60
|
-
fps,
|
|
61
60
|
frame,
|
|
62
|
-
src,
|
|
63
61
|
playbackRate: localPlaybackRate,
|
|
64
62
|
startFrom: -mediaStartsAt,
|
|
65
|
-
|
|
63
|
+
fps,
|
|
66
64
|
});
|
|
67
65
|
const { duration } = mediaRef.current;
|
|
68
66
|
const shouldBeTime = !Number.isNaN(duration) && Number.isFinite(duration)
|
package/dist/cjs/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION = "4.0.
|
|
1
|
+
export declare const VERSION = "4.0.87";
|
package/dist/cjs/version.js
CHANGED
|
@@ -15,8 +15,8 @@ const timeline_position_state_js_1 = require("../timeline-position-state.js");
|
|
|
15
15
|
const use_current_frame_js_1 = require("../use-current-frame.js");
|
|
16
16
|
const use_unsafe_video_config_js_1 = require("../use-unsafe-video-config.js");
|
|
17
17
|
const volume_prop_js_1 = require("../volume-prop.js");
|
|
18
|
-
const warn_about_non_seekable_media_js_1 = require("../warn-about-non-seekable-media.js");
|
|
19
18
|
const get_current_time_js_1 = require("./get-current-time.js");
|
|
19
|
+
const seek_until_right_js_1 = require("./seek-until-right.js");
|
|
20
20
|
const VideoForRenderingForwardFunction = ({ onError, volume: volumeProp, allowAmplificationDuringRender, playbackRate, onDuration, toneFrequency, name, acceptableTimeShiftInSeconds, ...props }, ref) => {
|
|
21
21
|
const absoluteFrame = (0, timeline_position_state_js_1.useTimelinePosition)();
|
|
22
22
|
const frame = (0, use_current_frame_js_1.useCurrentFrame)();
|
|
@@ -96,16 +96,12 @@ const VideoForRenderingForwardFunction = ({ onError, volume: volumeProp, allowAm
|
|
|
96
96
|
if (!current) {
|
|
97
97
|
return;
|
|
98
98
|
}
|
|
99
|
-
const currentTime = ((
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
startFrom: -mediaStartsAt,
|
|
106
|
-
mediaType: 'video',
|
|
107
|
-
});
|
|
108
|
-
})();
|
|
99
|
+
const currentTime = (0, get_current_time_js_1.getMediaTime)({
|
|
100
|
+
frame,
|
|
101
|
+
playbackRate: playbackRate || 1,
|
|
102
|
+
startFrom: -mediaStartsAt,
|
|
103
|
+
fps: videoConfig.fps,
|
|
104
|
+
});
|
|
109
105
|
const handle = (0, delay_render_js_1.delayRender)(`Rendering <Video /> with src="${props.src}"`);
|
|
110
106
|
if (process.env.NODE_ENV === 'test') {
|
|
111
107
|
(0, delay_render_js_1.continueRender)(handle);
|
|
@@ -124,25 +120,13 @@ const VideoForRenderingForwardFunction = ({ onError, volume: volumeProp, allowAm
|
|
|
124
120
|
current.removeEventListener('loadeddata', loadedDataHandler);
|
|
125
121
|
};
|
|
126
122
|
}
|
|
127
|
-
current.currentTime = currentTime;
|
|
128
|
-
const seekedHandler = () => {
|
|
129
|
-
(0, warn_about_non_seekable_media_js_1.warnAboutNonSeekableMedia)(current, 'exception');
|
|
130
|
-
if (window.navigator.platform.startsWith('Mac')) {
|
|
131
|
-
// Improve me: This is ensures frame perfectness but slows down render.
|
|
132
|
-
// Please see this issue for context: https://github.com/remotion-dev/remotion/issues/200
|
|
133
|
-
// Only affects macOS since it uses VideoToolbox decoding.
|
|
134
|
-
setTimeout(() => {
|
|
135
|
-
(0, delay_render_js_1.continueRender)(handle);
|
|
136
|
-
}, 100);
|
|
137
|
-
}
|
|
138
|
-
else {
|
|
139
|
-
(0, delay_render_js_1.continueRender)(handle);
|
|
140
|
-
}
|
|
141
|
-
};
|
|
142
|
-
current.addEventListener('seeked', seekedHandler, { once: true });
|
|
143
123
|
const endedHandler = () => {
|
|
144
124
|
(0, delay_render_js_1.continueRender)(handle);
|
|
145
125
|
};
|
|
126
|
+
const seek = (0, seek_until_right_js_1.seekToTimeMultipleUntilRight)(current, currentTime, videoConfig.fps);
|
|
127
|
+
seek.prom.then(() => {
|
|
128
|
+
(0, delay_render_js_1.continueRender)(handle);
|
|
129
|
+
});
|
|
146
130
|
current.addEventListener('ended', endedHandler, { once: true });
|
|
147
131
|
const errorHandler = () => {
|
|
148
132
|
var _a;
|
|
@@ -162,9 +146,9 @@ const VideoForRenderingForwardFunction = ({ onError, volume: volumeProp, allowAm
|
|
|
162
146
|
current.addEventListener('error', errorHandler, { once: true });
|
|
163
147
|
// If video skips to another frame or unmounts, we clear the created handle
|
|
164
148
|
return () => {
|
|
149
|
+
seek.cancel();
|
|
165
150
|
current.removeEventListener('ended', endedHandler);
|
|
166
151
|
current.removeEventListener('error', errorHandler);
|
|
167
|
-
current.removeEventListener('seeked', seekedHandler);
|
|
168
152
|
(0, delay_render_js_1.continueRender)(handle);
|
|
169
153
|
};
|
|
170
154
|
}, [
|
|
@@ -3,11 +3,9 @@ export declare const getExpectedMediaFrameUncorrected: ({ frame, playbackRate, s
|
|
|
3
3
|
playbackRate: number;
|
|
4
4
|
startFrom: number;
|
|
5
5
|
}) => number;
|
|
6
|
-
export declare const getMediaTime: ({ fps, frame,
|
|
6
|
+
export declare const getMediaTime: ({ fps, frame, playbackRate, startFrom, }: {
|
|
7
7
|
fps: number;
|
|
8
8
|
frame: number;
|
|
9
|
-
src: string;
|
|
10
9
|
playbackRate: number;
|
|
11
10
|
startFrom: number;
|
|
12
|
-
mediaType: 'video' | 'audio';
|
|
13
11
|
}) => number;
|
|
@@ -7,26 +7,13 @@ const getExpectedMediaFrameUncorrected = ({ frame, playbackRate, startFrom, }) =
|
|
|
7
7
|
return (0, interpolate_js_1.interpolate)(frame, [-1, startFrom, startFrom + 1], [-1, startFrom, startFrom + playbackRate]);
|
|
8
8
|
};
|
|
9
9
|
exports.getExpectedMediaFrameUncorrected = getExpectedMediaFrameUncorrected;
|
|
10
|
-
const getMediaTime = ({ fps, frame,
|
|
10
|
+
const getMediaTime = ({ fps, frame, playbackRate, startFrom, }) => {
|
|
11
11
|
const expectedFrame = (0, exports.getExpectedMediaFrameUncorrected)({
|
|
12
12
|
frame,
|
|
13
13
|
playbackRate,
|
|
14
14
|
startFrom,
|
|
15
15
|
});
|
|
16
|
-
const isChrome = typeof window !== 'undefined' &&
|
|
17
|
-
window.navigator.userAgent.match(/Chrome\/([0-9]+)/);
|
|
18
|
-
if (isChrome &&
|
|
19
|
-
Number(isChrome[1]) < 112 &&
|
|
20
|
-
mediaType === 'video' &&
|
|
21
|
-
src.endsWith('.mp4')) {
|
|
22
|
-
// In Chrome, for MP4s, if 30fps, the first frame is still displayed at 0.033333
|
|
23
|
-
// even though after that it increases by 0.033333333 each.
|
|
24
|
-
// So frame = 0 in Remotion is like frame = 1 for the browser
|
|
25
|
-
return (expectedFrame + 1) / fps;
|
|
26
|
-
}
|
|
27
|
-
// For WebM videos, we need to add a little bit of shift to get the right frame.
|
|
28
16
|
const msPerFrame = 1000 / fps;
|
|
29
|
-
|
|
30
|
-
return (expectedFrame * msPerFrame + msShift) / 1000;
|
|
17
|
+
return (expectedFrame * msPerFrame) / 1000;
|
|
31
18
|
};
|
|
32
19
|
exports.getMediaTime = getMediaTime;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const seekToTime: (element: HTMLVideoElement, desiredTime: number) => {
|
|
2
|
+
wait: Promise<number>;
|
|
3
|
+
cancel: () => void;
|
|
4
|
+
};
|
|
5
|
+
export declare const seekToTimeMultipleUntilRight: (element: HTMLVideoElement, desiredTime: number, fps: number) => {
|
|
6
|
+
prom: Promise<void>;
|
|
7
|
+
cancel: () => void;
|
|
8
|
+
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.seekToTimeMultipleUntilRight = exports.seekToTime = void 0;
|
|
4
|
+
const seekToTime = (element, desiredTime) => {
|
|
5
|
+
element.currentTime = desiredTime;
|
|
6
|
+
let cancel;
|
|
7
|
+
let cancelSeeked = null;
|
|
8
|
+
const prom = new Promise((resolve) => {
|
|
9
|
+
cancel = element.requestVideoFrameCallback((now, metadata) => {
|
|
10
|
+
const displayIn = metadata.expectedDisplayTime - now;
|
|
11
|
+
if (displayIn <= 0) {
|
|
12
|
+
resolve(metadata.mediaTime);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
setTimeout(() => {
|
|
16
|
+
resolve(metadata.mediaTime);
|
|
17
|
+
}, displayIn + 150);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
const waitForSeekedEvent = new Promise((resolve) => {
|
|
21
|
+
const onDone = () => {
|
|
22
|
+
resolve();
|
|
23
|
+
};
|
|
24
|
+
element.addEventListener('seeked', onDone, {
|
|
25
|
+
once: true,
|
|
26
|
+
});
|
|
27
|
+
cancelSeeked = () => {
|
|
28
|
+
element.removeEventListener('seeked', onDone);
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
return {
|
|
32
|
+
wait: Promise.all([prom, waitForSeekedEvent]).then(([time]) => time),
|
|
33
|
+
cancel: () => {
|
|
34
|
+
cancelSeeked === null || cancelSeeked === void 0 ? void 0 : cancelSeeked();
|
|
35
|
+
element.cancelVideoFrameCallback(cancel);
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
exports.seekToTime = seekToTime;
|
|
40
|
+
const seekToTimeMultipleUntilRight = (element, desiredTime, fps) => {
|
|
41
|
+
const threshold = 1 / fps / 2;
|
|
42
|
+
let currentCancel = () => undefined;
|
|
43
|
+
const prom = new Promise((resolve, reject) => {
|
|
44
|
+
const firstSeek = (0, exports.seekToTime)(element, desiredTime + threshold);
|
|
45
|
+
firstSeek.wait.then((seekedTo) => {
|
|
46
|
+
const difference = Math.abs(desiredTime - seekedTo);
|
|
47
|
+
if (difference < threshold) {
|
|
48
|
+
return resolve();
|
|
49
|
+
}
|
|
50
|
+
const sign = desiredTime > seekedTo ? 1 : -1;
|
|
51
|
+
const newSeek = (0, exports.seekToTime)(element, seekedTo + threshold * sign);
|
|
52
|
+
currentCancel = newSeek.cancel;
|
|
53
|
+
newSeek.wait
|
|
54
|
+
.then((newTime) => {
|
|
55
|
+
const newDifference = Math.abs(desiredTime - newTime);
|
|
56
|
+
if (newDifference < threshold) {
|
|
57
|
+
return resolve();
|
|
58
|
+
}
|
|
59
|
+
const thirdSeek = (0, exports.seekToTime)(element, desiredTime);
|
|
60
|
+
currentCancel = thirdSeek.cancel;
|
|
61
|
+
thirdSeek.wait.then(() => {
|
|
62
|
+
resolve();
|
|
63
|
+
});
|
|
64
|
+
})
|
|
65
|
+
.catch((err) => {
|
|
66
|
+
reject(err);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
currentCancel = firstSeek.cancel;
|
|
70
|
+
});
|
|
71
|
+
return {
|
|
72
|
+
prom,
|
|
73
|
+
cancel: () => {
|
|
74
|
+
currentCancel();
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
exports.seekToTimeMultipleUntilRight = seekToTimeMultipleUntilRight;
|
package/dist/esm/index.mjs
CHANGED
|
@@ -132,7 +132,7 @@ function truthy(value) {
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
// Automatically generated on publish
|
|
135
|
-
const VERSION = '4.0.
|
|
135
|
+
const VERSION = '4.0.87';
|
|
136
136
|
|
|
137
137
|
const checkMultipleRemotionVersions = () => {
|
|
138
138
|
if (typeof globalThis === 'undefined') {
|
|
@@ -1843,27 +1843,14 @@ function interpolate(input, inputRange, outputRange, options) {
|
|
|
1843
1843
|
const getExpectedMediaFrameUncorrected = ({ frame, playbackRate, startFrom, }) => {
|
|
1844
1844
|
return interpolate(frame, [-1, startFrom, startFrom + 1], [-1, startFrom, startFrom + playbackRate]);
|
|
1845
1845
|
};
|
|
1846
|
-
const getMediaTime = ({ fps, frame,
|
|
1846
|
+
const getMediaTime = ({ fps, frame, playbackRate, startFrom, }) => {
|
|
1847
1847
|
const expectedFrame = getExpectedMediaFrameUncorrected({
|
|
1848
1848
|
frame,
|
|
1849
1849
|
playbackRate,
|
|
1850
1850
|
startFrom,
|
|
1851
1851
|
});
|
|
1852
|
-
const isChrome = typeof window !== 'undefined' &&
|
|
1853
|
-
window.navigator.userAgent.match(/Chrome\/([0-9]+)/);
|
|
1854
|
-
if (isChrome &&
|
|
1855
|
-
Number(isChrome[1]) < 112 &&
|
|
1856
|
-
mediaType === 'video' &&
|
|
1857
|
-
src.endsWith('.mp4')) {
|
|
1858
|
-
// In Chrome, for MP4s, if 30fps, the first frame is still displayed at 0.033333
|
|
1859
|
-
// even though after that it increases by 0.033333333 each.
|
|
1860
|
-
// So frame = 0 in Remotion is like frame = 1 for the browser
|
|
1861
|
-
return (expectedFrame + 1) / fps;
|
|
1862
|
-
}
|
|
1863
|
-
// For WebM videos, we need to add a little bit of shift to get the right frame.
|
|
1864
1852
|
const msPerFrame = 1000 / fps;
|
|
1865
|
-
|
|
1866
|
-
return (expectedFrame * msPerFrame + msShift) / 1000;
|
|
1853
|
+
return (expectedFrame * msPerFrame) / 1000;
|
|
1867
1854
|
};
|
|
1868
1855
|
|
|
1869
1856
|
const toSeconds = (time, fps) => {
|
|
@@ -2009,12 +1996,10 @@ const useMediaPlayback = ({ mediaRef, src, mediaType, playbackRate: localPlaybac
|
|
|
2009
1996
|
mediaRef.current.playbackRate = playbackRateToSet;
|
|
2010
1997
|
}
|
|
2011
1998
|
const desiredUnclampedTime = getMediaTime({
|
|
2012
|
-
fps,
|
|
2013
1999
|
frame,
|
|
2014
|
-
src,
|
|
2015
2000
|
playbackRate: localPlaybackRate,
|
|
2016
2001
|
startFrom: -mediaStartsAt,
|
|
2017
|
-
|
|
2002
|
+
fps,
|
|
2018
2003
|
});
|
|
2019
2004
|
const { duration } = mediaRef.current;
|
|
2020
2005
|
const shouldBeTime = !Number.isNaN(duration) && Number.isFinite(duration)
|
|
@@ -4785,6 +4770,80 @@ const OffthreadVideo = (props) => {
|
|
|
4785
4770
|
return (jsx(VideoForDevelopment, { _remotionInternalStack: stack !== null && stack !== void 0 ? stack : null, _remotionInternalNativeLoopPassed: false, onDuration: onDuration, onlyWarnForMediaSeekingError: true, ...withoutTransparent }));
|
|
4786
4771
|
};
|
|
4787
4772
|
|
|
4773
|
+
const seekToTime = (element, desiredTime) => {
|
|
4774
|
+
element.currentTime = desiredTime;
|
|
4775
|
+
let cancel;
|
|
4776
|
+
let cancelSeeked = null;
|
|
4777
|
+
const prom = new Promise((resolve) => {
|
|
4778
|
+
cancel = element.requestVideoFrameCallback((now, metadata) => {
|
|
4779
|
+
const displayIn = metadata.expectedDisplayTime - now;
|
|
4780
|
+
if (displayIn <= 0) {
|
|
4781
|
+
resolve(metadata.mediaTime);
|
|
4782
|
+
return;
|
|
4783
|
+
}
|
|
4784
|
+
setTimeout(() => {
|
|
4785
|
+
resolve(metadata.mediaTime);
|
|
4786
|
+
}, displayIn + 150);
|
|
4787
|
+
});
|
|
4788
|
+
});
|
|
4789
|
+
const waitForSeekedEvent = new Promise((resolve) => {
|
|
4790
|
+
const onDone = () => {
|
|
4791
|
+
resolve();
|
|
4792
|
+
};
|
|
4793
|
+
element.addEventListener('seeked', onDone, {
|
|
4794
|
+
once: true,
|
|
4795
|
+
});
|
|
4796
|
+
cancelSeeked = () => {
|
|
4797
|
+
element.removeEventListener('seeked', onDone);
|
|
4798
|
+
};
|
|
4799
|
+
});
|
|
4800
|
+
return {
|
|
4801
|
+
wait: Promise.all([prom, waitForSeekedEvent]).then(([time]) => time),
|
|
4802
|
+
cancel: () => {
|
|
4803
|
+
cancelSeeked === null || cancelSeeked === void 0 ? void 0 : cancelSeeked();
|
|
4804
|
+
element.cancelVideoFrameCallback(cancel);
|
|
4805
|
+
},
|
|
4806
|
+
};
|
|
4807
|
+
};
|
|
4808
|
+
const seekToTimeMultipleUntilRight = (element, desiredTime, fps) => {
|
|
4809
|
+
const threshold = 1 / fps / 2;
|
|
4810
|
+
let currentCancel = () => undefined;
|
|
4811
|
+
const prom = new Promise((resolve, reject) => {
|
|
4812
|
+
const firstSeek = seekToTime(element, desiredTime + threshold);
|
|
4813
|
+
firstSeek.wait.then((seekedTo) => {
|
|
4814
|
+
const difference = Math.abs(desiredTime - seekedTo);
|
|
4815
|
+
if (difference < threshold) {
|
|
4816
|
+
return resolve();
|
|
4817
|
+
}
|
|
4818
|
+
const sign = desiredTime > seekedTo ? 1 : -1;
|
|
4819
|
+
const newSeek = seekToTime(element, seekedTo + threshold * sign);
|
|
4820
|
+
currentCancel = newSeek.cancel;
|
|
4821
|
+
newSeek.wait
|
|
4822
|
+
.then((newTime) => {
|
|
4823
|
+
const newDifference = Math.abs(desiredTime - newTime);
|
|
4824
|
+
if (newDifference < threshold) {
|
|
4825
|
+
return resolve();
|
|
4826
|
+
}
|
|
4827
|
+
const thirdSeek = seekToTime(element, desiredTime);
|
|
4828
|
+
currentCancel = thirdSeek.cancel;
|
|
4829
|
+
thirdSeek.wait.then(() => {
|
|
4830
|
+
resolve();
|
|
4831
|
+
});
|
|
4832
|
+
})
|
|
4833
|
+
.catch((err) => {
|
|
4834
|
+
reject(err);
|
|
4835
|
+
});
|
|
4836
|
+
});
|
|
4837
|
+
currentCancel = firstSeek.cancel;
|
|
4838
|
+
});
|
|
4839
|
+
return {
|
|
4840
|
+
prom,
|
|
4841
|
+
cancel: () => {
|
|
4842
|
+
currentCancel();
|
|
4843
|
+
},
|
|
4844
|
+
};
|
|
4845
|
+
};
|
|
4846
|
+
|
|
4788
4847
|
const VideoForRenderingForwardFunction = ({ onError, volume: volumeProp, allowAmplificationDuringRender, playbackRate, onDuration, toneFrequency, name, acceptableTimeShiftInSeconds, ...props }, ref) => {
|
|
4789
4848
|
const absoluteFrame = useTimelinePosition();
|
|
4790
4849
|
const frame = useCurrentFrame();
|
|
@@ -4864,16 +4923,12 @@ const VideoForRenderingForwardFunction = ({ onError, volume: volumeProp, allowAm
|
|
|
4864
4923
|
if (!current) {
|
|
4865
4924
|
return;
|
|
4866
4925
|
}
|
|
4867
|
-
const currentTime = (
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
startFrom: -mediaStartsAt,
|
|
4874
|
-
mediaType: 'video',
|
|
4875
|
-
});
|
|
4876
|
-
})();
|
|
4926
|
+
const currentTime = getMediaTime({
|
|
4927
|
+
frame,
|
|
4928
|
+
playbackRate: playbackRate || 1,
|
|
4929
|
+
startFrom: -mediaStartsAt,
|
|
4930
|
+
fps: videoConfig.fps,
|
|
4931
|
+
});
|
|
4877
4932
|
const handle = delayRender(`Rendering <Video /> with src="${props.src}"`);
|
|
4878
4933
|
if (process.env.NODE_ENV === 'test') {
|
|
4879
4934
|
continueRender(handle);
|
|
@@ -4892,25 +4947,13 @@ const VideoForRenderingForwardFunction = ({ onError, volume: volumeProp, allowAm
|
|
|
4892
4947
|
current.removeEventListener('loadeddata', loadedDataHandler);
|
|
4893
4948
|
};
|
|
4894
4949
|
}
|
|
4895
|
-
current.currentTime = currentTime;
|
|
4896
|
-
const seekedHandler = () => {
|
|
4897
|
-
warnAboutNonSeekableMedia(current, 'exception');
|
|
4898
|
-
if (window.navigator.platform.startsWith('Mac')) {
|
|
4899
|
-
// Improve me: This is ensures frame perfectness but slows down render.
|
|
4900
|
-
// Please see this issue for context: https://github.com/remotion-dev/remotion/issues/200
|
|
4901
|
-
// Only affects macOS since it uses VideoToolbox decoding.
|
|
4902
|
-
setTimeout(() => {
|
|
4903
|
-
continueRender(handle);
|
|
4904
|
-
}, 100);
|
|
4905
|
-
}
|
|
4906
|
-
else {
|
|
4907
|
-
continueRender(handle);
|
|
4908
|
-
}
|
|
4909
|
-
};
|
|
4910
|
-
current.addEventListener('seeked', seekedHandler, { once: true });
|
|
4911
4950
|
const endedHandler = () => {
|
|
4912
4951
|
continueRender(handle);
|
|
4913
4952
|
};
|
|
4953
|
+
const seek = seekToTimeMultipleUntilRight(current, currentTime, videoConfig.fps);
|
|
4954
|
+
seek.prom.then(() => {
|
|
4955
|
+
continueRender(handle);
|
|
4956
|
+
});
|
|
4914
4957
|
current.addEventListener('ended', endedHandler, { once: true });
|
|
4915
4958
|
const errorHandler = () => {
|
|
4916
4959
|
var _a;
|
|
@@ -4930,9 +4973,9 @@ const VideoForRenderingForwardFunction = ({ onError, volume: volumeProp, allowAm
|
|
|
4930
4973
|
current.addEventListener('error', errorHandler, { once: true });
|
|
4931
4974
|
// If video skips to another frame or unmounts, we clear the created handle
|
|
4932
4975
|
return () => {
|
|
4976
|
+
seek.cancel();
|
|
4933
4977
|
current.removeEventListener('ended', endedHandler);
|
|
4934
4978
|
current.removeEventListener('error', errorHandler);
|
|
4935
|
-
current.removeEventListener('seeked', seekedHandler);
|
|
4936
4979
|
continueRender(handle);
|
|
4937
4980
|
};
|
|
4938
4981
|
}, [
|
package/dist/esm/version.mjs
CHANGED