remotion 4.0.176 → 4.0.178
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/Composition.js +2 -1
- package/dist/cjs/ResolveCompositionConfig.js +12 -1
- package/dist/cjs/buffer-until-first-frame.d.ts +3 -2
- package/dist/cjs/buffer-until-first-frame.js +8 -4
- package/dist/cjs/input-props-serialization.d.ts +1 -0
- package/dist/cjs/input-props-serialization.js +43 -23
- package/dist/cjs/resolve-video-config.d.ts +11 -2
- package/dist/cjs/resolve-video-config.js +24 -7
- package/dist/cjs/use-lazy-component.js +2 -1
- package/dist/cjs/use-media-playback.js +35 -9
- package/dist/cjs/version.d.ts +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/cjs/video/OffthreadVideoForRendering.js +2 -2
- package/dist/cjs/video/Video.d.ts +2 -1
- package/dist/cjs/video/VideoForPreview.js +13 -5
- package/dist/cjs/video/VideoForRendering.d.ts +2 -1
- package/dist/cjs/video/VideoForRendering.js +1 -1
- package/dist/cjs/video/props.d.ts +4 -2
- package/dist/esm/index.mjs +186 -82
- package/dist/esm/no-react.mjs +24 -20
- package/dist/esm/version.mjs +1 -1
- package/package.json +6 -13
package/dist/cjs/Composition.js
CHANGED
|
@@ -12,6 +12,7 @@ const NativeLayers_js_1 = require("./NativeLayers.js");
|
|
|
12
12
|
const ResolveCompositionConfig_js_1 = require("./ResolveCompositionConfig.js");
|
|
13
13
|
const delay_render_js_1 = require("./delay-render.js");
|
|
14
14
|
const get_remotion_environment_js_1 = require("./get-remotion-environment.js");
|
|
15
|
+
const input_props_serialization_js_1 = require("./input-props-serialization.js");
|
|
15
16
|
const is_player_js_1 = require("./is-player.js");
|
|
16
17
|
const loading_indicator_js_1 = require("./loading-indicator.js");
|
|
17
18
|
const nonce_js_1 = require("./nonce.js");
|
|
@@ -78,7 +79,7 @@ const Composition = ({ width, height, fps, durationInFrames, id, defaultProps, s
|
|
|
78
79
|
id,
|
|
79
80
|
folderName,
|
|
80
81
|
component: lazy,
|
|
81
|
-
defaultProps: defaultProps,
|
|
82
|
+
defaultProps: (0, input_props_serialization_js_1.serializeThenDeserializeInStudio)((defaultProps !== null && defaultProps !== void 0 ? defaultProps : {})),
|
|
82
83
|
nonce,
|
|
83
84
|
parentFolderName: parentName,
|
|
84
85
|
schema: schema !== null && schema !== void 0 ? schema : null,
|
|
@@ -56,7 +56,7 @@ const ResolveCompositionConfig = ({ children }) => {
|
|
|
56
56
|
return controller;
|
|
57
57
|
}
|
|
58
58
|
const { signal } = controller;
|
|
59
|
-
const
|
|
59
|
+
const result = (0, resolve_video_config_js_1.resolveVideoConfigOrCatch)({
|
|
60
60
|
compositionId,
|
|
61
61
|
calculateMetadata,
|
|
62
62
|
originalProps: combinedProps,
|
|
@@ -67,6 +67,17 @@ const ResolveCompositionConfig = ({ children }) => {
|
|
|
67
67
|
compositionHeight,
|
|
68
68
|
compositionWidth,
|
|
69
69
|
});
|
|
70
|
+
if (result.type === 'error') {
|
|
71
|
+
setResolvedConfigs((r) => ({
|
|
72
|
+
...r,
|
|
73
|
+
[compositionId]: {
|
|
74
|
+
type: 'error',
|
|
75
|
+
error: result.error,
|
|
76
|
+
},
|
|
77
|
+
}));
|
|
78
|
+
return controller;
|
|
79
|
+
}
|
|
80
|
+
const promOrNot = result.result;
|
|
70
81
|
if (typeof promOrNot === 'object' && 'then' in promOrNot) {
|
|
71
82
|
setResolvedConfigs((r) => {
|
|
72
83
|
const prev = r[compositionId];
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
export declare const useBufferUntilFirstFrame: ({ mediaRef, mediaType, }: {
|
|
1
|
+
export declare const useBufferUntilFirstFrame: ({ mediaRef, mediaType, onVariableFpsVideoDetected, }: {
|
|
2
2
|
mediaRef: React.RefObject<HTMLVideoElement | HTMLAudioElement>;
|
|
3
3
|
mediaType: 'video' | 'audio';
|
|
4
|
+
onVariableFpsVideoDetected: () => void;
|
|
4
5
|
}) => {
|
|
5
6
|
isBuffering: () => boolean;
|
|
6
|
-
bufferUntilFirstFrame: () => void;
|
|
7
|
+
bufferUntilFirstFrame: (requestedTime: number) => void;
|
|
7
8
|
};
|
|
@@ -3,10 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.useBufferUntilFirstFrame = void 0;
|
|
4
4
|
const react_1 = require("react");
|
|
5
5
|
const use_buffer_state_1 = require("./use-buffer-state");
|
|
6
|
-
const useBufferUntilFirstFrame = ({ mediaRef, mediaType, }) => {
|
|
6
|
+
const useBufferUntilFirstFrame = ({ mediaRef, mediaType, onVariableFpsVideoDetected, }) => {
|
|
7
7
|
const bufferingRef = (0, react_1.useRef)(false);
|
|
8
8
|
const { delayPlayback } = (0, use_buffer_state_1.useBufferState)();
|
|
9
|
-
const bufferUntilFirstFrame = (0, react_1.useCallback)(() => {
|
|
9
|
+
const bufferUntilFirstFrame = (0, react_1.useCallback)((requestedTime) => {
|
|
10
10
|
if (mediaType !== 'video') {
|
|
11
11
|
return;
|
|
12
12
|
}
|
|
@@ -34,7 +34,11 @@ const useBufferUntilFirstFrame = ({ mediaRef, mediaType, }) => {
|
|
|
34
34
|
const onEndedOrPause = () => {
|
|
35
35
|
unblock();
|
|
36
36
|
};
|
|
37
|
-
current.requestVideoFrameCallback(() => {
|
|
37
|
+
current.requestVideoFrameCallback((_, info) => {
|
|
38
|
+
const differenceFromRequested = Math.abs(info.mediaTime - requestedTime);
|
|
39
|
+
if (differenceFromRequested > 0.5) {
|
|
40
|
+
onVariableFpsVideoDetected();
|
|
41
|
+
}
|
|
38
42
|
// Safari often seeks and then stalls.
|
|
39
43
|
// This makes sure that the video actually starts playing.
|
|
40
44
|
current.requestVideoFrameCallback(() => {
|
|
@@ -43,7 +47,7 @@ const useBufferUntilFirstFrame = ({ mediaRef, mediaType, }) => {
|
|
|
43
47
|
});
|
|
44
48
|
current.addEventListener('ended', onEndedOrPause, { once: true });
|
|
45
49
|
current.addEventListener('pause', onEndedOrPause, { once: true });
|
|
46
|
-
}, [delayPlayback, mediaRef, mediaType]);
|
|
50
|
+
}, [delayPlayback, mediaRef, mediaType, onVariableFpsVideoDetected]);
|
|
47
51
|
return (0, react_1.useMemo)(() => {
|
|
48
52
|
return {
|
|
49
53
|
isBuffering: () => bufferingRef.current,
|
|
@@ -13,3 +13,4 @@ export declare const serializeJSONWithDate: ({ data, indent, staticBase, }: {
|
|
|
13
13
|
staticBase: string | null;
|
|
14
14
|
}) => SerializedJSONWithCustomFields;
|
|
15
15
|
export declare const deserializeJSONWithCustomFields: <T = Record<string, unknown>>(data: string) => T;
|
|
16
|
+
export declare const serializeThenDeserializeInStudio: (props: Record<string, unknown>) => Record<string, unknown>;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
// Must keep this file in sync with the one in packages/lambda/src/shared/serialize-props.ts!
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.deserializeJSONWithCustomFields = exports.serializeJSONWithDate = exports.FILE_TOKEN = exports.DATE_TOKEN = void 0;
|
|
4
|
+
exports.serializeThenDeserializeInStudio = exports.deserializeJSONWithCustomFields = exports.serializeJSONWithDate = exports.FILE_TOKEN = exports.DATE_TOKEN = void 0;
|
|
5
|
+
const get_remotion_environment_js_1 = require("./get-remotion-environment.js");
|
|
5
6
|
const static_file_js_1 = require("./static-file.js");
|
|
6
7
|
exports.DATE_TOKEN = 'remotion-date:';
|
|
7
8
|
exports.FILE_TOKEN = 'remotion-file:';
|
|
@@ -10,29 +11,35 @@ const serializeJSONWithDate = ({ data, indent, staticBase, }) => {
|
|
|
10
11
|
let customFileUsed = false;
|
|
11
12
|
let mapUsed = false;
|
|
12
13
|
let setUsed = false;
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
14
|
+
try {
|
|
15
|
+
const serializedString = JSON.stringify(data, function (key, value) {
|
|
16
|
+
const item = this[key];
|
|
17
|
+
if (item instanceof Date) {
|
|
18
|
+
customDateUsed = true;
|
|
19
|
+
return `${exports.DATE_TOKEN}${item.toISOString()}`;
|
|
20
|
+
}
|
|
21
|
+
if (item instanceof Map) {
|
|
22
|
+
mapUsed = true;
|
|
23
|
+
return value;
|
|
24
|
+
}
|
|
25
|
+
if (item instanceof Set) {
|
|
26
|
+
setUsed = true;
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
if (typeof item === 'string' &&
|
|
30
|
+
staticBase !== null &&
|
|
31
|
+
item.startsWith(staticBase)) {
|
|
32
|
+
customFileUsed = true;
|
|
33
|
+
return `${exports.FILE_TOKEN}${item.replace(staticBase + '/', '')}`;
|
|
34
|
+
}
|
|
25
35
|
return value;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
return value;
|
|
34
|
-
}, indent);
|
|
35
|
-
return { serializedString, customDateUsed, customFileUsed, mapUsed, setUsed };
|
|
36
|
+
}, indent);
|
|
37
|
+
return { serializedString, customDateUsed, customFileUsed, mapUsed, setUsed };
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
throw new Error('Could not serialize the passed input props to JSON: ' +
|
|
41
|
+
err.message);
|
|
42
|
+
}
|
|
36
43
|
};
|
|
37
44
|
exports.serializeJSONWithDate = serializeJSONWithDate;
|
|
38
45
|
const deserializeJSONWithCustomFields = (data) => {
|
|
@@ -47,3 +54,16 @@ const deserializeJSONWithCustomFields = (data) => {
|
|
|
47
54
|
});
|
|
48
55
|
};
|
|
49
56
|
exports.deserializeJSONWithCustomFields = deserializeJSONWithCustomFields;
|
|
57
|
+
const serializeThenDeserializeInStudio = (props) => {
|
|
58
|
+
// Serializing once in the Studio, to catch potential serialization errors before
|
|
59
|
+
// you only get them during rendering
|
|
60
|
+
if ((0, get_remotion_environment_js_1.getRemotionEnvironment)().isStudio) {
|
|
61
|
+
return (0, exports.deserializeJSONWithCustomFields)((0, exports.serializeJSONWithDate)({
|
|
62
|
+
data: props,
|
|
63
|
+
indent: 2,
|
|
64
|
+
staticBase: window.remotion_staticBase,
|
|
65
|
+
}).serializedString);
|
|
66
|
+
}
|
|
67
|
+
return props;
|
|
68
|
+
};
|
|
69
|
+
exports.serializeThenDeserializeInStudio = serializeThenDeserializeInStudio;
|
|
@@ -2,7 +2,7 @@ import type { AnyZodObject } from 'zod';
|
|
|
2
2
|
import type { CalculateMetadataFunction } from './Composition.js';
|
|
3
3
|
import type { InferProps } from './props-if-has-props.js';
|
|
4
4
|
import type { VideoConfig } from './video-config.js';
|
|
5
|
-
|
|
5
|
+
type ResolveVideoConfigParams = {
|
|
6
6
|
compositionId: string;
|
|
7
7
|
compositionWidth: number | null;
|
|
8
8
|
compositionHeight: number | null;
|
|
@@ -12,4 +12,13 @@ export declare const resolveVideoConfig: ({ calculateMetadata, signal, defaultPr
|
|
|
12
12
|
signal: AbortSignal;
|
|
13
13
|
defaultProps: Record<string, unknown>;
|
|
14
14
|
originalProps: Record<string, unknown>;
|
|
15
|
-
}
|
|
15
|
+
};
|
|
16
|
+
export declare const resolveVideoConfig: ({ calculateMetadata, signal, defaultProps, originalProps, compositionId, compositionDurationInFrames, compositionFps, compositionHeight, compositionWidth, }: ResolveVideoConfigParams) => VideoConfig | Promise<VideoConfig>;
|
|
17
|
+
export declare const resolveVideoConfigOrCatch: (params: ResolveVideoConfigParams) => {
|
|
18
|
+
type: 'success';
|
|
19
|
+
result: VideoConfig | Promise<VideoConfig>;
|
|
20
|
+
} | {
|
|
21
|
+
type: 'error';
|
|
22
|
+
error: Error;
|
|
23
|
+
};
|
|
24
|
+
export {};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.resolveVideoConfig = void 0;
|
|
3
|
+
exports.resolveVideoConfigOrCatch = exports.resolveVideoConfig = void 0;
|
|
4
|
+
const input_props_serialization_js_1 = require("./input-props-serialization.js");
|
|
4
5
|
const validate_default_codec_js_1 = require("./validation/validate-default-codec.js");
|
|
5
6
|
const validate_dimensions_js_1 = require("./validation/validate-dimensions.js");
|
|
6
7
|
const validate_duration_in_frames_js_1 = require("./validation/validate-duration-in-frames.js");
|
|
@@ -53,8 +54,8 @@ const resolveVideoConfig = ({ calculateMetadata, signal, defaultProps, originalP
|
|
|
53
54
|
fps,
|
|
54
55
|
durationInFrames,
|
|
55
56
|
id: compositionId,
|
|
56
|
-
defaultProps,
|
|
57
|
-
props: (_a = c.props) !== null && _a !== void 0 ? _a : originalProps,
|
|
57
|
+
defaultProps: (0, input_props_serialization_js_1.serializeThenDeserializeInStudio)(defaultProps),
|
|
58
|
+
props: (0, input_props_serialization_js_1.serializeThenDeserializeInStudio)((_a = c.props) !== null && _a !== void 0 ? _a : originalProps),
|
|
58
59
|
defaultCodec: defaultCodec !== null && defaultCodec !== void 0 ? defaultCodec : null,
|
|
59
60
|
};
|
|
60
61
|
});
|
|
@@ -71,17 +72,33 @@ const resolveVideoConfig = ({ calculateMetadata, signal, defaultProps, originalP
|
|
|
71
72
|
return {
|
|
72
73
|
...data,
|
|
73
74
|
id: compositionId,
|
|
74
|
-
defaultProps: defaultProps !== null && defaultProps !== void 0 ? defaultProps : {},
|
|
75
|
-
props: originalProps,
|
|
75
|
+
defaultProps: (0, input_props_serialization_js_1.serializeThenDeserializeInStudio)(defaultProps !== null && defaultProps !== void 0 ? defaultProps : {}),
|
|
76
|
+
props: (0, input_props_serialization_js_1.serializeThenDeserializeInStudio)(originalProps),
|
|
76
77
|
defaultCodec: null,
|
|
77
78
|
};
|
|
78
79
|
}
|
|
79
80
|
return {
|
|
80
81
|
...data,
|
|
81
82
|
id: compositionId,
|
|
82
|
-
defaultProps: defaultProps !== null && defaultProps !== void 0 ? defaultProps : {},
|
|
83
|
-
props: (_a = calculatedProm.props) !== null && _a !== void 0 ? _a : originalProps,
|
|
83
|
+
defaultProps: (0, input_props_serialization_js_1.serializeThenDeserializeInStudio)(defaultProps !== null && defaultProps !== void 0 ? defaultProps : {}),
|
|
84
|
+
props: (0, input_props_serialization_js_1.serializeThenDeserializeInStudio)((_a = calculatedProm.props) !== null && _a !== void 0 ? _a : originalProps),
|
|
84
85
|
defaultCodec: (_b = calculatedProm.defaultCodec) !== null && _b !== void 0 ? _b : null,
|
|
85
86
|
};
|
|
86
87
|
};
|
|
87
88
|
exports.resolveVideoConfig = resolveVideoConfig;
|
|
89
|
+
const resolveVideoConfigOrCatch = (params) => {
|
|
90
|
+
try {
|
|
91
|
+
const promiseOrReturnValue = (0, exports.resolveVideoConfig)(params);
|
|
92
|
+
return {
|
|
93
|
+
type: 'success',
|
|
94
|
+
result: promiseOrReturnValue,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
catch (err) {
|
|
98
|
+
return {
|
|
99
|
+
type: 'error',
|
|
100
|
+
error: err,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
exports.resolveVideoConfigOrCatch = resolveVideoConfigOrCatch;
|
|
@@ -28,7 +28,8 @@ const react_1 = __importStar(require("react"));
|
|
|
28
28
|
// Expected, it can be any component props
|
|
29
29
|
const useLazyComponent = (compProps) => {
|
|
30
30
|
const lazy = (0, react_1.useMemo)(() => {
|
|
31
|
-
if ('lazyComponent' in compProps
|
|
31
|
+
if ('lazyComponent' in compProps &&
|
|
32
|
+
typeof compProps.lazyComponent !== 'undefined') {
|
|
32
33
|
return react_1.default.lazy(compProps.lazyComponent);
|
|
33
34
|
}
|
|
34
35
|
if ('component' in compProps) {
|
|
@@ -31,6 +31,7 @@ const useMediaPlayback = ({ mediaRef, src, mediaType, playbackRate: localPlaybac
|
|
|
31
31
|
const buffering = (0, react_1.useContext)(buffering_js_1.BufferingContextReact);
|
|
32
32
|
const { fps } = (0, use_video_config_js_1.useVideoConfig)();
|
|
33
33
|
const mediaStartsAt = (0, use_audio_frame_js_1.useMediaStartsAt)();
|
|
34
|
+
const lastSeekDueToShift = (0, react_1.useRef)(null);
|
|
34
35
|
if (!buffering) {
|
|
35
36
|
throw new Error('useMediaPlayback must be used inside a <BufferingContext>');
|
|
36
37
|
}
|
|
@@ -46,9 +47,21 @@ const useMediaPlayback = ({ mediaRef, src, mediaType, playbackRate: localPlaybac
|
|
|
46
47
|
shouldBuffer: pauseWhenBuffering,
|
|
47
48
|
isPremounting,
|
|
48
49
|
});
|
|
50
|
+
const isVariableFpsVideoMap = (0, react_1.useRef)({});
|
|
51
|
+
const onVariableFpsVideoDetected = (0, react_1.useCallback)(() => {
|
|
52
|
+
if (!src) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (debugSeeking) {
|
|
56
|
+
// eslint-disable-next-line no-console
|
|
57
|
+
console.log(`Detected ${src} as a variable FPS video. Disabling buffering while seeking.`);
|
|
58
|
+
}
|
|
59
|
+
isVariableFpsVideoMap.current[src] = true;
|
|
60
|
+
}, [debugSeeking, src]);
|
|
49
61
|
const { bufferUntilFirstFrame, isBuffering } = (0, buffer_until_first_frame_js_1.useBufferUntilFirstFrame)({
|
|
50
62
|
mediaRef,
|
|
51
63
|
mediaType,
|
|
64
|
+
onVariableFpsVideoDetected,
|
|
52
65
|
});
|
|
53
66
|
const playbackRate = localPlaybackRate * globalPlaybackRate;
|
|
54
67
|
// For short audio, a lower acceptable time shift is used
|
|
@@ -94,31 +107,42 @@ const useMediaPlayback = ({ mediaRef, src, mediaType, playbackRate: localPlaybac
|
|
|
94
107
|
const shouldBeTime = !Number.isNaN(duration) && Number.isFinite(duration)
|
|
95
108
|
? Math.min(duration, desiredUnclampedTime)
|
|
96
109
|
: desiredUnclampedTime;
|
|
97
|
-
const
|
|
110
|
+
const mediaTagTime = mediaRef.current.currentTime;
|
|
98
111
|
const rvcTime = (_a = currentTime.current) !== null && _a !== void 0 ? _a : null;
|
|
99
|
-
const
|
|
112
|
+
const isVariableFpsVideo = isVariableFpsVideoMap.current[src];
|
|
113
|
+
const timeShiftMediaTag = Math.abs(shouldBeTime - mediaTagTime);
|
|
100
114
|
const timeShiftRvcTag = rvcTime ? Math.abs(shouldBeTime - rvcTime) : null;
|
|
101
|
-
const timeShift = timeShiftRvcTag
|
|
115
|
+
const timeShift = timeShiftRvcTag && !isVariableFpsVideo
|
|
116
|
+
? timeShiftRvcTag
|
|
117
|
+
: timeShiftMediaTag;
|
|
102
118
|
if (debugSeeking) {
|
|
103
119
|
// eslint-disable-next-line no-console
|
|
104
120
|
console.log({
|
|
105
|
-
|
|
121
|
+
mediaTagTime,
|
|
106
122
|
rvcTime,
|
|
107
123
|
shouldBeTime,
|
|
108
124
|
state: mediaRef.current.readyState,
|
|
109
125
|
playing: !mediaRef.current.paused,
|
|
126
|
+
isVariableFpsVideo,
|
|
110
127
|
});
|
|
111
128
|
}
|
|
112
|
-
if (timeShift > acceptableTimeShiftButLessThanDuration
|
|
129
|
+
if (timeShift > acceptableTimeShiftButLessThanDuration &&
|
|
130
|
+
lastSeekDueToShift.current !== shouldBeTime) {
|
|
113
131
|
// If scrubbing around, adjust timing
|
|
114
132
|
// or if time shift is bigger than 0.45sec
|
|
115
133
|
if (debugSeeking) {
|
|
116
134
|
// eslint-disable-next-line no-console
|
|
117
|
-
console.log('Seeking', {
|
|
135
|
+
console.log('Seeking', {
|
|
136
|
+
shouldBeTime,
|
|
137
|
+
isTime: mediaTagTime,
|
|
138
|
+
rvcTime,
|
|
139
|
+
timeShift,
|
|
140
|
+
});
|
|
118
141
|
}
|
|
119
142
|
seek(mediaRef, shouldBeTime);
|
|
120
|
-
|
|
121
|
-
|
|
143
|
+
lastSeekDueToShift.current = shouldBeTime;
|
|
144
|
+
if (playing && !isVariableFpsVideo) {
|
|
145
|
+
bufferUntilFirstFrame(shouldBeTime);
|
|
122
146
|
if (mediaRef.current.paused) {
|
|
123
147
|
(0, play_and_handle_not_allowed_error_js_1.playAndHandleNotAllowedError)(mediaRef, mediaType);
|
|
124
148
|
}
|
|
@@ -150,7 +174,9 @@ const useMediaPlayback = ({ mediaRef, src, mediaType, playbackRate: localPlaybac
|
|
|
150
174
|
seek(mediaRef, shouldBeTime);
|
|
151
175
|
}
|
|
152
176
|
(0, play_and_handle_not_allowed_error_js_1.playAndHandleNotAllowedError)(mediaRef, mediaType);
|
|
153
|
-
|
|
177
|
+
if (!isVariableFpsVideo) {
|
|
178
|
+
bufferUntilFirstFrame(shouldBeTime);
|
|
179
|
+
}
|
|
154
180
|
}
|
|
155
181
|
}, [
|
|
156
182
|
absoluteFrame,
|
package/dist/cjs/version.d.ts
CHANGED
package/dist/cjs/version.js
CHANGED
|
@@ -102,9 +102,9 @@ const OffthreadVideoForRendering = ({ onError, volume: volumeProp, playbackRate,
|
|
|
102
102
|
toneMapped,
|
|
103
103
|
});
|
|
104
104
|
}, [toneMapped, currentTime, src, transparent]);
|
|
105
|
-
const onErr = (0, react_1.useCallback)((
|
|
105
|
+
const onErr = (0, react_1.useCallback)(() => {
|
|
106
106
|
if (onError) {
|
|
107
|
-
onError === null || onError === void 0 ? void 0 : onError(
|
|
107
|
+
onError === null || onError === void 0 ? void 0 : onError(new Error('Failed to load image with src ' + actualSrc));
|
|
108
108
|
}
|
|
109
109
|
else {
|
|
110
110
|
(0, cancel_render_js_1.cancelRender)('Failed to load image with src ' + actualSrc);
|
|
@@ -4,7 +4,7 @@ import type { RemotionMainVideoProps } from './props';
|
|
|
4
4
|
* @description allows you to include a video file in your Remotion project. It wraps the native HTMLVideoElement.
|
|
5
5
|
* @see [Documentation](https://www.remotion.dev/docs/video)
|
|
6
6
|
*/
|
|
7
|
-
export declare const Video: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.VideoHTMLAttributes<HTMLVideoElement>, HTMLVideoElement>, "nonce" | "onEnded" | "autoPlay" | "controls"> & {
|
|
7
|
+
export declare const Video: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.VideoHTMLAttributes<HTMLVideoElement>, HTMLVideoElement>, "nonce" | "onError" | "onEnded" | "autoPlay" | "controls"> & {
|
|
8
8
|
name?: string | undefined;
|
|
9
9
|
volume?: import("../volume-prop.js").VolumeProp | undefined;
|
|
10
10
|
playbackRate?: number | undefined;
|
|
@@ -16,6 +16,7 @@ export declare const Video: React.ForwardRefExoticComponent<Omit<Omit<React.Deta
|
|
|
16
16
|
delayRenderTimeoutInMilliseconds?: number | undefined;
|
|
17
17
|
loopVolumeCurveBehavior?: import("../audio/use-audio-frame.js").LoopVolumeCurveBehavior | undefined;
|
|
18
18
|
delayRenderRetries?: number | undefined;
|
|
19
|
+
onError?: ((err: Error) => void) | undefined;
|
|
19
20
|
} & RemotionMainVideoProps & {
|
|
20
21
|
/**
|
|
21
22
|
* @deprecated For internal use only
|
|
@@ -19,7 +19,7 @@ const VideoForDevelopmentRefForwardingFunction = (props, ref) => {
|
|
|
19
19
|
const videoRef = (0, react_1.useRef)(null);
|
|
20
20
|
const { volume, muted, playbackRate, onlyWarnForMediaSeekingError, src, onDuration,
|
|
21
21
|
// @ts-expect-error
|
|
22
|
-
acceptableTimeShift, acceptableTimeShiftInSeconds, toneFrequency, name, _remotionInternalNativeLoopPassed, _remotionInternalStack, _remotionDebugSeeking, style, pauseWhenBuffering, showInTimeline, loopVolumeCurveBehavior, ...nativeProps } = props;
|
|
22
|
+
acceptableTimeShift, acceptableTimeShiftInSeconds, toneFrequency, name, _remotionInternalNativeLoopPassed, _remotionInternalStack, _remotionDebugSeeking, style, pauseWhenBuffering, showInTimeline, loopVolumeCurveBehavior, onError, ...nativeProps } = props;
|
|
23
23
|
const volumePropFrame = (0, use_audio_frame_js_1.useFrameForVolumeProp)(loopVolumeCurveBehavior !== null && loopVolumeCurveBehavior !== void 0 ? loopVolumeCurveBehavior : 'repeat');
|
|
24
24
|
const { fps, durationInFrames } = (0, use_video_config_js_1.useVideoConfig)();
|
|
25
25
|
const parentSequence = (0, react_1.useContext)(SequenceContext_js_1.SequenceContext);
|
|
@@ -83,24 +83,32 @@ const VideoForDevelopmentRefForwardingFunction = (props, ref) => {
|
|
|
83
83
|
}
|
|
84
84
|
const errorHandler = () => {
|
|
85
85
|
var _a;
|
|
86
|
-
if (current
|
|
86
|
+
if (current.error) {
|
|
87
87
|
// eslint-disable-next-line no-console
|
|
88
88
|
console.error('Error occurred in video', current === null || current === void 0 ? void 0 : current.error);
|
|
89
89
|
// If user is handling the error, we don't cause an unhandled exception
|
|
90
|
-
if (
|
|
90
|
+
if (onError) {
|
|
91
|
+
const err = new Error(`Code ${current.error.code}: ${current.error.message}`);
|
|
92
|
+
onError(err);
|
|
91
93
|
return;
|
|
92
94
|
}
|
|
93
95
|
throw new Error(`The browser threw an error while playing the video ${src}: Code ${current.error.code} - ${(_a = current === null || current === void 0 ? void 0 : current.error) === null || _a === void 0 ? void 0 : _a.message}. See https://remotion.dev/docs/media-playback-error for help. Pass an onError() prop to handle the error.`);
|
|
94
96
|
}
|
|
95
97
|
else {
|
|
96
|
-
|
|
98
|
+
// If user is handling the error, we don't cause an unhandled exception
|
|
99
|
+
if (onError) {
|
|
100
|
+
const err = new Error(`The browser threw an error while playing the video ${src}`);
|
|
101
|
+
onError(err);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
throw new Error('The browser threw an error while playing the video');
|
|
97
105
|
}
|
|
98
106
|
};
|
|
99
107
|
current.addEventListener('error', errorHandler, { once: true });
|
|
100
108
|
return () => {
|
|
101
109
|
current.removeEventListener('error', errorHandler);
|
|
102
110
|
};
|
|
103
|
-
}, [
|
|
111
|
+
}, [onError, src]);
|
|
104
112
|
const currentOnDurationCallback = (0, react_1.useRef)();
|
|
105
113
|
currentOnDurationCallback.current = onDuration;
|
|
106
114
|
(0, react_1.useEffect)(() => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ForwardRefExoticComponent, RefAttributes } from 'react';
|
|
2
2
|
import React from 'react';
|
|
3
|
-
export declare const VideoForRendering: ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.VideoHTMLAttributes<HTMLVideoElement>, HTMLVideoElement>, "nonce" | "onEnded" | "autoPlay" | "controls"> & {
|
|
3
|
+
export declare const VideoForRendering: ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.VideoHTMLAttributes<HTMLVideoElement>, HTMLVideoElement>, "nonce" | "onError" | "onEnded" | "autoPlay" | "controls"> & {
|
|
4
4
|
name?: string | undefined;
|
|
5
5
|
volume?: import("../volume-prop.js").VolumeProp | undefined;
|
|
6
6
|
playbackRate?: number | undefined;
|
|
@@ -12,6 +12,7 @@ export declare const VideoForRendering: ForwardRefExoticComponent<Omit<React.Det
|
|
|
12
12
|
delayRenderTimeoutInMilliseconds?: number | undefined;
|
|
13
13
|
loopVolumeCurveBehavior?: import("../audio/use-audio-frame.js").LoopVolumeCurveBehavior | undefined;
|
|
14
14
|
delayRenderRetries?: number | undefined;
|
|
15
|
+
onError?: ((err: Error) => void) | undefined;
|
|
15
16
|
} & {
|
|
16
17
|
readonly onDuration: (src: string, durationInSeconds: number) => void;
|
|
17
18
|
} & RefAttributes<HTMLVideoElement>>;
|
|
@@ -203,6 +203,6 @@ const VideoForRenderingForwardFunction = ({ onError, volume: volumeProp, allowAm
|
|
|
203
203
|
};
|
|
204
204
|
}, [src, onDuration, delayRenderRetries, delayRenderTimeoutInMilliseconds]);
|
|
205
205
|
}
|
|
206
|
-
return (0, jsx_runtime_1.jsx)("video", { ref: videoRef, ...props
|
|
206
|
+
return (0, jsx_runtime_1.jsx)("video", { ref: videoRef, ...props });
|
|
207
207
|
};
|
|
208
208
|
exports.VideoForRendering = (0, react_1.forwardRef)(VideoForRenderingForwardFunction);
|
|
@@ -10,7 +10,7 @@ export type RemotionMainVideoProps = {
|
|
|
10
10
|
_remotionInternalNativeLoopPassed?: boolean;
|
|
11
11
|
_remotionDebugSeeking?: boolean;
|
|
12
12
|
};
|
|
13
|
-
export type RemotionVideoProps = Omit<React.DetailedHTMLProps<React.VideoHTMLAttributes<HTMLVideoElement>, HTMLVideoElement>, 'autoPlay' | 'controls' | 'onEnded' | 'nonce'> & {
|
|
13
|
+
export type RemotionVideoProps = Omit<React.DetailedHTMLProps<React.VideoHTMLAttributes<HTMLVideoElement>, HTMLVideoElement>, 'autoPlay' | 'controls' | 'onEnded' | 'nonce' | 'onError'> & {
|
|
14
14
|
name?: string;
|
|
15
15
|
volume?: VolumeProp;
|
|
16
16
|
playbackRate?: number;
|
|
@@ -22,6 +22,7 @@ export type RemotionVideoProps = Omit<React.DetailedHTMLProps<React.VideoHTMLAtt
|
|
|
22
22
|
delayRenderTimeoutInMilliseconds?: number;
|
|
23
23
|
loopVolumeCurveBehavior?: LoopVolumeCurveBehavior;
|
|
24
24
|
delayRenderRetries?: number;
|
|
25
|
+
onError?: (err: Error) => void;
|
|
25
26
|
};
|
|
26
27
|
type DeprecatedOffthreadVideoProps = {
|
|
27
28
|
/**
|
|
@@ -38,7 +39,7 @@ export type OffthreadVideoProps = {
|
|
|
38
39
|
volume?: VolumeProp;
|
|
39
40
|
playbackRate?: number;
|
|
40
41
|
muted?: boolean;
|
|
41
|
-
onError?:
|
|
42
|
+
onError?: (err: Error) => void;
|
|
42
43
|
acceptableTimeShiftInSeconds?: number;
|
|
43
44
|
allowAmplificationDuringRender?: boolean;
|
|
44
45
|
toneFrequency?: number;
|
|
@@ -47,6 +48,7 @@ export type OffthreadVideoProps = {
|
|
|
47
48
|
pauseWhenBuffering?: boolean;
|
|
48
49
|
loopVolumeCurveBehavior?: LoopVolumeCurveBehavior;
|
|
49
50
|
delayRenderTimeoutInMilliseconds?: number;
|
|
51
|
+
delayRenderRetries?: number;
|
|
50
52
|
/**
|
|
51
53
|
* @deprecated For internal use only
|
|
52
54
|
*/
|