remotion 4.0.84 → 4.0.86
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/RemotionRoot.js +1 -1
- package/dist/cjs/buffering.d.ts +26 -0
- package/dist/cjs/buffering.js +75 -0
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/internals.d.ts +3 -1
- package/dist/cjs/prefetch.d.ts +5 -0
- package/dist/cjs/prefetch.js +48 -8
- package/dist/cjs/timeline-position-state.d.ts +3 -1
- package/dist/cjs/timeline-position-state.js +18 -10
- package/dist/cjs/use-buffer.d.ts +5 -0
- package/dist/cjs/use-buffer.js +20 -0
- 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.js +23 -5
- package/dist/cjs/warn-about-non-seekable-media.js +7 -1
- package/dist/esm/index.mjs +162 -65
- package/dist/esm/version.mjs +1 -1
- package/package.json +1 -1
- package/dist/cjs/CatchError.d.ts +0 -15
- package/dist/cjs/CatchError.js +0 -68
package/dist/cjs/RemotionRoot.js
CHANGED
|
@@ -14,7 +14,7 @@ const timeline_position_state_js_1 = require("./timeline-position-state.js");
|
|
|
14
14
|
const duration_state_js_1 = require("./video/duration-state.js");
|
|
15
15
|
const RemotionRoot = ({ children, numberOfAudioTags }) => {
|
|
16
16
|
const [remotionRootId] = (0, react_1.useState)(() => String((0, random_js_1.random)(null)));
|
|
17
|
-
const [frame, setFrame] = (0, react_1.useState)(
|
|
17
|
+
const [frame, setFrame] = (0, react_1.useState)(() => (0, timeline_position_state_js_1.getInitialFrameState)());
|
|
18
18
|
const [playing, setPlaying] = (0, react_1.useState)(false);
|
|
19
19
|
const imperativePlaying = (0, react_1.useRef)(false);
|
|
20
20
|
const [fastRefreshes, setFastRefreshes] = (0, react_1.useState)(0);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
type Block = {
|
|
3
|
+
id: string;
|
|
4
|
+
};
|
|
5
|
+
type OnBufferingCallback = () => void;
|
|
6
|
+
type OnResumeCallback = () => void;
|
|
7
|
+
type ListenForBuffering = (callback: OnBufferingCallback) => {
|
|
8
|
+
remove: () => void;
|
|
9
|
+
};
|
|
10
|
+
type ListenForResume = (callback: OnResumeCallback) => {
|
|
11
|
+
remove: () => void;
|
|
12
|
+
};
|
|
13
|
+
type AddBlock = (block: Block) => {
|
|
14
|
+
unblock: () => void;
|
|
15
|
+
};
|
|
16
|
+
type BufferManager = {
|
|
17
|
+
blocks: Block[];
|
|
18
|
+
addBlock: AddBlock;
|
|
19
|
+
listenForBuffering: ListenForBuffering;
|
|
20
|
+
listenForResume: ListenForResume;
|
|
21
|
+
};
|
|
22
|
+
export declare const BufferingContextReact: React.Context<BufferManager | null>;
|
|
23
|
+
export declare const BufferingProvider: React.FC<{
|
|
24
|
+
children: React.ReactNode;
|
|
25
|
+
}>;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.BufferingProvider = exports.BufferingContextReact = void 0;
|
|
27
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
28
|
+
const react_1 = __importStar(require("react"));
|
|
29
|
+
const createBufferManager = () => {
|
|
30
|
+
let blocks = [];
|
|
31
|
+
let onBufferingCallback = [];
|
|
32
|
+
let onResumeCallback = [];
|
|
33
|
+
const addBlock = (block) => {
|
|
34
|
+
blocks.push(block);
|
|
35
|
+
onBufferingCallback.forEach((callback) => callback());
|
|
36
|
+
return {
|
|
37
|
+
unblock: () => {
|
|
38
|
+
blocks = blocks.filter((b) => b !== block);
|
|
39
|
+
if (blocks.length === 0) {
|
|
40
|
+
onResumeCallback.forEach((callback) => callback());
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
const listenForBuffering = (callback) => {
|
|
46
|
+
onBufferingCallback.push(callback);
|
|
47
|
+
return {
|
|
48
|
+
remove: () => {
|
|
49
|
+
onBufferingCallback = onBufferingCallback.filter((c) => c !== callback);
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
const listenForResume = (callback) => {
|
|
54
|
+
onResumeCallback.push(callback);
|
|
55
|
+
return {
|
|
56
|
+
remove: () => {
|
|
57
|
+
onResumeCallback = onResumeCallback.filter((c) => c !== callback);
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
return {
|
|
62
|
+
blocks,
|
|
63
|
+
addBlock,
|
|
64
|
+
listenForBuffering,
|
|
65
|
+
listenForResume,
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
exports.BufferingContextReact = react_1.default.createContext(null);
|
|
69
|
+
const BufferingProvider = ({ children }) => {
|
|
70
|
+
const [bufferManager] = (0, react_1.useState)(() => {
|
|
71
|
+
return createBufferManager();
|
|
72
|
+
});
|
|
73
|
+
return ((0, jsx_runtime_1.jsx)(exports.BufferingContextReact.Provider, { value: bufferManager, children: children }));
|
|
74
|
+
};
|
|
75
|
+
exports.BufferingProvider = BufferingProvider;
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -84,7 +84,7 @@ export { interpolateColors } from './interpolate-colors.js';
|
|
|
84
84
|
export { Loop } from './loop/index.js';
|
|
85
85
|
export { ClipRegion } from './NativeLayers.js';
|
|
86
86
|
export { EasingFunction, ExtrapolateType, interpolate, InterpolateOptions, random, RandomSeed, } from './no-react';
|
|
87
|
-
export { prefetch } from './prefetch.js';
|
|
87
|
+
export { prefetch, PrefetchOnProgress } from './prefetch.js';
|
|
88
88
|
export { registerRoot } from './register-root.js';
|
|
89
89
|
export { LayoutAndStyle, Sequence, SequenceProps, SequencePropsWithoutDuration, } from './Sequence.js';
|
|
90
90
|
export { Series } from './series/index.js';
|
package/dist/cjs/internals.d.ts
CHANGED
|
@@ -112,7 +112,9 @@ export declare const Internals: {
|
|
|
112
112
|
}>>;
|
|
113
113
|
readonly REMOTION_STUDIO_CONTAINER_ELEMENT: "__remotion-studio-container";
|
|
114
114
|
readonly RenderAssetManager: import("react").Context<import("./RenderAssetManager.js").RenderAssetManagerContext>;
|
|
115
|
-
readonly persistCurrentFrame: (
|
|
115
|
+
readonly persistCurrentFrame: (time: {
|
|
116
|
+
[x: string]: number;
|
|
117
|
+
}) => void;
|
|
116
118
|
readonly useTimelineSetFrame: () => (u: import("react").SetStateAction<Record<string, number>>) => void;
|
|
117
119
|
readonly FILE_TOKEN: "remotion-file:";
|
|
118
120
|
readonly DATE_TOKEN: "remotion-date:";
|
package/dist/cjs/prefetch.d.ts
CHANGED
|
@@ -3,6 +3,10 @@ type FetchAndPreload = {
|
|
|
3
3
|
free: () => void;
|
|
4
4
|
waitUntilDone: () => Promise<string>;
|
|
5
5
|
};
|
|
6
|
+
export type PrefetchOnProgress = (options: {
|
|
7
|
+
totalBytes: number | null;
|
|
8
|
+
loadedBytes: number;
|
|
9
|
+
}) => void;
|
|
6
10
|
/**
|
|
7
11
|
* @description When you call the preFetch() function, an asset will be fetched and kept in memory so it is ready when you want to play it in a <Player>.
|
|
8
12
|
* @see [Documentation](https://www.remotion.dev/docs/prefetch)
|
|
@@ -10,5 +14,6 @@ type FetchAndPreload = {
|
|
|
10
14
|
export declare const prefetch: (src: string, options?: {
|
|
11
15
|
method?: 'blob-url' | 'base64';
|
|
12
16
|
contentType?: string;
|
|
17
|
+
onProgress?: PrefetchOnProgress;
|
|
13
18
|
}) => FetchAndPreload;
|
|
14
19
|
export {};
|
package/dist/cjs/prefetch.js
CHANGED
|
@@ -23,6 +23,31 @@ const blobToBase64 = function (blob) {
|
|
|
23
23
|
reader.readAsDataURL(blob);
|
|
24
24
|
});
|
|
25
25
|
};
|
|
26
|
+
const getBlobFromReader = async ({ reader, contentType, contentLength, onProgress, }) => {
|
|
27
|
+
let receivedLength = 0;
|
|
28
|
+
const chunks = [];
|
|
29
|
+
// eslint-disable-next-line no-constant-condition
|
|
30
|
+
while (true) {
|
|
31
|
+
const { done, value } = await reader.read();
|
|
32
|
+
if (done) {
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
chunks.push(value);
|
|
36
|
+
receivedLength += value.length;
|
|
37
|
+
if (onProgress) {
|
|
38
|
+
onProgress({ loadedBytes: receivedLength, totalBytes: contentLength });
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const chunksAll = new Uint8Array(receivedLength);
|
|
42
|
+
let position = 0;
|
|
43
|
+
for (const chunk of chunks) {
|
|
44
|
+
chunksAll.set(chunk, position);
|
|
45
|
+
position += chunk.length;
|
|
46
|
+
}
|
|
47
|
+
return new Blob([chunksAll], {
|
|
48
|
+
type: contentType !== null && contentType !== void 0 ? contentType : undefined,
|
|
49
|
+
});
|
|
50
|
+
};
|
|
26
51
|
/**
|
|
27
52
|
* @description When you call the preFetch() function, an asset will be fetched and kept in memory so it is ready when you want to play it in a <Player>.
|
|
28
53
|
* @see [Documentation](https://www.remotion.dev/docs/prefetch)
|
|
@@ -50,6 +75,7 @@ const prefetch = (src, options) => {
|
|
|
50
75
|
signal: controller.signal,
|
|
51
76
|
})
|
|
52
77
|
.then((res) => {
|
|
78
|
+
var _a, _b, _c;
|
|
53
79
|
canBeAborted = false;
|
|
54
80
|
if (canceled) {
|
|
55
81
|
return null;
|
|
@@ -57,19 +83,33 @@ const prefetch = (src, options) => {
|
|
|
57
83
|
if (!res.ok) {
|
|
58
84
|
throw new Error(`HTTP error, status = ${res.status}`);
|
|
59
85
|
}
|
|
60
|
-
|
|
86
|
+
const headerContentType = res.headers.get('Content-Type');
|
|
87
|
+
const contentType = (_a = options === null || options === void 0 ? void 0 : options.contentType) !== null && _a !== void 0 ? _a : headerContentType;
|
|
88
|
+
const hasProperContentType = contentType &&
|
|
89
|
+
(contentType.startsWith('video/') ||
|
|
90
|
+
contentType.startsWith('audio/') ||
|
|
91
|
+
contentType.startsWith('image/'));
|
|
92
|
+
if (!hasProperContentType) {
|
|
93
|
+
// eslint-disable-next-line no-console
|
|
94
|
+
console.warn(`Called prefetch() on ${src} which returned a "Content-Type" of ${headerContentType}. Prefetched content should have a proper content type (video/... or audio/...) or a contentType passed the options of prefetch(). Otherwise, prefetching will not work properly in all browsers.`);
|
|
95
|
+
}
|
|
96
|
+
if (!res.body) {
|
|
97
|
+
throw new Error(`HTTP response of ${src} has no body`);
|
|
98
|
+
}
|
|
99
|
+
const reader = res.body.getReader();
|
|
100
|
+
return getBlobFromReader({
|
|
101
|
+
reader,
|
|
102
|
+
contentType: (_c = (_b = options === null || options === void 0 ? void 0 : options.contentType) !== null && _b !== void 0 ? _b : headerContentType) !== null && _c !== void 0 ? _c : null,
|
|
103
|
+
contentLength: res.headers.get('Content-Length')
|
|
104
|
+
? parseInt(res.headers.get('Content-Length'), 10)
|
|
105
|
+
: null,
|
|
106
|
+
onProgress: options === null || options === void 0 ? void 0 : options.onProgress,
|
|
107
|
+
});
|
|
61
108
|
})
|
|
62
109
|
.then((buf) => {
|
|
63
110
|
if (!buf) {
|
|
64
111
|
return;
|
|
65
112
|
}
|
|
66
|
-
if (!buf.type.startsWith('video/') &&
|
|
67
|
-
!buf.type.startsWith('audio/') &&
|
|
68
|
-
!buf.type.startsWith('image/') &&
|
|
69
|
-
!(options === null || options === void 0 ? void 0 : options.contentType)) {
|
|
70
|
-
// eslint-disable-next-line no-console
|
|
71
|
-
console.warn(`Called prefetch() on ${src} which returned a "Content-Type" of ${buf.type}. Prefetched content should have a proper content type (video/... or audio/...) or a contentType passed the options of prefetch(). Otherwise, prefetching will not work properly in all browsers.`);
|
|
72
|
-
}
|
|
73
113
|
const actualBlob = (options === null || options === void 0 ? void 0 : options.contentType)
|
|
74
114
|
? new Blob([buf], { type: options.contentType })
|
|
75
115
|
: buf;
|
|
@@ -18,7 +18,9 @@ export type SetTimelineContextValue = {
|
|
|
18
18
|
};
|
|
19
19
|
export declare const TimelineContext: import("react").Context<TimelineContextValue>;
|
|
20
20
|
export declare const SetTimelineContext: import("react").Context<SetTimelineContextValue>;
|
|
21
|
-
|
|
21
|
+
type CurrentTimePerComposition = Record<string, number>;
|
|
22
|
+
export declare const persistCurrentFrame: (time: CurrentTimePerComposition) => void;
|
|
23
|
+
export declare const getInitialFrameState: () => CurrentTimePerComposition;
|
|
22
24
|
export declare const getFrameForComposition: (composition: string) => number;
|
|
23
25
|
export declare const useTimelinePosition: () => number;
|
|
24
26
|
export declare const useTimelineSetFrame: () => (u: React.SetStateAction<Record<string, number>>) => void;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.usePlayingState = exports.useTimelineSetFrame = exports.useTimelinePosition = exports.getFrameForComposition = exports.persistCurrentFrame = exports.SetTimelineContext = exports.TimelineContext = void 0;
|
|
3
|
+
exports.usePlayingState = exports.useTimelineSetFrame = exports.useTimelinePosition = exports.getFrameForComposition = exports.getInitialFrameState = exports.persistCurrentFrame = exports.SetTimelineContext = exports.TimelineContext = void 0;
|
|
4
4
|
const react_1 = require("react");
|
|
5
5
|
const use_video_js_1 = require("./use-video.js");
|
|
6
6
|
exports.TimelineContext = (0, react_1.createContext)({
|
|
@@ -24,19 +24,27 @@ exports.SetTimelineContext = (0, react_1.createContext)({
|
|
|
24
24
|
throw new Error('default');
|
|
25
25
|
},
|
|
26
26
|
});
|
|
27
|
-
const makeKey = (
|
|
28
|
-
return `remotion.time
|
|
27
|
+
const makeKey = () => {
|
|
28
|
+
return `remotion.time-all`;
|
|
29
29
|
};
|
|
30
|
-
const persistCurrentFrame = (
|
|
31
|
-
localStorage.setItem(makeKey(
|
|
30
|
+
const persistCurrentFrame = (time) => {
|
|
31
|
+
localStorage.setItem(makeKey(), JSON.stringify(time));
|
|
32
32
|
};
|
|
33
33
|
exports.persistCurrentFrame = persistCurrentFrame;
|
|
34
|
+
const getInitialFrameState = () => {
|
|
35
|
+
var _a;
|
|
36
|
+
const item = (_a = localStorage.getItem(makeKey())) !== null && _a !== void 0 ? _a : '{}';
|
|
37
|
+
const obj = JSON.parse(item);
|
|
38
|
+
return obj;
|
|
39
|
+
};
|
|
40
|
+
exports.getInitialFrameState = getInitialFrameState;
|
|
34
41
|
const getFrameForComposition = (composition) => {
|
|
35
|
-
var _a, _b;
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
42
|
+
var _a, _b, _c;
|
|
43
|
+
const item = (_a = localStorage.getItem(makeKey())) !== null && _a !== void 0 ? _a : '{}';
|
|
44
|
+
const obj = JSON.parse(item);
|
|
45
|
+
return obj[composition]
|
|
46
|
+
? Number(obj[composition])
|
|
47
|
+
: (_c = (typeof window === 'undefined' ? 0 : (_b = window.remotion_initialFrame) !== null && _b !== void 0 ? _b : 0)) !== null && _c !== void 0 ? _c : 0;
|
|
40
48
|
};
|
|
41
49
|
exports.getFrameForComposition = getFrameForComposition;
|
|
42
50
|
const useTimelinePosition = () => {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useBuffer = void 0;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
const buffering_1 = require("./buffering");
|
|
6
|
+
const useBuffer = () => {
|
|
7
|
+
const buffer = (0, react_1.useContext)(buffering_1.BufferingContextReact);
|
|
8
|
+
if (!buffer) {
|
|
9
|
+
throw new TypeError('Can only use useBuffer() inside a Remotion composition');
|
|
10
|
+
}
|
|
11
|
+
return {
|
|
12
|
+
delayPlayback: () => {
|
|
13
|
+
const { unblock } = buffer.addBlock({
|
|
14
|
+
id: String(Math.random()),
|
|
15
|
+
});
|
|
16
|
+
return { unblock };
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
};
|
|
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.86";
|
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;
|
|
@@ -4,14 +4,34 @@ exports.seekToTimeMultipleUntilRight = exports.seekToTime = void 0;
|
|
|
4
4
|
const seekToTime = (element, desiredTime) => {
|
|
5
5
|
element.currentTime = desiredTime;
|
|
6
6
|
let cancel;
|
|
7
|
+
let cancelSeeked = null;
|
|
7
8
|
const prom = new Promise((resolve) => {
|
|
8
|
-
cancel = element.requestVideoFrameCallback((
|
|
9
|
-
|
|
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 + 50);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
const waitForSeekedEvent = new Promise((resolve) => {
|
|
21
|
+
const onDone = () => {
|
|
22
|
+
resolve();
|
|
23
|
+
};
|
|
24
|
+
element.addEventListener('seeked', onDone, {
|
|
25
|
+
once: true,
|
|
10
26
|
});
|
|
27
|
+
cancelSeeked = () => {
|
|
28
|
+
element.removeEventListener('seeked', onDone);
|
|
29
|
+
};
|
|
11
30
|
});
|
|
12
31
|
return {
|
|
13
|
-
wait: prom,
|
|
32
|
+
wait: Promise.all([prom, waitForSeekedEvent]).then(([time]) => time),
|
|
14
33
|
cancel: () => {
|
|
34
|
+
cancelSeeked === null || cancelSeeked === void 0 ? void 0 : cancelSeeked();
|
|
15
35
|
element.cancelVideoFrameCallback(cancel);
|
|
16
36
|
},
|
|
17
37
|
};
|
|
@@ -24,7 +44,6 @@ const seekToTimeMultipleUntilRight = (element, desiredTime, fps) => {
|
|
|
24
44
|
const firstSeek = (0, exports.seekToTime)(element, desiredTime + threshold);
|
|
25
45
|
firstSeek.wait.then((seekedTo) => {
|
|
26
46
|
const difference = Math.abs(desiredTime - seekedTo);
|
|
27
|
-
const ident = Math.random();
|
|
28
47
|
if (difference < threshold) {
|
|
29
48
|
return resolve();
|
|
30
49
|
}
|
|
@@ -34,7 +53,6 @@ const seekToTimeMultipleUntilRight = (element, desiredTime, fps) => {
|
|
|
34
53
|
newSeek.wait
|
|
35
54
|
.then((newTime) => {
|
|
36
55
|
const newDifference = Math.abs(desiredTime - newTime);
|
|
37
|
-
console.log(ident, 'before', seekedTo, 'after', newTime, 'desired', desiredTime);
|
|
38
56
|
if (newDifference < threshold) {
|
|
39
57
|
return resolve();
|
|
40
58
|
}
|
|
@@ -18,7 +18,13 @@ const warnAboutNonSeekableMedia = (ref, type) => {
|
|
|
18
18
|
}
|
|
19
19
|
const range = { start: ref.seekable.start(0), end: ref.seekable.end(0) };
|
|
20
20
|
if (range.start === 0 && range.end === 0) {
|
|
21
|
-
const msg =
|
|
21
|
+
const msg = [
|
|
22
|
+
`The media ${ref.src} cannot be seeked. This could be one of few reasons:`,
|
|
23
|
+
'1) The media resource was replaced while the video is playing but it was not loaded yet.',
|
|
24
|
+
'2) The media does not support seeking.',
|
|
25
|
+
'3) The media was loaded with security headers prventing it from being included.',
|
|
26
|
+
'Please see https://remotion.dev/docs/non-seekable-media for assistance.',
|
|
27
|
+
].join('\n');
|
|
22
28
|
if (type === 'console-error') {
|
|
23
29
|
// eslint-disable-next-line no-console
|
|
24
30
|
console.error(msg);
|
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.86';
|
|
136
136
|
|
|
137
137
|
const checkMultipleRemotionVersions = () => {
|
|
138
138
|
if (typeof globalThis === 'undefined') {
|
|
@@ -864,18 +864,25 @@ const SetTimelineContext = createContext({
|
|
|
864
864
|
throw new Error('default');
|
|
865
865
|
},
|
|
866
866
|
});
|
|
867
|
-
const makeKey = (
|
|
868
|
-
return `remotion.time
|
|
867
|
+
const makeKey = () => {
|
|
868
|
+
return `remotion.time-all`;
|
|
869
869
|
};
|
|
870
|
-
const persistCurrentFrame = (
|
|
871
|
-
localStorage.setItem(makeKey(
|
|
870
|
+
const persistCurrentFrame = (time) => {
|
|
871
|
+
localStorage.setItem(makeKey(), JSON.stringify(time));
|
|
872
|
+
};
|
|
873
|
+
const getInitialFrameState = () => {
|
|
874
|
+
var _a;
|
|
875
|
+
const item = (_a = localStorage.getItem(makeKey())) !== null && _a !== void 0 ? _a : '{}';
|
|
876
|
+
const obj = JSON.parse(item);
|
|
877
|
+
return obj;
|
|
872
878
|
};
|
|
873
879
|
const getFrameForComposition = (composition) => {
|
|
874
|
-
var _a, _b;
|
|
875
|
-
const
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
880
|
+
var _a, _b, _c;
|
|
881
|
+
const item = (_a = localStorage.getItem(makeKey())) !== null && _a !== void 0 ? _a : '{}';
|
|
882
|
+
const obj = JSON.parse(item);
|
|
883
|
+
return obj[composition]
|
|
884
|
+
? Number(obj[composition])
|
|
885
|
+
: (_c = (typeof window === 'undefined' ? 0 : (_b = window.remotion_initialFrame) !== null && _b !== void 0 ? _b : 0)) !== null && _c !== void 0 ? _c : 0;
|
|
879
886
|
};
|
|
880
887
|
const useTimelinePosition = () => {
|
|
881
888
|
var _a, _b;
|
|
@@ -906,6 +913,7 @@ var TimelinePosition = /*#__PURE__*/Object.freeze({
|
|
|
906
913
|
TimelineContext: TimelineContext,
|
|
907
914
|
SetTimelineContext: SetTimelineContext,
|
|
908
915
|
persistCurrentFrame: persistCurrentFrame,
|
|
916
|
+
getInitialFrameState: getInitialFrameState,
|
|
909
917
|
getFrameForComposition: getFrameForComposition,
|
|
910
918
|
useTimelinePosition: useTimelinePosition,
|
|
911
919
|
useTimelineSetFrame: useTimelineSetFrame,
|
|
@@ -1258,6 +1266,31 @@ const blobToBase64 = function (blob) {
|
|
|
1258
1266
|
reader.readAsDataURL(blob);
|
|
1259
1267
|
});
|
|
1260
1268
|
};
|
|
1269
|
+
const getBlobFromReader = async ({ reader, contentType, contentLength, onProgress, }) => {
|
|
1270
|
+
let receivedLength = 0;
|
|
1271
|
+
const chunks = [];
|
|
1272
|
+
// eslint-disable-next-line no-constant-condition
|
|
1273
|
+
while (true) {
|
|
1274
|
+
const { done, value } = await reader.read();
|
|
1275
|
+
if (done) {
|
|
1276
|
+
break;
|
|
1277
|
+
}
|
|
1278
|
+
chunks.push(value);
|
|
1279
|
+
receivedLength += value.length;
|
|
1280
|
+
if (onProgress) {
|
|
1281
|
+
onProgress({ loadedBytes: receivedLength, totalBytes: contentLength });
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
const chunksAll = new Uint8Array(receivedLength);
|
|
1285
|
+
let position = 0;
|
|
1286
|
+
for (const chunk of chunks) {
|
|
1287
|
+
chunksAll.set(chunk, position);
|
|
1288
|
+
position += chunk.length;
|
|
1289
|
+
}
|
|
1290
|
+
return new Blob([chunksAll], {
|
|
1291
|
+
type: contentType !== null && contentType !== void 0 ? contentType : undefined,
|
|
1292
|
+
});
|
|
1293
|
+
};
|
|
1261
1294
|
/**
|
|
1262
1295
|
* @description When you call the preFetch() function, an asset will be fetched and kept in memory so it is ready when you want to play it in a <Player>.
|
|
1263
1296
|
* @see [Documentation](https://www.remotion.dev/docs/prefetch)
|
|
@@ -1285,6 +1318,7 @@ const prefetch = (src, options) => {
|
|
|
1285
1318
|
signal: controller.signal,
|
|
1286
1319
|
})
|
|
1287
1320
|
.then((res) => {
|
|
1321
|
+
var _a, _b, _c;
|
|
1288
1322
|
canBeAborted = false;
|
|
1289
1323
|
if (canceled) {
|
|
1290
1324
|
return null;
|
|
@@ -1292,19 +1326,33 @@ const prefetch = (src, options) => {
|
|
|
1292
1326
|
if (!res.ok) {
|
|
1293
1327
|
throw new Error(`HTTP error, status = ${res.status}`);
|
|
1294
1328
|
}
|
|
1295
|
-
|
|
1329
|
+
const headerContentType = res.headers.get('Content-Type');
|
|
1330
|
+
const contentType = (_a = options === null || options === void 0 ? void 0 : options.contentType) !== null && _a !== void 0 ? _a : headerContentType;
|
|
1331
|
+
const hasProperContentType = contentType &&
|
|
1332
|
+
(contentType.startsWith('video/') ||
|
|
1333
|
+
contentType.startsWith('audio/') ||
|
|
1334
|
+
contentType.startsWith('image/'));
|
|
1335
|
+
if (!hasProperContentType) {
|
|
1336
|
+
// eslint-disable-next-line no-console
|
|
1337
|
+
console.warn(`Called prefetch() on ${src} which returned a "Content-Type" of ${headerContentType}. Prefetched content should have a proper content type (video/... or audio/...) or a contentType passed the options of prefetch(). Otherwise, prefetching will not work properly in all browsers.`);
|
|
1338
|
+
}
|
|
1339
|
+
if (!res.body) {
|
|
1340
|
+
throw new Error(`HTTP response of ${src} has no body`);
|
|
1341
|
+
}
|
|
1342
|
+
const reader = res.body.getReader();
|
|
1343
|
+
return getBlobFromReader({
|
|
1344
|
+
reader,
|
|
1345
|
+
contentType: (_c = (_b = options === null || options === void 0 ? void 0 : options.contentType) !== null && _b !== void 0 ? _b : headerContentType) !== null && _c !== void 0 ? _c : null,
|
|
1346
|
+
contentLength: res.headers.get('Content-Length')
|
|
1347
|
+
? parseInt(res.headers.get('Content-Length'), 10)
|
|
1348
|
+
: null,
|
|
1349
|
+
onProgress: options === null || options === void 0 ? void 0 : options.onProgress,
|
|
1350
|
+
});
|
|
1296
1351
|
})
|
|
1297
1352
|
.then((buf) => {
|
|
1298
1353
|
if (!buf) {
|
|
1299
1354
|
return;
|
|
1300
1355
|
}
|
|
1301
|
-
if (!buf.type.startsWith('video/') &&
|
|
1302
|
-
!buf.type.startsWith('audio/') &&
|
|
1303
|
-
!buf.type.startsWith('image/') &&
|
|
1304
|
-
!(options === null || options === void 0 ? void 0 : options.contentType)) {
|
|
1305
|
-
// eslint-disable-next-line no-console
|
|
1306
|
-
console.warn(`Called prefetch() on ${src} which returned a "Content-Type" of ${buf.type}. Prefetched content should have a proper content type (video/... or audio/...) or a contentType passed the options of prefetch(). Otherwise, prefetching will not work properly in all browsers.`);
|
|
1307
|
-
}
|
|
1308
1356
|
const actualBlob = (options === null || options === void 0 ? void 0 : options.contentType)
|
|
1309
1357
|
? new Blob([buf], { type: options.contentType })
|
|
1310
1358
|
: buf;
|
|
@@ -1795,27 +1843,14 @@ function interpolate(input, inputRange, outputRange, options) {
|
|
|
1795
1843
|
const getExpectedMediaFrameUncorrected = ({ frame, playbackRate, startFrom, }) => {
|
|
1796
1844
|
return interpolate(frame, [-1, startFrom, startFrom + 1], [-1, startFrom, startFrom + playbackRate]);
|
|
1797
1845
|
};
|
|
1798
|
-
const getMediaTime = ({ fps, frame,
|
|
1846
|
+
const getMediaTime = ({ fps, frame, playbackRate, startFrom, }) => {
|
|
1799
1847
|
const expectedFrame = getExpectedMediaFrameUncorrected({
|
|
1800
1848
|
frame,
|
|
1801
1849
|
playbackRate,
|
|
1802
1850
|
startFrom,
|
|
1803
1851
|
});
|
|
1804
|
-
const isChrome = typeof window !== 'undefined' &&
|
|
1805
|
-
window.navigator.userAgent.match(/Chrome\/([0-9]+)/);
|
|
1806
|
-
if (isChrome &&
|
|
1807
|
-
Number(isChrome[1]) < 112 &&
|
|
1808
|
-
mediaType === 'video' &&
|
|
1809
|
-
src.endsWith('.mp4')) {
|
|
1810
|
-
// In Chrome, for MP4s, if 30fps, the first frame is still displayed at 0.033333
|
|
1811
|
-
// even though after that it increases by 0.033333333 each.
|
|
1812
|
-
// So frame = 0 in Remotion is like frame = 1 for the browser
|
|
1813
|
-
return (expectedFrame + 1) / fps;
|
|
1814
|
-
}
|
|
1815
|
-
// For WebM videos, we need to add a little bit of shift to get the right frame.
|
|
1816
1852
|
const msPerFrame = 1000 / fps;
|
|
1817
|
-
|
|
1818
|
-
return (expectedFrame * msPerFrame + msShift) / 1000;
|
|
1853
|
+
return (expectedFrame * msPerFrame) / 1000;
|
|
1819
1854
|
};
|
|
1820
1855
|
|
|
1821
1856
|
const toSeconds = (time, fps) => {
|
|
@@ -1892,7 +1927,13 @@ const warnAboutNonSeekableMedia = (ref, type) => {
|
|
|
1892
1927
|
}
|
|
1893
1928
|
const range = { start: ref.seekable.start(0), end: ref.seekable.end(0) };
|
|
1894
1929
|
if (range.start === 0 && range.end === 0) {
|
|
1895
|
-
const msg =
|
|
1930
|
+
const msg = [
|
|
1931
|
+
`The media ${ref.src} cannot be seeked. This could be one of few reasons:`,
|
|
1932
|
+
'1) The media resource was replaced while the video is playing but it was not loaded yet.',
|
|
1933
|
+
'2) The media does not support seeking.',
|
|
1934
|
+
'3) The media was loaded with security headers prventing it from being included.',
|
|
1935
|
+
'Please see https://remotion.dev/docs/non-seekable-media for assistance.',
|
|
1936
|
+
].join('\n');
|
|
1896
1937
|
if (type === 'console-error') {
|
|
1897
1938
|
// eslint-disable-next-line no-console
|
|
1898
1939
|
console.error(msg);
|
|
@@ -1955,12 +1996,10 @@ const useMediaPlayback = ({ mediaRef, src, mediaType, playbackRate: localPlaybac
|
|
|
1955
1996
|
mediaRef.current.playbackRate = playbackRateToSet;
|
|
1956
1997
|
}
|
|
1957
1998
|
const desiredUnclampedTime = getMediaTime({
|
|
1958
|
-
fps,
|
|
1959
1999
|
frame,
|
|
1960
|
-
src,
|
|
1961
2000
|
playbackRate: localPlaybackRate,
|
|
1962
2001
|
startFrom: -mediaStartsAt,
|
|
1963
|
-
|
|
2002
|
+
fps,
|
|
1964
2003
|
});
|
|
1965
2004
|
const { duration } = mediaRef.current;
|
|
1966
2005
|
const shouldBeTime = !Number.isNaN(duration) && Number.isFinite(duration)
|
|
@@ -3472,7 +3511,7 @@ const waitForRoot = (fn) => {
|
|
|
3472
3511
|
|
|
3473
3512
|
const RemotionRoot = ({ children, numberOfAudioTags }) => {
|
|
3474
3513
|
const [remotionRootId] = useState(() => String(random(null)));
|
|
3475
|
-
const [frame, setFrame] = useState(
|
|
3514
|
+
const [frame, setFrame] = useState(() => getInitialFrameState());
|
|
3476
3515
|
const [playing, setPlaying] = useState(false);
|
|
3477
3516
|
const imperativePlaying = useRef(false);
|
|
3478
3517
|
const [fastRefreshes, setFastRefreshes] = useState(0);
|
|
@@ -4731,6 +4770,80 @@ const OffthreadVideo = (props) => {
|
|
|
4731
4770
|
return (jsx(VideoForDevelopment, { _remotionInternalStack: stack !== null && stack !== void 0 ? stack : null, _remotionInternalNativeLoopPassed: false, onDuration: onDuration, onlyWarnForMediaSeekingError: true, ...withoutTransparent }));
|
|
4732
4771
|
};
|
|
4733
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 + 50);
|
|
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
|
+
|
|
4734
4847
|
const VideoForRenderingForwardFunction = ({ onError, volume: volumeProp, allowAmplificationDuringRender, playbackRate, onDuration, toneFrequency, name, acceptableTimeShiftInSeconds, ...props }, ref) => {
|
|
4735
4848
|
const absoluteFrame = useTimelinePosition();
|
|
4736
4849
|
const frame = useCurrentFrame();
|
|
@@ -4810,16 +4923,12 @@ const VideoForRenderingForwardFunction = ({ onError, volume: volumeProp, allowAm
|
|
|
4810
4923
|
if (!current) {
|
|
4811
4924
|
return;
|
|
4812
4925
|
}
|
|
4813
|
-
const currentTime = (
|
|
4814
|
-
|
|
4815
|
-
|
|
4816
|
-
|
|
4817
|
-
|
|
4818
|
-
|
|
4819
|
-
startFrom: -mediaStartsAt,
|
|
4820
|
-
mediaType: 'video',
|
|
4821
|
-
});
|
|
4822
|
-
})();
|
|
4926
|
+
const currentTime = getMediaTime({
|
|
4927
|
+
frame,
|
|
4928
|
+
playbackRate: playbackRate || 1,
|
|
4929
|
+
startFrom: -mediaStartsAt,
|
|
4930
|
+
fps: videoConfig.fps,
|
|
4931
|
+
});
|
|
4823
4932
|
const handle = delayRender(`Rendering <Video /> with src="${props.src}"`);
|
|
4824
4933
|
if (process.env.NODE_ENV === 'test') {
|
|
4825
4934
|
continueRender(handle);
|
|
@@ -4838,25 +4947,13 @@ const VideoForRenderingForwardFunction = ({ onError, volume: volumeProp, allowAm
|
|
|
4838
4947
|
current.removeEventListener('loadeddata', loadedDataHandler);
|
|
4839
4948
|
};
|
|
4840
4949
|
}
|
|
4841
|
-
current.currentTime = currentTime;
|
|
4842
|
-
const seekedHandler = () => {
|
|
4843
|
-
warnAboutNonSeekableMedia(current, 'exception');
|
|
4844
|
-
if (window.navigator.platform.startsWith('Mac')) {
|
|
4845
|
-
// Improve me: This is ensures frame perfectness but slows down render.
|
|
4846
|
-
// Please see this issue for context: https://github.com/remotion-dev/remotion/issues/200
|
|
4847
|
-
// Only affects macOS since it uses VideoToolbox decoding.
|
|
4848
|
-
setTimeout(() => {
|
|
4849
|
-
continueRender(handle);
|
|
4850
|
-
}, 100);
|
|
4851
|
-
}
|
|
4852
|
-
else {
|
|
4853
|
-
continueRender(handle);
|
|
4854
|
-
}
|
|
4855
|
-
};
|
|
4856
|
-
current.addEventListener('seeked', seekedHandler, { once: true });
|
|
4857
4950
|
const endedHandler = () => {
|
|
4858
4951
|
continueRender(handle);
|
|
4859
4952
|
};
|
|
4953
|
+
const seek = seekToTimeMultipleUntilRight(current, currentTime, videoConfig.fps);
|
|
4954
|
+
seek.prom.then(() => {
|
|
4955
|
+
continueRender(handle);
|
|
4956
|
+
});
|
|
4860
4957
|
current.addEventListener('ended', endedHandler, { once: true });
|
|
4861
4958
|
const errorHandler = () => {
|
|
4862
4959
|
var _a;
|
|
@@ -4876,9 +4973,9 @@ const VideoForRenderingForwardFunction = ({ onError, volume: volumeProp, allowAm
|
|
|
4876
4973
|
current.addEventListener('error', errorHandler, { once: true });
|
|
4877
4974
|
// If video skips to another frame or unmounts, we clear the created handle
|
|
4878
4975
|
return () => {
|
|
4976
|
+
seek.cancel();
|
|
4879
4977
|
current.removeEventListener('ended', endedHandler);
|
|
4880
4978
|
current.removeEventListener('error', errorHandler);
|
|
4881
|
-
current.removeEventListener('seeked', seekedHandler);
|
|
4882
4979
|
continueRender(handle);
|
|
4883
4980
|
};
|
|
4884
4981
|
}, [
|
package/dist/esm/version.mjs
CHANGED
package/package.json
CHANGED
package/dist/cjs/CatchError.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
export declare class CatchError extends React.Component {
|
|
3
|
-
state: {
|
|
4
|
-
hasError: boolean;
|
|
5
|
-
};
|
|
6
|
-
constructor(props: {
|
|
7
|
-
children: React.ReactNode;
|
|
8
|
-
});
|
|
9
|
-
static getDerivedStateFromError(error: Error): {
|
|
10
|
-
hasError: boolean;
|
|
11
|
-
};
|
|
12
|
-
componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void;
|
|
13
|
-
render(): React.ReactNode;
|
|
14
|
-
}
|
|
15
|
-
export declare const StackTraceFetcher: () => JSX.Element;
|
package/dist/cjs/CatchError.js
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
24
|
-
};
|
|
25
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.StackTraceFetcher = exports.CatchError = void 0;
|
|
27
|
-
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
28
|
-
const react_1 = __importStar(require("react"));
|
|
29
|
-
const ErrorThrower = () => {
|
|
30
|
-
const [trigger, setTrigger] = react_1.default.useState(false);
|
|
31
|
-
(0, react_1.useEffect)(() => {
|
|
32
|
-
setTrigger(true);
|
|
33
|
-
}, []);
|
|
34
|
-
if (trigger) {
|
|
35
|
-
// throw new Error('lol');
|
|
36
|
-
}
|
|
37
|
-
return null;
|
|
38
|
-
};
|
|
39
|
-
class CatchError extends react_1.default.Component {
|
|
40
|
-
// eslint-disable-next-line no-useless-constructor
|
|
41
|
-
constructor(props) {
|
|
42
|
-
super(props);
|
|
43
|
-
this.state = { hasError: false };
|
|
44
|
-
}
|
|
45
|
-
static getDerivedStateFromError(error) {
|
|
46
|
-
console.log('DERIVED STATE');
|
|
47
|
-
console.error(error);
|
|
48
|
-
return { hasError: true };
|
|
49
|
-
}
|
|
50
|
-
componentDidCatch(error, errorInfo) {
|
|
51
|
-
console.log('DID CATCH');
|
|
52
|
-
console.error(error, errorInfo);
|
|
53
|
-
}
|
|
54
|
-
render() {
|
|
55
|
-
console.log('state', this);
|
|
56
|
-
if (this.state.hasError) {
|
|
57
|
-
console.log('null');
|
|
58
|
-
return null;
|
|
59
|
-
}
|
|
60
|
-
// @ts-expect-error
|
|
61
|
-
return this.props.children;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
exports.CatchError = CatchError;
|
|
65
|
-
const StackTraceFetcher = () => {
|
|
66
|
-
return ((0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsx)(CatchError, { children: (0, jsx_runtime_1.jsx)(ErrorThrower, {}) }) }));
|
|
67
|
-
};
|
|
68
|
-
exports.StackTraceFetcher = StackTraceFetcher;
|