remotion 4.0.465 → 4.0.467
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/CompositionManager.d.ts +1 -0
- package/dist/cjs/HtmlInCanvas.js +3 -1
- package/dist/cjs/Img.js +4 -4
- package/dist/cjs/Sequence.d.ts +4 -0
- package/dist/cjs/Sequence.js +6 -1
- package/dist/cjs/animated-image/AnimatedImage.js +1 -1
- package/dist/cjs/animated-image/canvas.js +3 -50
- package/dist/cjs/animated-image/props.d.ts +2 -1
- package/dist/cjs/audio/AudioForPreview.js +1 -0
- package/dist/cjs/audio/shared-audio-tags.d.ts +3 -2
- package/dist/cjs/audio/shared-audio-tags.js +26 -7
- package/dist/cjs/audio/use-audio-context.d.ts +4 -0
- package/dist/cjs/audio/use-audio-context.js +36 -0
- package/dist/cjs/calculate-image-fit.d.ts +8 -0
- package/dist/cjs/calculate-image-fit.js +52 -0
- package/dist/cjs/canvas-image/CanvasImage.d.ts +18 -0
- package/dist/cjs/canvas-image/CanvasImage.js +247 -0
- package/dist/cjs/canvas-image/index.d.ts +2 -0
- package/dist/cjs/canvas-image/index.js +5 -0
- package/dist/cjs/canvas-image/props.d.ts +26 -0
- package/dist/cjs/canvas-image/props.js +2 -0
- package/dist/cjs/effects/Solid.js +1 -1
- package/dist/cjs/effects/create-effect.js +2 -0
- package/dist/cjs/effects/effect-types.d.ts +1 -0
- package/dist/cjs/get-timeline-duration.js +2 -1
- package/dist/cjs/index.d.ts +6 -0
- package/dist/cjs/index.js +15 -9
- package/dist/cjs/internals.d.ts +9 -6
- package/dist/cjs/internals.js +11 -12
- package/dist/cjs/loop/index.js +1 -1
- package/dist/cjs/series/index.js +2 -2
- package/dist/cjs/use-media-in-timeline.d.ts +2 -1
- package/dist/cjs/use-media-in-timeline.js +3 -1
- package/dist/cjs/use-schema.d.ts +5 -0
- package/dist/cjs/version.d.ts +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/cjs/video/VideoForPreview.js +5 -0
- package/dist/esm/index.mjs +884 -502
- package/dist/esm/version.mjs +1 -1
- package/package.json +2 -2
package/dist/cjs/HtmlInCanvas.js
CHANGED
|
@@ -235,7 +235,9 @@ const HtmlInCanvasInner = (0, react_1.forwardRef)(({ width, height, effects = []
|
|
|
235
235
|
const { durationInFrames: videoDuration } = (0, use_video_config_js_1.useVideoConfig)();
|
|
236
236
|
const resolvedDuration = durationInFrames !== null && durationInFrames !== void 0 ? durationInFrames : videoDuration;
|
|
237
237
|
const memoizedEffectDefinitions = (0, use_memoized_effects_js_1.useMemoizedEffectDefinitions)(effects);
|
|
238
|
-
return ((0, jsx_runtime_1.jsx)(Sequence_js_1.Sequence, { durationInFrames: resolvedDuration, name: name !== null && name !== void 0 ? name : '<HtmlInCanvas>',
|
|
238
|
+
return ((0, jsx_runtime_1.jsx)(Sequence_js_1.Sequence, { durationInFrames: resolvedDuration, name: name !== null && name !== void 0 ? name : '<HtmlInCanvas>', _remotionInternalDocumentationLink: name === undefined
|
|
239
|
+
? 'https://www.remotion.dev/docs/remotion/html-in-canvas'
|
|
240
|
+
: undefined, _experimentalControls: controls, _remotionInternalEffects: memoizedEffectDefinitions, layout: "none", ...sequenceProps, children: (0, jsx_runtime_1.jsx)(HtmlInCanvasContent, { ref: ref, width: width, height: height, effects: effects, onPaint: onPaint, onInit: onInit, controls: controls, style: style, children: children }) }));
|
|
239
241
|
});
|
|
240
242
|
HtmlInCanvasInner.displayName = 'HtmlInCanvas';
|
|
241
243
|
const htmlInCanvasSchema = {
|
package/dist/cjs/Img.js
CHANGED
|
@@ -25,7 +25,7 @@ function truncateSrcForLabel(src) {
|
|
|
25
25
|
}
|
|
26
26
|
return src;
|
|
27
27
|
}
|
|
28
|
-
const ImgContent = ({ onError, maxRetries = 2, src, pauseWhenLoading, delayRenderRetries, delayRenderTimeoutInMilliseconds, onImageFrame, crossOrigin, ref, ...props }) => {
|
|
28
|
+
const ImgContent = ({ onError, maxRetries = 2, src, pauseWhenLoading, delayRenderRetries, delayRenderTimeoutInMilliseconds, onImageFrame, crossOrigin, decoding, ref, ...props }) => {
|
|
29
29
|
const imageRef = (0, react_1.useRef)(null);
|
|
30
30
|
const errors = (0, react_1.useRef)({});
|
|
31
31
|
const { delayPlayback } = (0, use_buffer_state_js_1.useBufferState)();
|
|
@@ -172,20 +172,20 @@ const ImgContent = ({ onError, maxRetries = 2, src, pauseWhenLoading, delayRende
|
|
|
172
172
|
delayRender,
|
|
173
173
|
]);
|
|
174
174
|
}
|
|
175
|
-
const { isClientSideRendering } = (0, use_remotion_environment_js_1.useRemotionEnvironment)();
|
|
175
|
+
const { isClientSideRendering, isRendering } = (0, use_remotion_environment_js_1.useRemotionEnvironment)();
|
|
176
176
|
const crossOriginValue = (0, get_cross_origin_value_js_1.getCrossOriginValue)({
|
|
177
177
|
crossOrigin,
|
|
178
178
|
requestsVideoFrame: false,
|
|
179
179
|
isClientSideRendering,
|
|
180
180
|
});
|
|
181
181
|
// src gets set once we've loaded and decoded the image.
|
|
182
|
-
return ((0, jsx_runtime_1.jsx)("img", { ...props, ref: imageRef, crossOrigin: crossOriginValue, onError: didGetError, decoding:
|
|
182
|
+
return ((0, jsx_runtime_1.jsx)("img", { ...props, ref: imageRef, crossOrigin: crossOriginValue, onError: didGetError, decoding: isRendering ? 'sync' : decoding }));
|
|
183
183
|
};
|
|
184
184
|
const ImgInner = ({ hidden, name, stack, showInTimeline, src, from, durationInFrames, _experimentalControls: controls, ...props }) => {
|
|
185
185
|
if (!src) {
|
|
186
186
|
throw new Error('No "src" prop was passed to <Img>.');
|
|
187
187
|
}
|
|
188
|
-
return ((0, jsx_runtime_1.jsx)(Sequence_js_1.Sequence, { layout: "none", from: from !== null && from !== void 0 ? from : 0, durationInFrames: durationInFrames !== null && durationInFrames !== void 0 ? durationInFrames : Infinity, _remotionInternalStack: stack, _remotionInternalIsMedia: { type: 'image', src }, name: name !== null && name !== void 0 ? name : '<Img>', _experimentalControls: controls, showInTimeline: showInTimeline !== null && showInTimeline !== void 0 ? showInTimeline : true, hidden: hidden, children: (0, jsx_runtime_1.jsx)(ImgContent, { src: src, ...props }) }));
|
|
188
|
+
return ((0, jsx_runtime_1.jsx)(Sequence_js_1.Sequence, { layout: "none", from: from !== null && from !== void 0 ? from : 0, durationInFrames: durationInFrames !== null && durationInFrames !== void 0 ? durationInFrames : Infinity, _remotionInternalStack: stack, _remotionInternalDocumentationLink: name === undefined ? 'https://www.remotion.dev/docs/img' : undefined, _remotionInternalIsMedia: { type: 'image', src }, name: name !== null && name !== void 0 ? name : '<Img>', _experimentalControls: controls, showInTimeline: showInTimeline !== null && showInTimeline !== void 0 ? showInTimeline : true, hidden: hidden, children: (0, jsx_runtime_1.jsx)(ImgContent, { src: src, ...props }) }));
|
|
189
189
|
};
|
|
190
190
|
const imgSchema = {
|
|
191
191
|
...sequence_field_schema_js_1.sequenceVisualStyleSchema,
|
package/dist/cjs/Sequence.d.ts
CHANGED
|
@@ -40,6 +40,10 @@ export type SequencePropsWithoutDuration = {
|
|
|
40
40
|
* @deprecated For internal use only.
|
|
41
41
|
*/
|
|
42
42
|
readonly _remotionInternalStack?: string;
|
|
43
|
+
/**
|
|
44
|
+
* @deprecated For internal use only.
|
|
45
|
+
*/
|
|
46
|
+
readonly _remotionInternalDocumentationLink?: string;
|
|
43
47
|
/**
|
|
44
48
|
* @deprecated For internal use only.
|
|
45
49
|
*/
|
package/dist/cjs/Sequence.js
CHANGED
|
@@ -18,7 +18,7 @@ const use_remotion_environment_js_1 = require("./use-remotion-environment.js");
|
|
|
18
18
|
const use_video_config_js_1 = require("./use-video-config.js");
|
|
19
19
|
const v5_flag_js_1 = require("./v5-flag.js");
|
|
20
20
|
const wrap_in_schema_js_1 = require("./wrap-in-schema.js");
|
|
21
|
-
const RegularSequenceRefForwardingFunction = ({ from = 0, durationInFrames = Infinity, children, name, height, width, showInTimeline = true, hidden = false, _experimentalControls: controls, _remotionInternalEffects, _remotionInternalLoopDisplay: loopDisplay, _remotionInternalStack: stack, _remotionInternalPremountDisplay: premountDisplay, _remotionInternalPostmountDisplay: postmountDisplay, _remotionInternalIsMedia: isMedia, ...other }, ref) => {
|
|
21
|
+
const RegularSequenceRefForwardingFunction = ({ from = 0, durationInFrames = Infinity, children, name, height, width, showInTimeline = true, hidden = false, _experimentalControls: controls, _remotionInternalEffects, _remotionInternalLoopDisplay: loopDisplay, _remotionInternalStack: stack, _remotionInternalDocumentationLink: documentationLink, _remotionInternalPremountDisplay: premountDisplay, _remotionInternalPostmountDisplay: postmountDisplay, _remotionInternalIsMedia: isMedia, ...other }, ref) => {
|
|
22
22
|
var _a;
|
|
23
23
|
const { layout = 'absolute-fill' } = other;
|
|
24
24
|
const [id] = (0, react_1.useState)(() => String(Math.random()));
|
|
@@ -97,6 +97,7 @@ const RegularSequenceRefForwardingFunction = ({ from = 0, durationInFrames = Inf
|
|
|
97
97
|
const timelineClipName = (0, react_1.useMemo)(() => {
|
|
98
98
|
return name !== null && name !== void 0 ? name : '';
|
|
99
99
|
}, [name]);
|
|
100
|
+
const resolvedDocumentationLink = documentationLink !== null && documentationLink !== void 0 ? documentationLink : (name === undefined ? 'https://www.remotion.dev/docs/sequence' : null);
|
|
100
101
|
const env = (0, use_remotion_environment_js_1.useRemotionEnvironment)();
|
|
101
102
|
const inheritedStack = (_a = other === null || other === void 0 ? void 0 : other.stack) !== null && _a !== void 0 ? _a : null;
|
|
102
103
|
// Our assumption: Stack doesnt' change. After we symbolicate we assign it a nodePath
|
|
@@ -115,6 +116,7 @@ const RegularSequenceRefForwardingFunction = ({ from = 0, durationInFrames = Inf
|
|
|
115
116
|
controls: controls !== null && controls !== void 0 ? controls : null,
|
|
116
117
|
effects: _remotionInternalEffects !== null && _remotionInternalEffects !== void 0 ? _remotionInternalEffects : [],
|
|
117
118
|
displayName: timelineClipName,
|
|
119
|
+
documentationLink: resolvedDocumentationLink,
|
|
118
120
|
duration: actualDurationInFrames,
|
|
119
121
|
from,
|
|
120
122
|
id,
|
|
@@ -135,6 +137,7 @@ const RegularSequenceRefForwardingFunction = ({ from = 0, durationInFrames = Inf
|
|
|
135
137
|
controls: controls !== null && controls !== void 0 ? controls : null,
|
|
136
138
|
effects: _remotionInternalEffects !== null && _remotionInternalEffects !== void 0 ? _remotionInternalEffects : [],
|
|
137
139
|
displayName: timelineClipName,
|
|
140
|
+
documentationLink: resolvedDocumentationLink,
|
|
138
141
|
doesVolumeChange: isMedia.data.doesVolumeChange,
|
|
139
142
|
duration: actualDurationInFrames,
|
|
140
143
|
from,
|
|
@@ -162,6 +165,7 @@ const RegularSequenceRefForwardingFunction = ({ from = 0, durationInFrames = Inf
|
|
|
162
165
|
duration: actualDurationInFrames,
|
|
163
166
|
id,
|
|
164
167
|
displayName: timelineClipName,
|
|
168
|
+
documentationLink: resolvedDocumentationLink,
|
|
165
169
|
parent: (_c = parentSequence === null || parentSequence === void 0 ? void 0 : parentSequence.id) !== null && _c !== void 0 ? _c : null,
|
|
166
170
|
type: 'sequence',
|
|
167
171
|
rootId,
|
|
@@ -197,6 +201,7 @@ const RegularSequenceRefForwardingFunction = ({ from = 0, durationInFrames = Inf
|
|
|
197
201
|
controls,
|
|
198
202
|
_remotionInternalEffects,
|
|
199
203
|
isMedia,
|
|
204
|
+
resolvedDocumentationLink,
|
|
200
205
|
]);
|
|
201
206
|
// Ceil to support floats
|
|
202
207
|
// https://github.com/remotion-dev/remotion/issues/2958
|
|
@@ -158,7 +158,7 @@ const AnimatedImageInner = ({ src, width, height, onError, fit, playbackRate, lo
|
|
|
158
158
|
className,
|
|
159
159
|
style,
|
|
160
160
|
};
|
|
161
|
-
return ((0, jsx_runtime_1.jsx)(Sequence_js_1.Sequence, { layout: "none", durationInFrames: resolvedDuration, name: "<AnimatedImage>", _experimentalControls: controls, _remotionInternalEffects: memoizedEffectDefinitions, ...sequenceProps, children: (0, jsx_runtime_1.jsx)(AnimatedImageContent, { ...animatedImageProps, ref: ref, effects: effects, controls: controls }) }));
|
|
161
|
+
return ((0, jsx_runtime_1.jsx)(Sequence_js_1.Sequence, { layout: "none", durationInFrames: resolvedDuration, name: "<AnimatedImage>", _remotionInternalDocumentationLink: "https://www.remotion.dev/docs/animatedimage", _experimentalControls: controls, _remotionInternalEffects: memoizedEffectDefinitions, ...sequenceProps, children: (0, jsx_runtime_1.jsx)(AnimatedImageContent, { ...animatedImageProps, ref: ref, effects: effects, controls: controls }) }));
|
|
162
162
|
};
|
|
163
163
|
exports.AnimatedImage = (0, wrap_in_schema_js_1.wrapInSchema)(AnimatedImageInner, animatedImageSchema);
|
|
164
164
|
exports.AnimatedImage.displayName = 'AnimatedImage';
|
|
@@ -36,56 +36,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.Canvas = void 0;
|
|
37
37
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
38
38
|
const react_1 = __importStar(require("react"));
|
|
39
|
+
const calculate_image_fit_js_1 = require("../calculate-image-fit.js");
|
|
39
40
|
const run_effect_chain_js_1 = require("../effects/run-effect-chain.js");
|
|
40
41
|
const use_effect_chain_state_js_1 = require("../effects/use-effect-chain-state.js");
|
|
41
|
-
const calcArgs = (fit, frameSize, canvasSize) => {
|
|
42
|
-
switch (fit) {
|
|
43
|
-
case 'fill': {
|
|
44
|
-
return [
|
|
45
|
-
0,
|
|
46
|
-
0,
|
|
47
|
-
frameSize.width,
|
|
48
|
-
frameSize.height,
|
|
49
|
-
0,
|
|
50
|
-
0,
|
|
51
|
-
canvasSize.width,
|
|
52
|
-
canvasSize.height,
|
|
53
|
-
];
|
|
54
|
-
}
|
|
55
|
-
case 'contain': {
|
|
56
|
-
const ratio = Math.min(canvasSize.width / frameSize.width, canvasSize.height / frameSize.height);
|
|
57
|
-
const centerX = (canvasSize.width - frameSize.width * ratio) / 2;
|
|
58
|
-
const centerY = (canvasSize.height - frameSize.height * ratio) / 2;
|
|
59
|
-
return [
|
|
60
|
-
0,
|
|
61
|
-
0,
|
|
62
|
-
frameSize.width,
|
|
63
|
-
frameSize.height,
|
|
64
|
-
centerX,
|
|
65
|
-
centerY,
|
|
66
|
-
frameSize.width * ratio,
|
|
67
|
-
frameSize.height * ratio,
|
|
68
|
-
];
|
|
69
|
-
}
|
|
70
|
-
case 'cover': {
|
|
71
|
-
const ratio = Math.max(canvasSize.width / frameSize.width, canvasSize.height / frameSize.height);
|
|
72
|
-
const centerX = (canvasSize.width - frameSize.width * ratio) / 2;
|
|
73
|
-
const centerY = (canvasSize.height - frameSize.height * ratio) / 2;
|
|
74
|
-
return [
|
|
75
|
-
0,
|
|
76
|
-
0,
|
|
77
|
-
frameSize.width,
|
|
78
|
-
frameSize.height,
|
|
79
|
-
centerX,
|
|
80
|
-
centerY,
|
|
81
|
-
frameSize.width * ratio,
|
|
82
|
-
frameSize.height * ratio,
|
|
83
|
-
];
|
|
84
|
-
}
|
|
85
|
-
default:
|
|
86
|
-
throw new Error('Unknown fit: ' + fit);
|
|
87
|
-
}
|
|
88
|
-
};
|
|
89
42
|
const CanvasRefForwardingFunction = ({ width, height, fit, className, style, effects }, ref) => {
|
|
90
43
|
const canvasRef = (0, react_1.useRef)(null);
|
|
91
44
|
const chainState = (0, use_effect_chain_state_js_1.useEffectChainState)();
|
|
@@ -95,7 +48,7 @@ const CanvasRefForwardingFunction = ({ width, height, fit, className, style, eff
|
|
|
95
48
|
}
|
|
96
49
|
return document.createElement('canvas');
|
|
97
50
|
}, []);
|
|
98
|
-
const draw = (0, react_1.useCallback)(
|
|
51
|
+
const draw = (0, react_1.useCallback)((imageData) => {
|
|
99
52
|
const canvas = canvasRef.current;
|
|
100
53
|
const canvasWidth = width !== null && width !== void 0 ? width : imageData.displayWidth;
|
|
101
54
|
const canvasHeight = height !== null && height !== void 0 ? height : imageData.displayHeight;
|
|
@@ -111,7 +64,7 @@ const CanvasRefForwardingFunction = ({ width, height, fit, className, style, eff
|
|
|
111
64
|
if (!sourceCtx) {
|
|
112
65
|
throw new Error('Could not get 2d context for source canvas');
|
|
113
66
|
}
|
|
114
|
-
sourceCtx.drawImage(imageData, ...
|
|
67
|
+
sourceCtx.drawImage(imageData, ...(0, calculate_image_fit_js_1.calculateImageFit)(fit, {
|
|
115
68
|
height: imageData.displayHeight,
|
|
116
69
|
width: imageData.displayWidth,
|
|
117
70
|
}, {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ImageFit } from '../calculate-image-fit.js';
|
|
1
2
|
import type { EffectsProp } from '../effects/effect-types.js';
|
|
2
3
|
import type { SequenceProps } from '../Sequence.js';
|
|
3
4
|
export type RemotionAnimatedImageLoopBehavior = 'loop' | 'pause-after-finish' | 'clear-after-finish';
|
|
@@ -17,4 +18,4 @@ export type AnimatedImageProps = Omit<SequenceProps, 'children' | 'durationInFra
|
|
|
17
18
|
readonly durationInFrames?: number;
|
|
18
19
|
readonly effects?: EffectsProp;
|
|
19
20
|
};
|
|
20
|
-
export type AnimatedImageFillMode =
|
|
21
|
+
export type AnimatedImageFillMode = ImageFit;
|
|
@@ -134,6 +134,7 @@ const AudioForDevelopmentForwardRefFunction = (props, ref) => {
|
|
|
134
134
|
premountDisplay: (_a = sequenceContext === null || sequenceContext === void 0 ? void 0 : sequenceContext.premountDisplay) !== null && _a !== void 0 ? _a : null,
|
|
135
135
|
postmountDisplay: (_b = sequenceContext === null || sequenceContext === void 0 ? void 0 : sequenceContext.postmountDisplay) !== null && _b !== void 0 ? _b : null,
|
|
136
136
|
loopDisplay: undefined,
|
|
137
|
+
documentationLink: name === undefined ? 'https://www.remotion.dev/docs/html5-audio' : null,
|
|
137
138
|
});
|
|
138
139
|
// putting playback before useVolume
|
|
139
140
|
// because volume looks at playbackrate
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type AudioHTMLAttributes } from 'react';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import type { SharedElementSourceNode } from './shared-element-source-node.js';
|
|
4
|
+
import type { RemotionAudioContextState } from './use-audio-context.js';
|
|
4
5
|
/**
|
|
5
6
|
* This functionality of Remotion will keep a certain amount
|
|
6
7
|
* of <audio> tags pre-mounted and by default filled with an empty audio track.
|
|
@@ -33,7 +34,6 @@ export type ScheduleAudioNodeResult = {
|
|
|
33
34
|
export type ScheduleAudioNodeOptions = {
|
|
34
35
|
readonly node: AudioBufferSourceNode;
|
|
35
36
|
readonly mediaTimestamp: number;
|
|
36
|
-
readonly currentTime: number;
|
|
37
37
|
readonly scheduledTime: number;
|
|
38
38
|
readonly originalUnloopedMediaTimestamp: number;
|
|
39
39
|
readonly duration: number;
|
|
@@ -49,6 +49,7 @@ export type AudioSyncAnchorEmitter = {
|
|
|
49
49
|
};
|
|
50
50
|
type SharedAudioContextValue = {
|
|
51
51
|
audioContext: AudioContext | null;
|
|
52
|
+
getAudioContextState: () => RemotionAudioContextState | null;
|
|
52
53
|
gainNode: GainNode | null;
|
|
53
54
|
audioSyncAnchor: {
|
|
54
55
|
value: number;
|
|
@@ -56,7 +57,7 @@ type SharedAudioContextValue = {
|
|
|
56
57
|
audioSyncAnchorEmitter: AudioSyncAnchorEmitter;
|
|
57
58
|
scheduleAudioNode: (options: ScheduleAudioNodeOptions) => ScheduleAudioNodeResult;
|
|
58
59
|
resume: () => Promise<void>;
|
|
59
|
-
suspend: () => void
|
|
60
|
+
suspend: () => Promise<void>;
|
|
60
61
|
getIsResumingAudioContext: () => Promise<void> | null;
|
|
61
62
|
unscheduleAudioNode: (node: AudioBufferSourceNode) => void;
|
|
62
63
|
};
|
|
@@ -77,6 +77,17 @@ const didPropChange = (key, newProp, prevProp) => {
|
|
|
77
77
|
};
|
|
78
78
|
exports.SharedAudioContext = (0, react_1.createContext)(null);
|
|
79
79
|
exports.SharedAudioTagsContext = (0, react_1.createContext)(null);
|
|
80
|
+
const shouldSaveForLater = (state) => {
|
|
81
|
+
if (state === 'suspended' ||
|
|
82
|
+
state === 'running-to-suspended' ||
|
|
83
|
+
state === 'interrupted') {
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
if (state === 'running' || state === 'suspended-to-running') {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
throw new Error(`Unexpected audio context state: ${state}`);
|
|
90
|
+
};
|
|
80
91
|
const SharedAudioContextProvider = ({ children, audioLatencyHint, audioEnabled }) => {
|
|
81
92
|
const logLevel = (0, log_level_context_js_1.useLogLevel)();
|
|
82
93
|
const ctxAndGain = (0, use_audio_context_js_1.useSingletonAudioContext)({
|
|
@@ -110,11 +121,18 @@ const SharedAudioContextProvider = ({ children, audioLatencyHint, audioEnabled }
|
|
|
110
121
|
nodesToResume.current.delete(node);
|
|
111
122
|
}, []);
|
|
112
123
|
const scheduleAudioNode = (0, react_1.useMemo)(() => {
|
|
113
|
-
return ({ node, mediaTimestamp,
|
|
124
|
+
return ({ node, mediaTimestamp, scheduledTime, duration, offset, originalUnloopedMediaTimestamp, }) => {
|
|
114
125
|
if (!ctxAndGain) {
|
|
115
126
|
throw new Error('Audio context not found');
|
|
116
127
|
}
|
|
117
|
-
const
|
|
128
|
+
const currentState = ctxAndGain.getState();
|
|
129
|
+
if (currentState === 'closed') {
|
|
130
|
+
return {
|
|
131
|
+
type: 'not-started',
|
|
132
|
+
reason: 'audio context is closed',
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
const saveForLater = shouldSaveForLater(currentState);
|
|
118
136
|
if (duration > 0) {
|
|
119
137
|
if (saveForLater) {
|
|
120
138
|
nodesToResume.current.set(node, {
|
|
@@ -145,7 +163,7 @@ const SharedAudioContextProvider = ({ children, audioLatencyHint, audioEnabled }
|
|
|
145
163
|
: 'color: blue; font-weight: bold', duration < 0
|
|
146
164
|
? 'missed ' + Math.abs(offset).toFixed(2) + 's'
|
|
147
165
|
: Math.abs(timeDiff).toFixed(2) +
|
|
148
|
-
(timeDiff < 0 ? ' delay' : ' ahead'), '', 'current=' +
|
|
166
|
+
(timeDiff < 0 ? ' delay' : ' ahead'), '', 'current=' + ctxAndGain.audioContext.currentTime.toFixed(4), 'offset=' + offset.toFixed(4), 'latency=' + latency.toFixed(4), 'state=' + ctxAndGain.audioContext.state, originalUnloopedMediaTimestamp !== mediaTime
|
|
149
167
|
? 'original_ts=' + originalUnloopedMediaTimestamp.toFixed(4)
|
|
150
168
|
: '', 'action=' + (saveForLater ? 'schedule' : 'start'), '');
|
|
151
169
|
prev.scheduledEndTime = scheduledEndTime;
|
|
@@ -176,7 +194,7 @@ const SharedAudioContextProvider = ({ children, audioLatencyHint, audioEnabled }
|
|
|
176
194
|
node.start(r.scheduledTime, r.offset, r.duration);
|
|
177
195
|
});
|
|
178
196
|
nodesToResume.current.clear();
|
|
179
|
-
const resumePromise = ctxAndGain.
|
|
197
|
+
const resumePromise = ctxAndGain.resume();
|
|
180
198
|
isResuming.current = new Promise((resolve) => {
|
|
181
199
|
(0, wait_until_actually_resumed_js_1.waitUntilActuallyResumed)(ctxAndGain.audioContext, logLevel).then(resolve);
|
|
182
200
|
resumePromise.catch((err) => {
|
|
@@ -196,18 +214,19 @@ const SharedAudioContextProvider = ({ children, audioLatencyHint, audioEnabled }
|
|
|
196
214
|
}, []);
|
|
197
215
|
const suspend = (0, react_1.useCallback)(() => {
|
|
198
216
|
if (!ctxAndGain) {
|
|
199
|
-
return;
|
|
217
|
+
return Promise.resolve();
|
|
200
218
|
}
|
|
201
219
|
if (!audioContextIsPlayingEventually.current) {
|
|
202
|
-
return;
|
|
220
|
+
return Promise.resolve();
|
|
203
221
|
}
|
|
204
222
|
audioContextIsPlayingEventually.current = false;
|
|
205
|
-
ctxAndGain.
|
|
223
|
+
return ctxAndGain.suspend();
|
|
206
224
|
}, [ctxAndGain]);
|
|
207
225
|
const audioContextValue = (0, react_1.useMemo)(() => {
|
|
208
226
|
var _a, _b;
|
|
209
227
|
return {
|
|
210
228
|
audioContext: (_a = ctxAndGain === null || ctxAndGain === void 0 ? void 0 : ctxAndGain.audioContext) !== null && _a !== void 0 ? _a : null,
|
|
229
|
+
getAudioContextState: () => { var _a; return (_a = ctxAndGain === null || ctxAndGain === void 0 ? void 0 : ctxAndGain.getState()) !== null && _a !== void 0 ? _a : null; },
|
|
211
230
|
gainNode: (_b = ctxAndGain === null || ctxAndGain === void 0 ? void 0 : ctxAndGain.gainNode) !== null && _b !== void 0 ? _b : null,
|
|
212
231
|
audioSyncAnchor,
|
|
213
232
|
audioSyncAnchorEmitter,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { LogLevel } from '../log';
|
|
2
|
+
export type RemotionAudioContextState = AudioContextState | 'running-to-suspended' | 'suspended-to-running';
|
|
2
3
|
export declare const useSingletonAudioContext: ({ logLevel, latencyHint, audioEnabled, }: {
|
|
3
4
|
logLevel: LogLevel;
|
|
4
5
|
latencyHint: AudioContextLatencyCategory;
|
|
@@ -6,4 +7,7 @@ export declare const useSingletonAudioContext: ({ logLevel, latencyHint, audioEn
|
|
|
6
7
|
}) => {
|
|
7
8
|
audioContext: AudioContext;
|
|
8
9
|
gainNode: GainNode;
|
|
10
|
+
getState: () => RemotionAudioContextState;
|
|
11
|
+
resume: () => Promise<void>;
|
|
12
|
+
suspend: () => Promise<void>;
|
|
9
13
|
} | null;
|
|
@@ -39,9 +39,45 @@ const useSingletonAudioContext = ({ logLevel, latencyHint, audioEnabled, }) => {
|
|
|
39
39
|
gainNode.connect(audioContext.destination);
|
|
40
40
|
log_1.Log.trace({ logLevel, tag: 'audio' }, 'Creating new audio context');
|
|
41
41
|
audioContext.suspend();
|
|
42
|
+
// Tracks the state we are transitioning towards while resume()/suspend()
|
|
43
|
+
// have been called but the native state has not updated yet.
|
|
44
|
+
let transitionTarget = null;
|
|
45
|
+
const getState = () => {
|
|
46
|
+
const nativeState = audioContext.state;
|
|
47
|
+
if (transitionTarget === 'running' && nativeState !== 'running') {
|
|
48
|
+
return 'suspended-to-running';
|
|
49
|
+
}
|
|
50
|
+
if (transitionTarget === 'suspended' && nativeState !== 'suspended') {
|
|
51
|
+
return 'running-to-suspended';
|
|
52
|
+
}
|
|
53
|
+
return nativeState;
|
|
54
|
+
};
|
|
55
|
+
const resume = () => {
|
|
56
|
+
transitionTarget = 'running';
|
|
57
|
+
const promise = audioContext.resume();
|
|
58
|
+
promise.finally(() => {
|
|
59
|
+
if (transitionTarget === 'running') {
|
|
60
|
+
transitionTarget = null;
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
return promise;
|
|
64
|
+
};
|
|
65
|
+
const suspend = () => {
|
|
66
|
+
transitionTarget = 'suspended';
|
|
67
|
+
const promise = audioContext.suspend();
|
|
68
|
+
promise.finally(() => {
|
|
69
|
+
if (transitionTarget === 'suspended') {
|
|
70
|
+
transitionTarget = null;
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
return promise;
|
|
74
|
+
};
|
|
42
75
|
return {
|
|
43
76
|
audioContext,
|
|
44
77
|
gainNode,
|
|
78
|
+
getState,
|
|
79
|
+
resume,
|
|
80
|
+
suspend,
|
|
45
81
|
};
|
|
46
82
|
}, [logLevel, latencyHint, env.isRendering, audioEnabled]);
|
|
47
83
|
return context;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type ImageFit = 'contain' | 'cover' | 'fill';
|
|
2
|
+
export declare const calculateImageFit: (fit: ImageFit, imageSize: {
|
|
3
|
+
width: number;
|
|
4
|
+
height: number;
|
|
5
|
+
}, canvasSize: {
|
|
6
|
+
width: number;
|
|
7
|
+
height: number;
|
|
8
|
+
}) => [number, number, number, number, number, number, number, number];
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.calculateImageFit = void 0;
|
|
4
|
+
const calculateImageFit = (fit, imageSize, canvasSize) => {
|
|
5
|
+
switch (fit) {
|
|
6
|
+
case 'fill': {
|
|
7
|
+
return [
|
|
8
|
+
0,
|
|
9
|
+
0,
|
|
10
|
+
imageSize.width,
|
|
11
|
+
imageSize.height,
|
|
12
|
+
0,
|
|
13
|
+
0,
|
|
14
|
+
canvasSize.width,
|
|
15
|
+
canvasSize.height,
|
|
16
|
+
];
|
|
17
|
+
}
|
|
18
|
+
case 'contain': {
|
|
19
|
+
const ratio = Math.min(canvasSize.width / imageSize.width, canvasSize.height / imageSize.height);
|
|
20
|
+
const centerX = (canvasSize.width - imageSize.width * ratio) / 2;
|
|
21
|
+
const centerY = (canvasSize.height - imageSize.height * ratio) / 2;
|
|
22
|
+
return [
|
|
23
|
+
0,
|
|
24
|
+
0,
|
|
25
|
+
imageSize.width,
|
|
26
|
+
imageSize.height,
|
|
27
|
+
centerX,
|
|
28
|
+
centerY,
|
|
29
|
+
imageSize.width * ratio,
|
|
30
|
+
imageSize.height * ratio,
|
|
31
|
+
];
|
|
32
|
+
}
|
|
33
|
+
case 'cover': {
|
|
34
|
+
const ratio = Math.max(canvasSize.width / imageSize.width, canvasSize.height / imageSize.height);
|
|
35
|
+
const centerX = (canvasSize.width - imageSize.width * ratio) / 2;
|
|
36
|
+
const centerY = (canvasSize.height - imageSize.height * ratio) / 2;
|
|
37
|
+
return [
|
|
38
|
+
0,
|
|
39
|
+
0,
|
|
40
|
+
imageSize.width,
|
|
41
|
+
imageSize.height,
|
|
42
|
+
centerX,
|
|
43
|
+
centerY,
|
|
44
|
+
imageSize.width * ratio,
|
|
45
|
+
imageSize.height * ratio,
|
|
46
|
+
];
|
|
47
|
+
}
|
|
48
|
+
default:
|
|
49
|
+
throw new Error('Unknown fit: ' + fit);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
exports.calculateImageFit = calculateImageFit;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { EffectsProp } from '../effects/effect-types.js';
|
|
2
|
+
export declare const CanvasImage: import("react").ComponentType<Pick<import("../Sequence.js").SequenceProps, "hidden" | "name" | "durationInFrames" | "from" | "showInTimeline"> & {
|
|
3
|
+
readonly stack?: string;
|
|
4
|
+
} & {
|
|
5
|
+
readonly src: string;
|
|
6
|
+
readonly width?: number;
|
|
7
|
+
readonly height?: number;
|
|
8
|
+
readonly fit?: import("../calculate-image-fit.js").ImageFit;
|
|
9
|
+
readonly effects?: EffectsProp;
|
|
10
|
+
readonly className?: string;
|
|
11
|
+
readonly style?: React.CSSProperties;
|
|
12
|
+
readonly id?: string;
|
|
13
|
+
readonly onError?: (error: Error) => void;
|
|
14
|
+
readonly pauseWhenLoading?: boolean;
|
|
15
|
+
readonly maxRetries?: number;
|
|
16
|
+
readonly delayRenderRetries?: number;
|
|
17
|
+
readonly delayRenderTimeoutInMilliseconds?: number;
|
|
18
|
+
} & import("react").RefAttributes<HTMLCanvasElement>>;
|