remotion 4.0.486 → 4.0.487
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/HtmlInCanvas.js +2 -4
- package/dist/cjs/Still.js +2 -0
- package/dist/cjs/TimelineContext.d.ts +3 -3
- package/dist/cjs/buffering.d.ts +1 -1
- package/dist/cjs/buffering.js +14 -6
- package/dist/cjs/get-media-sync-action.d.ts +44 -0
- package/dist/cjs/get-media-sync-action.js +78 -0
- package/dist/cjs/internals.d.ts +2 -2
- package/dist/cjs/timeline-position-state.d.ts +2 -2
- package/dist/cjs/use-media-playback.js +70 -82
- package/dist/cjs/use-request-video-callback-time.d.ts +1 -1
- package/dist/cjs/version.d.ts +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/cjs/wrap-remotion-context.d.ts +1 -1
- package/dist/esm/index.mjs +147 -76
- package/dist/esm/version.mjs +1 -1
- package/package.json +2 -2
package/dist/cjs/HtmlInCanvas.js
CHANGED
|
@@ -104,8 +104,7 @@ const HtmlInCanvasContent = (0, react_1.forwardRef)(({ width, height, effects, c
|
|
|
104
104
|
ref(node);
|
|
105
105
|
}
|
|
106
106
|
else if (ref) {
|
|
107
|
-
ref.current =
|
|
108
|
-
node;
|
|
107
|
+
ref.current = node;
|
|
109
108
|
}
|
|
110
109
|
}, [ref]);
|
|
111
110
|
const chainState = (0, use_effect_chain_state_js_1.useEffectChainState)();
|
|
@@ -319,8 +318,7 @@ const HtmlInCanvasInner = (0, react_1.forwardRef)(({ width, height, effects = []
|
|
|
319
318
|
ref(node);
|
|
320
319
|
}
|
|
321
320
|
else if (ref) {
|
|
322
|
-
ref.current =
|
|
323
|
-
node;
|
|
321
|
+
ref.current = node;
|
|
324
322
|
}
|
|
325
323
|
}, [ref]);
|
|
326
324
|
return (jsx_runtime_1.jsx(Sequence_js_1.Sequence, { durationInFrames: resolvedDuration, name: name !== null && name !== void 0 ? name : '<HtmlInCanvas>', _remotionInternalDocumentationLink: "https://www.remotion.dev/docs/remotion/html-in-canvas", controls: controls, _remotionInternalEffects: memoizedEffectDefinitions, outlineRef: actualRef, layout: "none", ...sequenceProps, children: jsx_runtime_1.jsx(HtmlInCanvasContent, { ref: setCanvasRef, width: width, height: height, effects: effects, onPaint: onPaint, onInit: onInit, pixelDensity: pixelDensity, controls: controls, style: style, children: children }) }));
|
package/dist/cjs/Still.js
CHANGED
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.Still = void 0;
|
|
7
7
|
const react_1 = __importDefault(require("react"));
|
|
8
8
|
const Composition_js_1 = require("./Composition.js");
|
|
9
|
+
const enable_sequence_stack_traces_js_1 = require("./enable-sequence-stack-traces.js");
|
|
9
10
|
/*
|
|
10
11
|
* @description A `<Still />` is a `<Composition />` that is only 1 frame long.
|
|
11
12
|
* @see [Documentation](https://www.remotion.dev/docs/still)
|
|
@@ -20,3 +21,4 @@ const Still = (props) => {
|
|
|
20
21
|
return react_1.default.createElement(Composition_js_1.Composition, newProps);
|
|
21
22
|
};
|
|
22
23
|
exports.Still = Still;
|
|
24
|
+
(0, enable_sequence_stack_traces_js_1.addSequenceStackTraces)(exports.Still);
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { RefObject } from 'react';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { type PlayableMediaTag } from './timeline-position-state';
|
|
4
4
|
export type TimelineContextValue = {
|
|
5
5
|
frame: Record<string, number>;
|
|
6
6
|
playing: boolean;
|
|
7
7
|
rootId: string;
|
|
8
|
-
imperativePlaying:
|
|
9
|
-
audioAndVideoTags:
|
|
8
|
+
imperativePlaying: RefObject<boolean>;
|
|
9
|
+
audioAndVideoTags: RefObject<PlayableMediaTag[]>;
|
|
10
10
|
};
|
|
11
11
|
export type PlaybackRateContextValue = {
|
|
12
12
|
playbackRate: number;
|
package/dist/cjs/buffering.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ type BufferManager = {
|
|
|
17
17
|
addBlock: AddBlock;
|
|
18
18
|
listenForBuffering: ListenForBuffering;
|
|
19
19
|
listenForResume: ListenForResume;
|
|
20
|
-
buffering: React.
|
|
20
|
+
buffering: React.RefObject<boolean>;
|
|
21
21
|
};
|
|
22
22
|
export declare const BufferingContextReact: React.Context<BufferManager | null>;
|
|
23
23
|
export declare const BufferingProvider: React.FC<{
|
package/dist/cjs/buffering.js
CHANGED
|
@@ -90,7 +90,11 @@ const useBufferManager = (logLevel, mountTime) => {
|
|
|
90
90
|
if (rendering) {
|
|
91
91
|
return;
|
|
92
92
|
}
|
|
93
|
-
|
|
93
|
+
// Only fire on the `false -> true` transition: adding a block while
|
|
94
|
+
// already buffering (e.g. a second media element starts loading) must
|
|
95
|
+
// not re-dispatch `waiting` to listeners.
|
|
96
|
+
if (blocks.length > 0 && !buffering.current) {
|
|
97
|
+
buffering.current = true;
|
|
94
98
|
onBufferingCallbacks.forEach((c) => c());
|
|
95
99
|
(0, playback_logging_1.playbackLogging)({
|
|
96
100
|
logLevel,
|
|
@@ -110,7 +114,11 @@ const useBufferManager = (logLevel, mountTime) => {
|
|
|
110
114
|
if (rendering) {
|
|
111
115
|
return;
|
|
112
116
|
}
|
|
113
|
-
|
|
117
|
+
// Only fire on the `true -> false` transition: the initial mount and
|
|
118
|
+
// a block that was added and removed within the same commit must not
|
|
119
|
+
// dispatch `resume` to listeners.
|
|
120
|
+
if (blocks.length === 0 && buffering.current) {
|
|
121
|
+
buffering.current = false;
|
|
114
122
|
onResumeCallbacks.forEach((c) => c());
|
|
115
123
|
(0, playback_logging_1.playbackLogging)({
|
|
116
124
|
logLevel,
|
|
@@ -145,11 +153,11 @@ const useIsPlayerBuffering = (bufferManager) => {
|
|
|
145
153
|
const onResume = () => {
|
|
146
154
|
setIsBuffering(false);
|
|
147
155
|
};
|
|
148
|
-
bufferManager.listenForBuffering(onBuffer);
|
|
149
|
-
bufferManager.listenForResume(onResume);
|
|
156
|
+
const buffer = bufferManager.listenForBuffering(onBuffer);
|
|
157
|
+
const resume = bufferManager.listenForResume(onResume);
|
|
150
158
|
return () => {
|
|
151
|
-
|
|
152
|
-
|
|
159
|
+
buffer.remove();
|
|
160
|
+
resume.remove();
|
|
153
161
|
};
|
|
154
162
|
}, [bufferManager]);
|
|
155
163
|
return isBuffering;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export type MediaSyncAction = {
|
|
2
|
+
type: 'seek-due-to-shift';
|
|
3
|
+
shouldBeTime: number;
|
|
4
|
+
why: string;
|
|
5
|
+
bufferUntilFirstFrame: boolean;
|
|
6
|
+
playReason: string | null;
|
|
7
|
+
warnAboutNonSeekable: boolean;
|
|
8
|
+
} | {
|
|
9
|
+
type: 'seek-if-not-playing';
|
|
10
|
+
shouldBeTime: number;
|
|
11
|
+
why: string | null;
|
|
12
|
+
} | {
|
|
13
|
+
type: 'play-and-seek';
|
|
14
|
+
shouldBeTime: number;
|
|
15
|
+
why: string | null;
|
|
16
|
+
playReason: string;
|
|
17
|
+
bufferUntilFirstFrame: boolean;
|
|
18
|
+
} | {
|
|
19
|
+
type: 'none';
|
|
20
|
+
};
|
|
21
|
+
export type GetMediaSyncActionInput = {
|
|
22
|
+
duration: number;
|
|
23
|
+
currentTime: number;
|
|
24
|
+
paused: boolean;
|
|
25
|
+
ended: boolean;
|
|
26
|
+
desiredUnclampedTime: number;
|
|
27
|
+
mediaTagTime: number;
|
|
28
|
+
mediaTagLastUpdate: number;
|
|
29
|
+
rvcTime: number | null;
|
|
30
|
+
rvcLastUpdate: number | null;
|
|
31
|
+
isVariableFpsVideo: boolean;
|
|
32
|
+
acceptableTimeShift: number;
|
|
33
|
+
lastSeekDueToShift: number | null;
|
|
34
|
+
playing: boolean;
|
|
35
|
+
playbackRate: number;
|
|
36
|
+
mediaTagBufferingOrStalled: boolean;
|
|
37
|
+
playerBuffering: boolean;
|
|
38
|
+
absoluteFrame: number;
|
|
39
|
+
onlyWarnForMediaSeekingError: boolean;
|
|
40
|
+
isPremounting: boolean;
|
|
41
|
+
isPostmounting: boolean;
|
|
42
|
+
pauseWhenBuffering: boolean;
|
|
43
|
+
};
|
|
44
|
+
export declare const getMediaSyncAction: (input: GetMediaSyncActionInput) => MediaSyncAction;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Pure decision logic for `useMediaPlayback`.
|
|
3
|
+
//
|
|
4
|
+
// Every frame, the media element's clock has to be reconciled with the
|
|
5
|
+
// timeline clock. This function takes a snapshot of the relevant state and
|
|
6
|
+
// decides *what* should happen (seek / play / buffer / nothing). The effect in
|
|
7
|
+
// `use-media-playback.ts` is responsible for actually executing the returned
|
|
8
|
+
// action. Keeping the decision separate makes the branch ordering testable
|
|
9
|
+
// without a DOM or a real media element.
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.getMediaSyncAction = void 0;
|
|
12
|
+
const getMediaSyncAction = (input) => {
|
|
13
|
+
const { duration, currentTime, paused, ended, desiredUnclampedTime, mediaTagTime, mediaTagLastUpdate, rvcTime, rvcLastUpdate, isVariableFpsVideo, acceptableTimeShift, lastSeekDueToShift, playing, playbackRate, mediaTagBufferingOrStalled, playerBuffering, absoluteFrame, onlyWarnForMediaSeekingError, isPremounting, isPostmounting, pauseWhenBuffering, } = input;
|
|
14
|
+
const shouldBeTime = !Number.isNaN(duration) && Number.isFinite(duration)
|
|
15
|
+
? Math.min(duration, desiredUnclampedTime)
|
|
16
|
+
: desiredUnclampedTime;
|
|
17
|
+
const timeShiftMediaTag = Math.abs(shouldBeTime - mediaTagTime);
|
|
18
|
+
const timeShiftRvcTag = rvcTime ? Math.abs(shouldBeTime - rvcTime) : null;
|
|
19
|
+
const mostRecentTimeshift = rvcLastUpdate && rvcTime > mediaTagLastUpdate
|
|
20
|
+
? timeShiftRvcTag
|
|
21
|
+
: timeShiftMediaTag;
|
|
22
|
+
const timeShift = timeShiftRvcTag && !isVariableFpsVideo
|
|
23
|
+
? mostRecentTimeshift
|
|
24
|
+
: timeShiftMediaTag;
|
|
25
|
+
if (timeShift > acceptableTimeShift && lastSeekDueToShift !== shouldBeTime) {
|
|
26
|
+
// If scrubbing around, adjust timing
|
|
27
|
+
// or if time shift is bigger than 0.45sec
|
|
28
|
+
return {
|
|
29
|
+
type: 'seek-due-to-shift',
|
|
30
|
+
shouldBeTime,
|
|
31
|
+
why: `because time shift is too big. shouldBeTime = ${shouldBeTime}, isTime = ${mediaTagTime}, requestVideoCallbackTime = ${rvcTime}, timeShift = ${timeShift}${isVariableFpsVideo ? ', isVariableFpsVideo = true' : ''}, isPremounting = ${isPremounting}, isPostmounting = ${isPostmounting}, pauseWhenBuffering = ${pauseWhenBuffering}`,
|
|
32
|
+
bufferUntilFirstFrame: playing && playbackRate > 0,
|
|
33
|
+
playReason: playing && paused
|
|
34
|
+
? 'player is playing but media tag is paused, and just seeked'
|
|
35
|
+
: null,
|
|
36
|
+
warnAboutNonSeekable: !onlyWarnForMediaSeekingError,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
const seekThreshold = playing ? 0.15 : 0.01;
|
|
40
|
+
// Only perform a seek if the time is not already the same.
|
|
41
|
+
// Chrome rounds to 6 digits, so 0.033333333 -> 0.033333,
|
|
42
|
+
// therefore a threshold is allowed.
|
|
43
|
+
// Refer to the https://github.com/remotion-dev/video-buffering-example
|
|
44
|
+
// which is fixed by only seeking conditionally.
|
|
45
|
+
const makesSenseToSeek = Math.abs(currentTime - shouldBeTime) > seekThreshold;
|
|
46
|
+
const isSomethingElseBuffering = playerBuffering && !mediaTagBufferingOrStalled;
|
|
47
|
+
if (!playing || isSomethingElseBuffering) {
|
|
48
|
+
return {
|
|
49
|
+
type: 'seek-if-not-playing',
|
|
50
|
+
shouldBeTime,
|
|
51
|
+
why: makesSenseToSeek
|
|
52
|
+
? `not playing or something else is buffering. time offset is over seek threshold (${seekThreshold})`
|
|
53
|
+
: null,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
if (!playing || playerBuffering) {
|
|
57
|
+
return { type: 'none' };
|
|
58
|
+
}
|
|
59
|
+
// We now assured we are in playing state and not buffering
|
|
60
|
+
const pausedCondition = paused && !ended;
|
|
61
|
+
const firstFrameCondition = absoluteFrame === 0;
|
|
62
|
+
if (pausedCondition || firstFrameCondition) {
|
|
63
|
+
const reason = pausedCondition
|
|
64
|
+
? 'media tag is paused'
|
|
65
|
+
: 'absolute frame is 0';
|
|
66
|
+
return {
|
|
67
|
+
type: 'play-and-seek',
|
|
68
|
+
shouldBeTime,
|
|
69
|
+
why: makesSenseToSeek
|
|
70
|
+
? `is over timeshift threshold (threshold = ${seekThreshold}) and ${reason}`
|
|
71
|
+
: null,
|
|
72
|
+
playReason: `player is playing and ${reason}`,
|
|
73
|
+
bufferUntilFirstFrame: !isVariableFpsVideo && playbackRate > 0,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
return { type: 'none' };
|
|
77
|
+
};
|
|
78
|
+
exports.getMediaSyncAction = getMediaSyncAction;
|
package/dist/cjs/internals.d.ts
CHANGED
|
@@ -694,7 +694,7 @@ export declare const Internals: {
|
|
|
694
694
|
listenForResume: (callback: () => void) => {
|
|
695
695
|
remove: () => void;
|
|
696
696
|
};
|
|
697
|
-
buffering: import("react").
|
|
697
|
+
buffering: import("react").RefObject<boolean>;
|
|
698
698
|
} | null>;
|
|
699
699
|
readonly getComponentsToAddStacksTo: () => unknown[];
|
|
700
700
|
readonly CurrentScaleContext: import("react").Context<import("./use-current-scale.js").CurrentScaleContextType | null>;
|
|
@@ -823,7 +823,7 @@ export declare const Internals: {
|
|
|
823
823
|
listenForResume: (callback: () => void) => {
|
|
824
824
|
remove: () => void;
|
|
825
825
|
};
|
|
826
|
-
buffering: import("react").
|
|
826
|
+
buffering: import("react").RefObject<boolean>;
|
|
827
827
|
}) => boolean;
|
|
828
828
|
readonly TimelinePosition: typeof TimelinePosition;
|
|
829
829
|
readonly DelayRenderContextType: import("react").Context<import("./delay-render.js").DelayRenderScope | null>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { RefObject } from 'react';
|
|
2
2
|
import { type PlaybackRateContextValue, type TimelineContextValue } from './TimelineContext.js';
|
|
3
3
|
export type PlayableMediaTag = {
|
|
4
4
|
play: (reason: string) => void;
|
|
@@ -17,7 +17,7 @@ export declare const useTimelineSetFrame: () => (u: import("react").SetStateActi
|
|
|
17
17
|
type PlayingReturnType = readonly [
|
|
18
18
|
boolean,
|
|
19
19
|
(u: React.SetStateAction<boolean>) => void,
|
|
20
|
-
|
|
20
|
+
RefObject<boolean>
|
|
21
21
|
];
|
|
22
22
|
export declare const usePlayingState: () => PlayingReturnType;
|
|
23
23
|
export {};
|
|
@@ -5,6 +5,7 @@ const react_1 = require("react");
|
|
|
5
5
|
const use_audio_frame_js_1 = require("./audio/use-audio-frame.js");
|
|
6
6
|
const buffer_until_first_frame_js_1 = require("./buffer-until-first-frame.js");
|
|
7
7
|
const buffering_js_1 = require("./buffering.js");
|
|
8
|
+
const get_media_sync_action_js_1 = require("./get-media-sync-action.js");
|
|
8
9
|
const log_level_context_js_1 = require("./log-level-context.js");
|
|
9
10
|
const log_js_1 = require("./log.js");
|
|
10
11
|
const media_tag_current_time_timestamp_js_1 = require("./media-tag-current-time-timestamp.js");
|
|
@@ -144,7 +145,7 @@ const useMediaPlayback = ({ mediaRef, src, mediaType, playbackRate: localPlaybac
|
|
|
144
145
|
}, [mediaRef, playbackRate, preservePitch]);
|
|
145
146
|
(0, react_1.useEffect)(() => {
|
|
146
147
|
var _a, _b;
|
|
147
|
-
var _c;
|
|
148
|
+
var _c, _d;
|
|
148
149
|
const tagName = mediaType === 'audio' ? '<Html5Audio>' : '<Html5Video>';
|
|
149
150
|
if (!mediaRef.current) {
|
|
150
151
|
throw new Error(`No ${mediaType} ref found`);
|
|
@@ -152,107 +153,94 @@ const useMediaPlayback = ({ mediaRef, src, mediaType, playbackRate: localPlaybac
|
|
|
152
153
|
if (!src) {
|
|
153
154
|
throw new Error(`No 'src' attribute was passed to the ${tagName} element.`);
|
|
154
155
|
}
|
|
155
|
-
const {
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
:
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
rvcCurrentTime.current
|
|
166
|
-
|
|
167
|
-
:
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
156
|
+
const { current } = mediaRef;
|
|
157
|
+
const action = (0, get_media_sync_action_js_1.getMediaSyncAction)({
|
|
158
|
+
duration: current.duration,
|
|
159
|
+
currentTime: current.currentTime,
|
|
160
|
+
paused: current.paused,
|
|
161
|
+
ended: current.ended,
|
|
162
|
+
desiredUnclampedTime,
|
|
163
|
+
mediaTagTime: mediaTagCurrentTime.current.time,
|
|
164
|
+
mediaTagLastUpdate: mediaTagCurrentTime.current.lastUpdate,
|
|
165
|
+
rvcTime: (_c = (_a = rvcCurrentTime.current) === null || _a === void 0 ? void 0 : _a.time) !== null && _c !== void 0 ? _c : null,
|
|
166
|
+
rvcLastUpdate: (_d = (_b = rvcCurrentTime.current) === null || _b === void 0 ? void 0 : _b.lastUpdate) !== null && _d !== void 0 ? _d : null,
|
|
167
|
+
isVariableFpsVideo: Boolean(isVariableFpsVideoMap.current[src]),
|
|
168
|
+
acceptableTimeShift: acceptableTimeShiftButLessThanDuration,
|
|
169
|
+
lastSeekDueToShift: lastSeekDueToShift.current,
|
|
170
|
+
playing,
|
|
171
|
+
playbackRate,
|
|
172
|
+
mediaTagBufferingOrStalled: isMediaTagBuffering || isBuffering(),
|
|
173
|
+
playerBuffering: buffering.buffering.current,
|
|
174
|
+
absoluteFrame,
|
|
175
|
+
onlyWarnForMediaSeekingError,
|
|
176
|
+
isPremounting,
|
|
177
|
+
isPostmounting,
|
|
178
|
+
pauseWhenBuffering,
|
|
179
|
+
});
|
|
180
|
+
if (action.type === 'none') {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (action.type === 'seek-due-to-shift') {
|
|
175
184
|
lastSeek.current = (0, seek_js_1.seek)({
|
|
176
|
-
mediaRef:
|
|
177
|
-
time: shouldBeTime,
|
|
185
|
+
mediaRef: current,
|
|
186
|
+
time: action.shouldBeTime,
|
|
178
187
|
logLevel,
|
|
179
|
-
why:
|
|
188
|
+
why: action.why,
|
|
180
189
|
mountTime,
|
|
181
190
|
});
|
|
182
191
|
lastSeekDueToShift.current = lastSeek.current;
|
|
183
|
-
if (
|
|
184
|
-
|
|
185
|
-
bufferUntilFirstFrame(shouldBeTime);
|
|
186
|
-
}
|
|
187
|
-
if (mediaRef.current.paused) {
|
|
188
|
-
(0, play_and_handle_not_allowed_error_js_1.playAndHandleNotAllowedError)({
|
|
189
|
-
mediaRef,
|
|
190
|
-
mediaType,
|
|
191
|
-
onAutoPlayError,
|
|
192
|
-
logLevel,
|
|
193
|
-
mountTime,
|
|
194
|
-
reason: 'player is playing but media tag is paused, and just seeked',
|
|
195
|
-
isPlayer: env.isPlayer,
|
|
196
|
-
});
|
|
197
|
-
}
|
|
192
|
+
if (action.bufferUntilFirstFrame) {
|
|
193
|
+
bufferUntilFirstFrame(action.shouldBeTime);
|
|
198
194
|
}
|
|
199
|
-
if (
|
|
200
|
-
(0,
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
const seekThreshold = playing ? 0.15 : 0.01;
|
|
205
|
-
// Only perform a seek if the time is not already the same.
|
|
206
|
-
// Chrome rounds to 6 digits, so 0.033333333 -> 0.033333,
|
|
207
|
-
// therefore a threshold is allowed.
|
|
208
|
-
// Refer to the https://github.com/remotion-dev/video-buffering-example
|
|
209
|
-
// which is fixed by only seeking conditionally.
|
|
210
|
-
const makesSenseToSeek = Math.abs(mediaRef.current.currentTime - shouldBeTime) > seekThreshold;
|
|
211
|
-
const isMediaTagBufferingOrStalled = isMediaTagBuffering || isBuffering();
|
|
212
|
-
const isSomethingElseBuffering = buffering.buffering.current && !isMediaTagBufferingOrStalled;
|
|
213
|
-
if (!playing || isSomethingElseBuffering) {
|
|
214
|
-
if (makesSenseToSeek) {
|
|
215
|
-
lastSeek.current = (0, seek_js_1.seek)({
|
|
216
|
-
mediaRef: mediaRef.current,
|
|
217
|
-
time: shouldBeTime,
|
|
195
|
+
if (action.playReason !== null) {
|
|
196
|
+
(0, play_and_handle_not_allowed_error_js_1.playAndHandleNotAllowedError)({
|
|
197
|
+
mediaRef,
|
|
198
|
+
mediaType,
|
|
199
|
+
onAutoPlayError,
|
|
218
200
|
logLevel,
|
|
219
|
-
why: `not playing or something else is buffering. time offset is over seek threshold (${seekThreshold})`,
|
|
220
201
|
mountTime,
|
|
202
|
+
reason: action.playReason,
|
|
203
|
+
isPlayer: env.isPlayer,
|
|
221
204
|
});
|
|
222
205
|
}
|
|
206
|
+
if (action.warnAboutNonSeekable) {
|
|
207
|
+
(0, warn_about_non_seekable_media_js_1.warnAboutNonSeekableMedia)(current, 'console-error');
|
|
208
|
+
}
|
|
223
209
|
return;
|
|
224
210
|
}
|
|
225
|
-
if (
|
|
226
|
-
|
|
227
|
-
}
|
|
228
|
-
// We now assured we are in playing state and not buffering
|
|
229
|
-
const pausedCondition = mediaRef.current.paused && !mediaRef.current.ended;
|
|
230
|
-
const firstFrameCondition = absoluteFrame === 0;
|
|
231
|
-
if (pausedCondition || firstFrameCondition) {
|
|
232
|
-
const reason = pausedCondition
|
|
233
|
-
? 'media tag is paused'
|
|
234
|
-
: 'absolute frame is 0';
|
|
235
|
-
if (makesSenseToSeek) {
|
|
211
|
+
if (action.type === 'seek-if-not-playing') {
|
|
212
|
+
if (action.why !== null) {
|
|
236
213
|
lastSeek.current = (0, seek_js_1.seek)({
|
|
237
|
-
mediaRef:
|
|
238
|
-
time: shouldBeTime,
|
|
214
|
+
mediaRef: current,
|
|
215
|
+
time: action.shouldBeTime,
|
|
239
216
|
logLevel,
|
|
240
|
-
why:
|
|
217
|
+
why: action.why,
|
|
241
218
|
mountTime,
|
|
242
219
|
});
|
|
243
220
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
// action.type === 'play-and-seek'
|
|
224
|
+
if (action.why !== null) {
|
|
225
|
+
lastSeek.current = (0, seek_js_1.seek)({
|
|
226
|
+
mediaRef: current,
|
|
227
|
+
time: action.shouldBeTime,
|
|
248
228
|
logLevel,
|
|
229
|
+
why: action.why,
|
|
249
230
|
mountTime,
|
|
250
|
-
reason: `player is playing and ${reason}`,
|
|
251
|
-
isPlayer: env.isPlayer,
|
|
252
231
|
});
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
232
|
+
}
|
|
233
|
+
(0, play_and_handle_not_allowed_error_js_1.playAndHandleNotAllowedError)({
|
|
234
|
+
mediaRef,
|
|
235
|
+
mediaType,
|
|
236
|
+
onAutoPlayError,
|
|
237
|
+
logLevel,
|
|
238
|
+
mountTime,
|
|
239
|
+
reason: action.playReason,
|
|
240
|
+
isPlayer: env.isPlayer,
|
|
241
|
+
});
|
|
242
|
+
if (action.bufferUntilFirstFrame) {
|
|
243
|
+
bufferUntilFirstFrame(action.shouldBeTime);
|
|
256
244
|
}
|
|
257
245
|
}, [
|
|
258
246
|
absoluteFrame,
|
|
@@ -2,7 +2,7 @@ import type { RefObject } from 'react';
|
|
|
2
2
|
export declare const useRequestVideoCallbackTime: ({ mediaRef, mediaType, lastSeek, onVariableFpsVideoDetected, }: {
|
|
3
3
|
mediaRef: RefObject<HTMLAudioElement | HTMLVideoElement | null>;
|
|
4
4
|
mediaType: "audio" | "video";
|
|
5
|
-
lastSeek:
|
|
5
|
+
lastSeek: RefObject<number | null>;
|
|
6
6
|
onVariableFpsVideoDetected: () => void;
|
|
7
7
|
}) => RefObject<{
|
|
8
8
|
time: number;
|
package/dist/cjs/version.d.ts
CHANGED
package/dist/cjs/version.js
CHANGED
|
@@ -39,7 +39,7 @@ export declare function useRemotionContexts(): {
|
|
|
39
39
|
listenForResume: (callback: () => void) => {
|
|
40
40
|
remove: () => void;
|
|
41
41
|
};
|
|
42
|
-
buffering: React.
|
|
42
|
+
buffering: React.RefObject<boolean>;
|
|
43
43
|
} | null;
|
|
44
44
|
logLevelContext: import("./log-level-context.js").LoggingContextValue;
|
|
45
45
|
};
|
package/dist/esm/index.mjs
CHANGED
|
@@ -1291,7 +1291,7 @@ var addSequenceStackTraces = (component) => {
|
|
|
1291
1291
|
};
|
|
1292
1292
|
|
|
1293
1293
|
// src/version.ts
|
|
1294
|
-
var VERSION = "4.0.
|
|
1294
|
+
var VERSION = "4.0.487";
|
|
1295
1295
|
|
|
1296
1296
|
// src/multiple-versions-warning.ts
|
|
1297
1297
|
var checkMultipleRemotionVersions = () => {
|
|
@@ -7458,7 +7458,8 @@ var useBufferManager = (logLevel, mountTime) => {
|
|
|
7458
7458
|
if (rendering) {
|
|
7459
7459
|
return;
|
|
7460
7460
|
}
|
|
7461
|
-
if (blocks.length > 0) {
|
|
7461
|
+
if (blocks.length > 0 && !buffering.current) {
|
|
7462
|
+
buffering.current = true;
|
|
7462
7463
|
onBufferingCallbacks.forEach((c2) => c2());
|
|
7463
7464
|
playbackLogging({
|
|
7464
7465
|
logLevel,
|
|
@@ -7473,7 +7474,8 @@ var useBufferManager = (logLevel, mountTime) => {
|
|
|
7473
7474
|
if (rendering) {
|
|
7474
7475
|
return;
|
|
7475
7476
|
}
|
|
7476
|
-
if (blocks.length === 0) {
|
|
7477
|
+
if (blocks.length === 0 && buffering.current) {
|
|
7478
|
+
buffering.current = false;
|
|
7477
7479
|
onResumeCallbacks.forEach((c2) => c2());
|
|
7478
7480
|
playbackLogging({
|
|
7479
7481
|
logLevel,
|
|
@@ -7506,15 +7508,11 @@ var useIsPlayerBuffering = (bufferManager) => {
|
|
|
7506
7508
|
const onResume = () => {
|
|
7507
7509
|
setIsBuffering(false);
|
|
7508
7510
|
};
|
|
7509
|
-
bufferManager.listenForBuffering(onBuffer);
|
|
7510
|
-
bufferManager.listenForResume(onResume);
|
|
7511
|
+
const buffer = bufferManager.listenForBuffering(onBuffer);
|
|
7512
|
+
const resume = bufferManager.listenForResume(onResume);
|
|
7511
7513
|
return () => {
|
|
7512
|
-
|
|
7513
|
-
|
|
7514
|
-
});
|
|
7515
|
-
bufferManager.listenForResume(() => {
|
|
7516
|
-
return;
|
|
7517
|
-
});
|
|
7514
|
+
buffer.remove();
|
|
7515
|
+
resume.remove();
|
|
7518
7516
|
};
|
|
7519
7517
|
}, [bufferManager]);
|
|
7520
7518
|
return isBuffering;
|
|
@@ -7643,6 +7641,74 @@ var useBufferUntilFirstFrame = ({
|
|
|
7643
7641
|
}, [bufferUntilFirstFrame]);
|
|
7644
7642
|
};
|
|
7645
7643
|
|
|
7644
|
+
// src/get-media-sync-action.ts
|
|
7645
|
+
var getMediaSyncAction = (input) => {
|
|
7646
|
+
const {
|
|
7647
|
+
duration,
|
|
7648
|
+
currentTime,
|
|
7649
|
+
paused,
|
|
7650
|
+
ended,
|
|
7651
|
+
desiredUnclampedTime,
|
|
7652
|
+
mediaTagTime,
|
|
7653
|
+
mediaTagLastUpdate,
|
|
7654
|
+
rvcTime,
|
|
7655
|
+
rvcLastUpdate,
|
|
7656
|
+
isVariableFpsVideo,
|
|
7657
|
+
acceptableTimeShift,
|
|
7658
|
+
lastSeekDueToShift,
|
|
7659
|
+
playing,
|
|
7660
|
+
playbackRate,
|
|
7661
|
+
mediaTagBufferingOrStalled,
|
|
7662
|
+
playerBuffering,
|
|
7663
|
+
absoluteFrame,
|
|
7664
|
+
onlyWarnForMediaSeekingError,
|
|
7665
|
+
isPremounting,
|
|
7666
|
+
isPostmounting,
|
|
7667
|
+
pauseWhenBuffering
|
|
7668
|
+
} = input;
|
|
7669
|
+
const shouldBeTime = !Number.isNaN(duration) && Number.isFinite(duration) ? Math.min(duration, desiredUnclampedTime) : desiredUnclampedTime;
|
|
7670
|
+
const timeShiftMediaTag = Math.abs(shouldBeTime - mediaTagTime);
|
|
7671
|
+
const timeShiftRvcTag = rvcTime ? Math.abs(shouldBeTime - rvcTime) : null;
|
|
7672
|
+
const mostRecentTimeshift = rvcLastUpdate && rvcTime > mediaTagLastUpdate ? timeShiftRvcTag : timeShiftMediaTag;
|
|
7673
|
+
const timeShift = timeShiftRvcTag && !isVariableFpsVideo ? mostRecentTimeshift : timeShiftMediaTag;
|
|
7674
|
+
if (timeShift > acceptableTimeShift && lastSeekDueToShift !== shouldBeTime) {
|
|
7675
|
+
return {
|
|
7676
|
+
type: "seek-due-to-shift",
|
|
7677
|
+
shouldBeTime,
|
|
7678
|
+
why: `because time shift is too big. shouldBeTime = ${shouldBeTime}, isTime = ${mediaTagTime}, requestVideoCallbackTime = ${rvcTime}, timeShift = ${timeShift}${isVariableFpsVideo ? ", isVariableFpsVideo = true" : ""}, isPremounting = ${isPremounting}, isPostmounting = ${isPostmounting}, pauseWhenBuffering = ${pauseWhenBuffering}`,
|
|
7679
|
+
bufferUntilFirstFrame: playing && playbackRate > 0,
|
|
7680
|
+
playReason: playing && paused ? "player is playing but media tag is paused, and just seeked" : null,
|
|
7681
|
+
warnAboutNonSeekable: !onlyWarnForMediaSeekingError
|
|
7682
|
+
};
|
|
7683
|
+
}
|
|
7684
|
+
const seekThreshold = playing ? 0.15 : 0.01;
|
|
7685
|
+
const makesSenseToSeek = Math.abs(currentTime - shouldBeTime) > seekThreshold;
|
|
7686
|
+
const isSomethingElseBuffering = playerBuffering && !mediaTagBufferingOrStalled;
|
|
7687
|
+
if (!playing || isSomethingElseBuffering) {
|
|
7688
|
+
return {
|
|
7689
|
+
type: "seek-if-not-playing",
|
|
7690
|
+
shouldBeTime,
|
|
7691
|
+
why: makesSenseToSeek ? `not playing or something else is buffering. time offset is over seek threshold (${seekThreshold})` : null
|
|
7692
|
+
};
|
|
7693
|
+
}
|
|
7694
|
+
if (!playing || playerBuffering) {
|
|
7695
|
+
return { type: "none" };
|
|
7696
|
+
}
|
|
7697
|
+
const pausedCondition = paused && !ended;
|
|
7698
|
+
const firstFrameCondition = absoluteFrame === 0;
|
|
7699
|
+
if (pausedCondition || firstFrameCondition) {
|
|
7700
|
+
const reason = pausedCondition ? "media tag is paused" : "absolute frame is 0";
|
|
7701
|
+
return {
|
|
7702
|
+
type: "play-and-seek",
|
|
7703
|
+
shouldBeTime,
|
|
7704
|
+
why: makesSenseToSeek ? `is over timeshift threshold (threshold = ${seekThreshold}) and ${reason}` : null,
|
|
7705
|
+
playReason: `player is playing and ${reason}`,
|
|
7706
|
+
bufferUntilFirstFrame: !isVariableFpsVideo && playbackRate > 0
|
|
7707
|
+
};
|
|
7708
|
+
}
|
|
7709
|
+
return { type: "none" };
|
|
7710
|
+
};
|
|
7711
|
+
|
|
7646
7712
|
// src/media-tag-current-time-timestamp.ts
|
|
7647
7713
|
import React21 from "react";
|
|
7648
7714
|
var useCurrentTimeOfMediaTagWithUpdateTimeStamp = (mediaRef) => {
|
|
@@ -8078,89 +8144,93 @@ var useMediaPlayback = ({
|
|
|
8078
8144
|
if (!src) {
|
|
8079
8145
|
throw new Error(`No 'src' attribute was passed to the ${tagName} element.`);
|
|
8080
8146
|
}
|
|
8081
|
-
const {
|
|
8082
|
-
const
|
|
8083
|
-
|
|
8084
|
-
|
|
8085
|
-
|
|
8086
|
-
|
|
8087
|
-
|
|
8088
|
-
|
|
8089
|
-
|
|
8090
|
-
|
|
8147
|
+
const { current } = mediaRef;
|
|
8148
|
+
const action = getMediaSyncAction({
|
|
8149
|
+
duration: current.duration,
|
|
8150
|
+
currentTime: current.currentTime,
|
|
8151
|
+
paused: current.paused,
|
|
8152
|
+
ended: current.ended,
|
|
8153
|
+
desiredUnclampedTime,
|
|
8154
|
+
mediaTagTime: mediaTagCurrentTime.current.time,
|
|
8155
|
+
mediaTagLastUpdate: mediaTagCurrentTime.current.lastUpdate,
|
|
8156
|
+
rvcTime: rvcCurrentTime.current?.time ?? null,
|
|
8157
|
+
rvcLastUpdate: rvcCurrentTime.current?.lastUpdate ?? null,
|
|
8158
|
+
isVariableFpsVideo: Boolean(isVariableFpsVideoMap.current[src]),
|
|
8159
|
+
acceptableTimeShift: acceptableTimeShiftButLessThanDuration,
|
|
8160
|
+
lastSeekDueToShift: lastSeekDueToShift.current,
|
|
8161
|
+
playing,
|
|
8162
|
+
playbackRate,
|
|
8163
|
+
mediaTagBufferingOrStalled: isMediaTagBuffering || isBuffering(),
|
|
8164
|
+
playerBuffering: buffering.buffering.current,
|
|
8165
|
+
absoluteFrame,
|
|
8166
|
+
onlyWarnForMediaSeekingError,
|
|
8167
|
+
isPremounting,
|
|
8168
|
+
isPostmounting,
|
|
8169
|
+
pauseWhenBuffering
|
|
8170
|
+
});
|
|
8171
|
+
if (action.type === "none") {
|
|
8172
|
+
return;
|
|
8173
|
+
}
|
|
8174
|
+
if (action.type === "seek-due-to-shift") {
|
|
8091
8175
|
lastSeek.current = seek({
|
|
8092
|
-
mediaRef:
|
|
8093
|
-
time: shouldBeTime,
|
|
8176
|
+
mediaRef: current,
|
|
8177
|
+
time: action.shouldBeTime,
|
|
8094
8178
|
logLevel,
|
|
8095
|
-
why:
|
|
8179
|
+
why: action.why,
|
|
8096
8180
|
mountTime
|
|
8097
8181
|
});
|
|
8098
8182
|
lastSeekDueToShift.current = lastSeek.current;
|
|
8099
|
-
if (
|
|
8100
|
-
|
|
8101
|
-
bufferUntilFirstFrame(shouldBeTime);
|
|
8102
|
-
}
|
|
8103
|
-
if (mediaRef.current.paused) {
|
|
8104
|
-
playAndHandleNotAllowedError({
|
|
8105
|
-
mediaRef,
|
|
8106
|
-
mediaType,
|
|
8107
|
-
onAutoPlayError,
|
|
8108
|
-
logLevel,
|
|
8109
|
-
mountTime,
|
|
8110
|
-
reason: "player is playing but media tag is paused, and just seeked",
|
|
8111
|
-
isPlayer: env.isPlayer
|
|
8112
|
-
});
|
|
8113
|
-
}
|
|
8183
|
+
if (action.bufferUntilFirstFrame) {
|
|
8184
|
+
bufferUntilFirstFrame(action.shouldBeTime);
|
|
8114
8185
|
}
|
|
8115
|
-
if (
|
|
8116
|
-
|
|
8117
|
-
|
|
8118
|
-
|
|
8119
|
-
|
|
8120
|
-
const seekThreshold = playing ? 0.15 : 0.01;
|
|
8121
|
-
const makesSenseToSeek = Math.abs(mediaRef.current.currentTime - shouldBeTime) > seekThreshold;
|
|
8122
|
-
const isMediaTagBufferingOrStalled = isMediaTagBuffering || isBuffering();
|
|
8123
|
-
const isSomethingElseBuffering = buffering.buffering.current && !isMediaTagBufferingOrStalled;
|
|
8124
|
-
if (!playing || isSomethingElseBuffering) {
|
|
8125
|
-
if (makesSenseToSeek) {
|
|
8126
|
-
lastSeek.current = seek({
|
|
8127
|
-
mediaRef: mediaRef.current,
|
|
8128
|
-
time: shouldBeTime,
|
|
8186
|
+
if (action.playReason !== null) {
|
|
8187
|
+
playAndHandleNotAllowedError({
|
|
8188
|
+
mediaRef,
|
|
8189
|
+
mediaType,
|
|
8190
|
+
onAutoPlayError,
|
|
8129
8191
|
logLevel,
|
|
8130
|
-
|
|
8131
|
-
|
|
8192
|
+
mountTime,
|
|
8193
|
+
reason: action.playReason,
|
|
8194
|
+
isPlayer: env.isPlayer
|
|
8132
8195
|
});
|
|
8133
8196
|
}
|
|
8197
|
+
if (action.warnAboutNonSeekable) {
|
|
8198
|
+
warnAboutNonSeekableMedia(current, "console-error");
|
|
8199
|
+
}
|
|
8134
8200
|
return;
|
|
8135
8201
|
}
|
|
8136
|
-
if (
|
|
8137
|
-
|
|
8138
|
-
}
|
|
8139
|
-
const pausedCondition = mediaRef.current.paused && !mediaRef.current.ended;
|
|
8140
|
-
const firstFrameCondition = absoluteFrame === 0;
|
|
8141
|
-
if (pausedCondition || firstFrameCondition) {
|
|
8142
|
-
const reason = pausedCondition ? "media tag is paused" : "absolute frame is 0";
|
|
8143
|
-
if (makesSenseToSeek) {
|
|
8202
|
+
if (action.type === "seek-if-not-playing") {
|
|
8203
|
+
if (action.why !== null) {
|
|
8144
8204
|
lastSeek.current = seek({
|
|
8145
|
-
mediaRef:
|
|
8146
|
-
time: shouldBeTime,
|
|
8205
|
+
mediaRef: current,
|
|
8206
|
+
time: action.shouldBeTime,
|
|
8147
8207
|
logLevel,
|
|
8148
|
-
why:
|
|
8208
|
+
why: action.why,
|
|
8149
8209
|
mountTime
|
|
8150
8210
|
});
|
|
8151
8211
|
}
|
|
8152
|
-
|
|
8153
|
-
|
|
8154
|
-
|
|
8155
|
-
|
|
8212
|
+
return;
|
|
8213
|
+
}
|
|
8214
|
+
if (action.why !== null) {
|
|
8215
|
+
lastSeek.current = seek({
|
|
8216
|
+
mediaRef: current,
|
|
8217
|
+
time: action.shouldBeTime,
|
|
8156
8218
|
logLevel,
|
|
8157
|
-
|
|
8158
|
-
|
|
8159
|
-
isPlayer: env.isPlayer
|
|
8219
|
+
why: action.why,
|
|
8220
|
+
mountTime
|
|
8160
8221
|
});
|
|
8161
|
-
|
|
8162
|
-
|
|
8163
|
-
|
|
8222
|
+
}
|
|
8223
|
+
playAndHandleNotAllowedError({
|
|
8224
|
+
mediaRef,
|
|
8225
|
+
mediaType,
|
|
8226
|
+
onAutoPlayError,
|
|
8227
|
+
logLevel,
|
|
8228
|
+
mountTime,
|
|
8229
|
+
reason: action.playReason,
|
|
8230
|
+
isPlayer: env.isPlayer
|
|
8231
|
+
});
|
|
8232
|
+
if (action.bufferUntilFirstFrame) {
|
|
8233
|
+
bufferUntilFirstFrame(action.shouldBeTime);
|
|
8164
8234
|
}
|
|
8165
8235
|
}, [
|
|
8166
8236
|
absoluteFrame,
|
|
@@ -12009,6 +12079,7 @@ var Still = (props2) => {
|
|
|
12009
12079
|
};
|
|
12010
12080
|
return React42.createElement(Composition, newProps);
|
|
12011
12081
|
};
|
|
12082
|
+
addSequenceStackTraces(Still);
|
|
12012
12083
|
// src/video/html5-video.tsx
|
|
12013
12084
|
import { forwardRef as forwardRef16, useCallback as useCallback25, useContext as useContext39 } from "react";
|
|
12014
12085
|
|
package/dist/esm/version.mjs
CHANGED
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"url": "https://github.com/remotion-dev/remotion/tree/main/packages/core"
|
|
4
4
|
},
|
|
5
5
|
"name": "remotion",
|
|
6
|
-
"version": "4.0.
|
|
6
|
+
"version": "4.0.487",
|
|
7
7
|
"description": "Make videos programmatically",
|
|
8
8
|
"main": "dist/cjs/index.js",
|
|
9
9
|
"types": "dist/cjs/index.d.ts",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"react-dom": "19.2.3",
|
|
36
36
|
"webpack": "5.105.0",
|
|
37
37
|
"zod": "4.3.6",
|
|
38
|
-
"@remotion/eslint-config-internal": "4.0.
|
|
38
|
+
"@remotion/eslint-config-internal": "4.0.487",
|
|
39
39
|
"eslint": "9.19.0",
|
|
40
40
|
"@typescript/native-preview": "7.0.0-dev.20260217.1"
|
|
41
41
|
},
|