@remotion/player 4.0.289 → 4.0.291

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.
@@ -38,6 +38,7 @@ export type PlayerProps<Schema extends AnyZodObject, Props extends Record<string
38
38
  readonly showPosterWhenEnded?: boolean;
39
39
  readonly showPosterWhenUnplayed?: boolean;
40
40
  readonly showPosterWhenBuffering?: boolean;
41
+ readonly showPosterWhenBufferingAndPaused?: boolean;
41
42
  readonly inFrame?: number | null;
42
43
  readonly outFrame?: number | null;
43
44
  readonly initiallyShowControls?: number | boolean;
@@ -23,7 +23,7 @@ const componentOrNullIfLazy = (props) => {
23
23
  return null;
24
24
  };
25
25
  exports.componentOrNullIfLazy = componentOrNullIfLazy;
26
- const PlayerFn = ({ durationInFrames, compositionHeight, compositionWidth, fps, inputProps, style, controls = false, loop = false, autoPlay = false, showVolumeControls = true, allowFullscreen = true, clickToPlay, doubleClickToFullscreen = false, spaceKeyToPlayOrPause = true, moveToBeginningWhenEnded = true, numberOfSharedAudioTags = 5, errorFallback = () => '⚠️', playbackRate = 1, renderLoading, className, showPosterWhenUnplayed, showPosterWhenEnded, showPosterWhenPaused, showPosterWhenBuffering, initialFrame, renderPoster, inFrame, outFrame, initiallyShowControls, renderFullscreenButton, renderPlayPauseButton, renderVolumeSlider, alwaysShowControls = false, initiallyMuted = false, showPlaybackRateControl = false, posterFillMode = 'player-size', bufferStateDelayInMilliseconds, hideControlsWhenPointerDoesntMove = true, overflowVisible = false, renderMuteButton, browserMediaControlsBehavior: passedBrowserMediaControlsBehavior, overrideInternalClassName, logLevel = 'info', noSuspense, acknowledgeRemotionLicense, ...componentProps }, ref) => {
26
+ const PlayerFn = ({ durationInFrames, compositionHeight, compositionWidth, fps, inputProps, style, controls = false, loop = false, autoPlay = false, showVolumeControls = true, allowFullscreen = true, clickToPlay, doubleClickToFullscreen = false, spaceKeyToPlayOrPause = true, moveToBeginningWhenEnded = true, numberOfSharedAudioTags = 5, errorFallback = () => '⚠️', playbackRate = 1, renderLoading, className, showPosterWhenUnplayed, showPosterWhenEnded, showPosterWhenPaused, showPosterWhenBuffering, showPosterWhenBufferingAndPaused, initialFrame, renderPoster, inFrame, outFrame, initiallyShowControls, renderFullscreenButton, renderPlayPauseButton, renderVolumeSlider, alwaysShowControls = false, initiallyMuted = false, showPlaybackRateControl = false, posterFillMode = 'player-size', bufferStateDelayInMilliseconds, hideControlsWhenPointerDoesntMove = true, overflowVisible = false, renderMuteButton, browserMediaControlsBehavior: passedBrowserMediaControlsBehavior, overrideInternalClassName, logLevel = 'info', noSuspense, acknowledgeRemotionLicense, ...componentProps }, ref) => {
27
27
  if (typeof window !== 'undefined') {
28
28
  // eslint-disable-next-line react-hooks/rules-of-hooks
29
29
  (0, react_1.useLayoutEffect)(() => {
@@ -159,7 +159,7 @@ const PlayerFn = ({ durationInFrames, compositionHeight, compositionWidth, fps,
159
159
  }, [passedBrowserMediaControlsBehavior]);
160
160
  return ((0, jsx_runtime_1.jsx)(remotion_1.Internals.IsPlayerContextProvider, { children: (0, jsx_runtime_1.jsx)(SharedPlayerContext_js_1.SharedPlayerContexts, { timelineContext: timelineContextValue, component: component, compositionHeight: compositionHeight, compositionWidth: compositionWidth, durationInFrames: durationInFrames, fps: fps, numberOfSharedAudioTags: numberOfSharedAudioTags, initiallyMuted: initiallyMuted, logLevel: logLevel, children: (0, jsx_runtime_1.jsx)(remotion_1.Internals.Timeline.SetTimelineContext.Provider, { value: setTimelineContextValue, children: (0, jsx_runtime_1.jsx)(EmitterProvider_js_1.PlayerEmitterProvider, { currentPlaybackRate: currentPlaybackRate, children: (0, jsx_runtime_1.jsx)(PlayerUI_js_1.default, { ref: rootRef, posterFillMode: posterFillMode, renderLoading: renderLoading, autoPlay: Boolean(autoPlay), loop: Boolean(loop), controls: Boolean(controls), errorFallback: errorFallback, style: style, inputProps: actualInputProps, allowFullscreen: Boolean(allowFullscreen), moveToBeginningWhenEnded: Boolean(moveToBeginningWhenEnded), clickToPlay: typeof clickToPlay === 'boolean'
161
161
  ? clickToPlay
162
- : Boolean(controls), showVolumeControls: Boolean(showVolumeControls), doubleClickToFullscreen: Boolean(doubleClickToFullscreen), spaceKeyToPlayOrPause: Boolean(spaceKeyToPlayOrPause), playbackRate: currentPlaybackRate, className: className !== null && className !== void 0 ? className : undefined, showPosterWhenUnplayed: Boolean(showPosterWhenUnplayed), showPosterWhenEnded: Boolean(showPosterWhenEnded), showPosterWhenPaused: Boolean(showPosterWhenPaused), showPosterWhenBuffering: Boolean(showPosterWhenBuffering), renderPoster: renderPoster, inFrame: inFrame !== null && inFrame !== void 0 ? inFrame : null, outFrame: outFrame !== null && outFrame !== void 0 ? outFrame : null, initiallyShowControls: initiallyShowControls !== null && initiallyShowControls !== void 0 ? initiallyShowControls : true, renderFullscreen: renderFullscreenButton !== null && renderFullscreenButton !== void 0 ? renderFullscreenButton : null, renderPlayPauseButton: renderPlayPauseButton !== null && renderPlayPauseButton !== void 0 ? renderPlayPauseButton : null, renderMuteButton: renderMuteButton !== null && renderMuteButton !== void 0 ? renderMuteButton : null, renderVolumeSlider: renderVolumeSlider !== null && renderVolumeSlider !== void 0 ? renderVolumeSlider : null, alwaysShowControls: alwaysShowControls, showPlaybackRateControl: showPlaybackRateControl, bufferStateDelayInMilliseconds: bufferStateDelayInMilliseconds !== null && bufferStateDelayInMilliseconds !== void 0 ? bufferStateDelayInMilliseconds : 300, hideControlsWhenPointerDoesntMove: hideControlsWhenPointerDoesntMove, overflowVisible: overflowVisible, browserMediaControlsBehavior: browserMediaControlsBehavior, overrideInternalClassName: overrideInternalClassName !== null && overrideInternalClassName !== void 0 ? overrideInternalClassName : undefined, noSuspense: Boolean(noSuspense) }) }) }) }) }));
162
+ : Boolean(controls), showVolumeControls: Boolean(showVolumeControls), doubleClickToFullscreen: Boolean(doubleClickToFullscreen), spaceKeyToPlayOrPause: Boolean(spaceKeyToPlayOrPause), playbackRate: currentPlaybackRate, className: className !== null && className !== void 0 ? className : undefined, showPosterWhenUnplayed: Boolean(showPosterWhenUnplayed), showPosterWhenEnded: Boolean(showPosterWhenEnded), showPosterWhenPaused: Boolean(showPosterWhenPaused), showPosterWhenBuffering: Boolean(showPosterWhenBuffering), showPosterWhenBufferingAndPaused: Boolean(showPosterWhenBufferingAndPaused), renderPoster: renderPoster, inFrame: inFrame !== null && inFrame !== void 0 ? inFrame : null, outFrame: outFrame !== null && outFrame !== void 0 ? outFrame : null, initiallyShowControls: initiallyShowControls !== null && initiallyShowControls !== void 0 ? initiallyShowControls : true, renderFullscreen: renderFullscreenButton !== null && renderFullscreenButton !== void 0 ? renderFullscreenButton : null, renderPlayPauseButton: renderPlayPauseButton !== null && renderPlayPauseButton !== void 0 ? renderPlayPauseButton : null, renderMuteButton: renderMuteButton !== null && renderMuteButton !== void 0 ? renderMuteButton : null, renderVolumeSlider: renderVolumeSlider !== null && renderVolumeSlider !== void 0 ? renderVolumeSlider : null, alwaysShowControls: alwaysShowControls, showPlaybackRateControl: showPlaybackRateControl, bufferStateDelayInMilliseconds: bufferStateDelayInMilliseconds !== null && bufferStateDelayInMilliseconds !== void 0 ? bufferStateDelayInMilliseconds : 300, hideControlsWhenPointerDoesntMove: hideControlsWhenPointerDoesntMove, overflowVisible: overflowVisible, browserMediaControlsBehavior: browserMediaControlsBehavior, overrideInternalClassName: overrideInternalClassName !== null && overrideInternalClassName !== void 0 ? overrideInternalClassName : undefined, noSuspense: Boolean(noSuspense) }) }) }) }) }));
163
163
  };
164
164
  const forward = react_1.forwardRef;
165
165
  /*
@@ -35,6 +35,7 @@ declare const _default: React.ForwardRefExoticComponent<{
35
35
  readonly showPosterWhenEnded: boolean;
36
36
  readonly showPosterWhenUnplayed: boolean;
37
37
  readonly showPosterWhenBuffering: boolean;
38
+ readonly showPosterWhenBufferingAndPaused: boolean;
38
39
  readonly inFrame: number | null;
39
40
  readonly outFrame: number | null;
40
41
  readonly initiallyShowControls: number | boolean;
@@ -51,7 +51,7 @@ if (reactVersion === '0') {
51
51
  throw new Error(`Version ${reactVersion} of "react" is not supported by Remotion`);
52
52
  }
53
53
  const doesReactVersionSupportSuspense = parseInt(reactVersion, 10) >= 18;
54
- const PlayerUI = ({ controls, style, loop, autoPlay, allowFullscreen, inputProps, clickToPlay, showVolumeControls, doubleClickToFullscreen, spaceKeyToPlayOrPause, errorFallback, playbackRate, renderLoading, renderPoster, className, moveToBeginningWhenEnded, showPosterWhenUnplayed, showPosterWhenEnded, showPosterWhenPaused, showPosterWhenBuffering, inFrame, outFrame, initiallyShowControls, renderFullscreen: renderFullscreenButton, renderPlayPauseButton, renderMuteButton, renderVolumeSlider, alwaysShowControls, showPlaybackRateControl, posterFillMode, bufferStateDelayInMilliseconds, hideControlsWhenPointerDoesntMove, overflowVisible, browserMediaControlsBehavior, overrideInternalClassName, noSuspense, }, ref) => {
54
+ const PlayerUI = ({ controls, style, loop, autoPlay, allowFullscreen, inputProps, clickToPlay, showVolumeControls, doubleClickToFullscreen, spaceKeyToPlayOrPause, errorFallback, playbackRate, renderLoading, renderPoster, className, moveToBeginningWhenEnded, showPosterWhenUnplayed, showPosterWhenEnded, showPosterWhenPaused, showPosterWhenBuffering, showPosterWhenBufferingAndPaused, inFrame, outFrame, initiallyShowControls, renderFullscreen: renderFullscreenButton, renderPlayPauseButton, renderMuteButton, renderVolumeSlider, alwaysShowControls, showPlaybackRateControl, posterFillMode, bufferStateDelayInMilliseconds, hideControlsWhenPointerDoesntMove, overflowVisible, browserMediaControlsBehavior, overrideInternalClassName, noSuspense, }, ref) => {
55
55
  var _a, _b, _c;
56
56
  const config = remotion_1.Internals.useUnsafeVideoConfig();
57
57
  const video = remotion_1.Internals.useVideo();
@@ -426,6 +426,9 @@ const PlayerUI = ({ controls, style, loop, autoPlay, allowFullscreen, inputProps
426
426
  showPosterWhenEnded && player.isLastFrame && !player.isPlaying(),
427
427
  showPosterWhenUnplayed && !player.hasPlayed && !player.isPlaying(),
428
428
  showPosterWhenBuffering && showBufferIndicator && player.isPlaying(),
429
+ showPosterWhenBufferingAndPaused &&
430
+ showBufferIndicator &&
431
+ !player.isPlaying(),
429
432
  ].some(Boolean);
430
433
  const { left, top, width, height, ...outerWithoutScale } = outer;
431
434
  const content = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { style: outer, onPointerDown: clickToPlay ? handlePointerDown : undefined, onDoubleClick: doubleClickToFullscreen ? handleDoubleClick : undefined, children: [(0, jsx_runtime_1.jsxs)("div", { style: containerStyle, className: (0, player_css_classname_js_1.playerCssClassname)(overrideInternalClassName), children: [VideoComponent ? ((0, jsx_runtime_1.jsx)(error_boundary_js_1.ErrorBoundary, { onError: onError, errorFallback: errorFallback, children: (0, jsx_runtime_1.jsx)(remotion_1.Internals.CurrentScaleContext.Provider, { value: currentScale, children: (0, jsx_runtime_1.jsx)(VideoComponent, { ...((_c = video === null || video === void 0 ? void 0 : video.props) !== null && _c !== void 0 ? _c : {}), ...(inputProps !== null && inputProps !== void 0 ? inputProps : {}) }) }) })) : null, shouldShowPoster && posterFillMode === 'composition-size' ? ((0, jsx_runtime_1.jsx)("div", { style: {
@@ -13,7 +13,6 @@ const usePlayback = ({ loop, playbackRate, moveToBeginningWhenEnded, inFrame, ou
13
13
  const frame = remotion_1.Internals.Timeline.useTimelinePosition();
14
14
  const { playing, pause, emitter } = (0, use_player_js_1.usePlayer)();
15
15
  const setFrame = remotion_1.Internals.Timeline.useTimelineSetFrame();
16
- const buffering = (0, react_1.useRef)(null);
17
16
  // requestAnimationFrame() does not work if the tab is not active.
18
17
  // This means that audio will keep playing even if it has ended.
19
18
  // In that case, we use setTimeout() instead.
@@ -29,18 +28,6 @@ const usePlayback = ({ loop, playbackRate, moveToBeginningWhenEnded, inFrame, ou
29
28
  videoConfig: config,
30
29
  });
31
30
  // complete code for media session API
32
- (0, react_1.useEffect)(() => {
33
- const onBufferClear = context.listenForBuffering(() => {
34
- buffering.current = performance.now();
35
- });
36
- const onResumeClear = context.listenForResume(() => {
37
- buffering.current = null;
38
- });
39
- return () => {
40
- onBufferClear.remove();
41
- onResumeClear.remove();
42
- };
43
- }, [context]);
44
31
  (0, react_1.useEffect)(() => {
45
32
  if (!config) {
46
33
  return;
@@ -67,6 +54,9 @@ const usePlayback = ({ loop, playbackRate, moveToBeginningWhenEnded, inFrame, ou
67
54
  cancelQueuedFrame();
68
55
  };
69
56
  const callback = () => {
57
+ if (hasBeenStopped) {
58
+ return;
59
+ }
70
60
  const time = performance.now() - startedTime;
71
61
  const actualLastFrame = outFrame !== null && outFrame !== void 0 ? outFrame : config.durationInFrames - 1;
72
62
  const actualFirstFrame = inFrame !== null && inFrame !== void 0 ? inFrame : 0;
@@ -92,20 +82,15 @@ const usePlayback = ({ loop, playbackRate, moveToBeginningWhenEnded, inFrame, ou
92
82
  emitter.dispatchEnded();
93
83
  return;
94
84
  }
95
- if (!hasBeenStopped) {
96
- queueNextFrame();
97
- }
85
+ queueNextFrame();
98
86
  };
99
87
  const queueNextFrame = () => {
100
- if (buffering.current) {
88
+ if (context.buffering.current) {
101
89
  const stopListening = context.listenForResume(() => {
102
90
  stopListening.remove();
103
- if (hasBeenStopped) {
104
- return;
105
- }
106
91
  startedTime = performance.now();
107
92
  framesAdvanced = 0;
108
- callback();
93
+ queueNextFrame();
109
94
  });
110
95
  return;
111
96
  }
@@ -115,10 +100,9 @@ const usePlayback = ({ loop, playbackRate, moveToBeginningWhenEnded, inFrame, ou
115
100
  // Note: Most likely, this will not be 1000 / fps, but the browser will throttle it to ~1/sec.
116
101
  id: setTimeout(callback, 1000 / config.fps),
117
102
  };
103
+ return;
118
104
  }
119
- else {
120
- reqAnimFrameCall = { type: 'raf', id: requestAnimationFrame(callback) };
121
- }
105
+ reqAnimFrameCall = { type: 'raf', id: requestAnimationFrame(callback) };
122
106
  };
123
107
  queueNextFrame();
124
108
  const onVisibilityChange = () => {
@@ -148,7 +132,6 @@ const usePlayback = ({ loop, playbackRate, moveToBeginningWhenEnded, inFrame, ou
148
132
  moveToBeginningWhenEnded,
149
133
  isBackgroundedRef,
150
134
  getCurrentFrame,
151
- buffering,
152
135
  context,
153
136
  ]);
154
137
  (0, react_1.useEffect)(() => {
@@ -881,7 +881,6 @@ var usePlayback = ({
881
881
  const frame = Internals6.Timeline.useTimelinePosition();
882
882
  const { playing, pause, emitter } = usePlayer();
883
883
  const setFrame = Internals6.Timeline.useTimelineSetFrame();
884
- const buffering = useRef4(null);
885
884
  const isBackgroundedRef = useIsBackgrounded();
886
885
  const lastTimeUpdateEvent = useRef4(null);
887
886
  const context = useContext4(Internals6.BufferingContextReact);
@@ -893,18 +892,6 @@ var usePlayback = ({
893
892
  playbackRate,
894
893
  videoConfig: config
895
894
  });
896
- useEffect6(() => {
897
- const onBufferClear = context.listenForBuffering(() => {
898
- buffering.current = performance.now();
899
- });
900
- const onResumeClear = context.listenForResume(() => {
901
- buffering.current = null;
902
- });
903
- return () => {
904
- onBufferClear.remove();
905
- onResumeClear.remove();
906
- };
907
- }, [context]);
908
895
  useEffect6(() => {
909
896
  if (!config) {
910
897
  return;
@@ -930,6 +917,9 @@ var usePlayback = ({
930
917
  cancelQueuedFrame();
931
918
  };
932
919
  const callback = () => {
920
+ if (hasBeenStopped) {
921
+ return;
922
+ }
933
923
  const time = performance.now() - startedTime;
934
924
  const actualLastFrame = outFrame ?? config.durationInFrames - 1;
935
925
  const actualFirstFrame = inFrame ?? 0;
@@ -954,20 +944,15 @@ var usePlayback = ({
954
944
  emitter.dispatchEnded();
955
945
  return;
956
946
  }
957
- if (!hasBeenStopped) {
958
- queueNextFrame();
959
- }
947
+ queueNextFrame();
960
948
  };
961
949
  const queueNextFrame = () => {
962
- if (buffering.current) {
950
+ if (context.buffering.current) {
963
951
  const stopListening = context.listenForResume(() => {
964
952
  stopListening.remove();
965
- if (hasBeenStopped) {
966
- return;
967
- }
968
953
  startedTime = performance.now();
969
954
  framesAdvanced = 0;
970
- callback();
955
+ queueNextFrame();
971
956
  });
972
957
  return;
973
958
  }
@@ -976,9 +961,9 @@ var usePlayback = ({
976
961
  type: "timeout",
977
962
  id: setTimeout(callback, 1000 / config.fps)
978
963
  };
979
- } else {
980
- reqAnimFrameCall = { type: "raf", id: requestAnimationFrame(callback) };
964
+ return;
981
965
  }
966
+ reqAnimFrameCall = { type: "raf", id: requestAnimationFrame(callback) };
982
967
  };
983
968
  queueNextFrame();
984
969
  const onVisibilityChange = () => {
@@ -1006,7 +991,6 @@ var usePlayback = ({
1006
991
  moveToBeginningWhenEnded,
1007
992
  isBackgroundedRef,
1008
993
  getCurrentFrame,
1009
- buffering,
1010
994
  context
1011
995
  ]);
1012
996
  useEffect6(() => {
@@ -2384,6 +2368,7 @@ var PlayerUI = ({
2384
2368
  showPosterWhenEnded,
2385
2369
  showPosterWhenPaused,
2386
2370
  showPosterWhenBuffering,
2371
+ showPosterWhenBufferingAndPaused,
2387
2372
  inFrame,
2388
2373
  outFrame,
2389
2374
  initiallyShowControls,
@@ -2741,7 +2726,8 @@ var PlayerUI = ({
2741
2726
  showPosterWhenPaused && !player.isPlaying() && !seeking,
2742
2727
  showPosterWhenEnded && player.isLastFrame && !player.isPlaying(),
2743
2728
  showPosterWhenUnplayed && !player.hasPlayed && !player.isPlaying(),
2744
- showPosterWhenBuffering && showBufferIndicator && player.isPlaying()
2729
+ showPosterWhenBuffering && showBufferIndicator && player.isPlaying(),
2730
+ showPosterWhenBufferingAndPaused && showBufferIndicator && !player.isPlaying()
2745
2731
  ].some(Boolean);
2746
2732
  const { left, top, width, height, ...outerWithoutScale } = outer;
2747
2733
  const content = /* @__PURE__ */ jsxs9(Fragment3, {
@@ -3106,6 +3092,7 @@ var PlayerFn = ({
3106
3092
  showPosterWhenEnded,
3107
3093
  showPosterWhenPaused,
3108
3094
  showPosterWhenBuffering,
3095
+ showPosterWhenBufferingAndPaused,
3109
3096
  initialFrame,
3110
3097
  renderPoster,
3111
3098
  inFrame,
@@ -3286,6 +3273,7 @@ var PlayerFn = ({
3286
3273
  showPosterWhenEnded: Boolean(showPosterWhenEnded),
3287
3274
  showPosterWhenPaused: Boolean(showPosterWhenPaused),
3288
3275
  showPosterWhenBuffering: Boolean(showPosterWhenBuffering),
3276
+ showPosterWhenBufferingAndPaused: Boolean(showPosterWhenBufferingAndPaused),
3289
3277
  renderPoster,
3290
3278
  inFrame: inFrame ?? null,
3291
3279
  outFrame: outFrame ?? null,
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "url": "https://github.com/remotion-dev/remotion/tree/main/packages/player"
4
4
  },
5
5
  "name": "@remotion/player",
6
- "version": "4.0.289",
6
+ "version": "4.0.291",
7
7
  "description": "React component for embedding a Remotion preview into your app",
8
8
  "main": "dist/cjs/index.js",
9
9
  "types": "dist/cjs/index.d.ts",
@@ -28,7 +28,7 @@
28
28
  ],
29
29
  "license": "SEE LICENSE IN LICENSE.md",
30
30
  "dependencies": {
31
- "remotion": "4.0.289"
31
+ "remotion": "4.0.291"
32
32
  },
33
33
  "peerDependencies": {
34
34
  "react": ">=16.8.0",
@@ -43,7 +43,7 @@
43
43
  "webpack": "5.96.1",
44
44
  "zod": "3.22.3",
45
45
  "eslint": "9.19.0",
46
- "@remotion/eslint-config-internal": "4.0.289"
46
+ "@remotion/eslint-config-internal": "4.0.291"
47
47
  },
48
48
  "keywords": [
49
49
  "remotion",
@@ -1,171 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.usePlayback = void 0;
4
- /* eslint-disable @typescript-eslint/no-use-before-define */
5
- const react_1 = require("react");
6
- const react_dom_1 = require("react-dom");
7
- const remotion_1 = require("remotion");
8
- const browser_mediasession_js_1 = require("./browser-mediasession.js");
9
- const calculate_next_frame_js_1 = require("./calculate-next-frame.js");
10
- const is_backgrounded_js_1 = require("./is-backgrounded.js");
11
- const use_player_js_1 = require("./use-player.js");
12
- const usePlayback = ({ loop, playbackRate, moveToBeginningWhenEnded, inFrame, outFrame, browserMediaControlsBehavior, getCurrentFrame, }) => {
13
- const config = remotion_1.Internals.useUnsafeVideoConfig();
14
- const frame = remotion_1.Internals.Timeline.useTimelinePosition();
15
- const { playing, pause, emitter } = (0, use_player_js_1.usePlayer)();
16
- const setFrame = remotion_1.Internals.Timeline.useTimelineSetFrame();
17
- const buffering = (0, react_1.useRef)(null);
18
- // requestAnimationFrame() does not work if the tab is not active.
19
- // This means that audio will keep playing even if it has ended.
20
- // In that case, we use setTimeout() instead.
21
- const isBackgroundedRef = (0, is_backgrounded_js_1.useIsBackgrounded)();
22
- const lastTimeUpdateEvent = (0, react_1.useRef)(null);
23
- const context = (0, react_1.useContext)(remotion_1.Internals.BufferingContextReact);
24
- if (!context) {
25
- throw new Error('Missing the buffering context. Most likely you have a Remotion version mismatch.');
26
- }
27
- (0, browser_mediasession_js_1.useBrowserMediaSession)({
28
- browserMediaControlsBehavior,
29
- playbackRate,
30
- videoConfig: config,
31
- });
32
- // complete code for media session API
33
- (0, react_1.useEffect)(() => {
34
- const onBufferClear = context.listenForBuffering(() => {
35
- buffering.current = performance.now();
36
- });
37
- const onResumeClear = context.listenForResume(() => {
38
- buffering.current = null;
39
- });
40
- return () => {
41
- onBufferClear.remove();
42
- onResumeClear.remove();
43
- };
44
- }, [context]);
45
- (0, react_1.useEffect)(() => {
46
- if (!config) {
47
- return;
48
- }
49
- if (!playing) {
50
- return;
51
- }
52
- let hasBeenStopped = false;
53
- let reqAnimFrameCall = null;
54
- let startedTime = performance.now();
55
- let framesAdvanced = 0;
56
- const cancelQueuedFrame = () => {
57
- if (reqAnimFrameCall !== null) {
58
- if (reqAnimFrameCall.type === 'raf') {
59
- cancelAnimationFrame(reqAnimFrameCall.id);
60
- }
61
- else {
62
- clearTimeout(reqAnimFrameCall.id);
63
- }
64
- }
65
- };
66
- const stop = () => {
67
- hasBeenStopped = true;
68
- cancelQueuedFrame();
69
- };
70
- const callback = () => {
71
- const time = performance.now() - startedTime;
72
- const actualLastFrame = outFrame !== null && outFrame !== void 0 ? outFrame : config.durationInFrames - 1;
73
- const actualFirstFrame = inFrame !== null && inFrame !== void 0 ? inFrame : 0;
74
- const currentFrame = getCurrentFrame();
75
- const { nextFrame, framesToAdvance, hasEnded } = (0, calculate_next_frame_js_1.calculateNextFrame)({
76
- time,
77
- currentFrame,
78
- playbackSpeed: playbackRate,
79
- fps: config.fps,
80
- actualFirstFrame,
81
- actualLastFrame,
82
- framesAdvanced,
83
- shouldLoop: loop,
84
- });
85
- framesAdvanced += framesToAdvance;
86
- if (nextFrame !== getCurrentFrame() &&
87
- (!hasEnded || moveToBeginningWhenEnded)) {
88
- (0, react_dom_1.flushSync)(() => {
89
- setFrame((c) => ({ ...c, [config.id]: nextFrame }));
90
- });
91
- }
92
- if (hasEnded) {
93
- stop();
94
- pause();
95
- emitter.dispatchEnded();
96
- return;
97
- }
98
- if (!hasBeenStopped) {
99
- queueNextFrame();
100
- }
101
- };
102
- const queueNextFrame = () => {
103
- if (buffering.current) {
104
- const stopListening = context.listenForResume(() => {
105
- stopListening.remove();
106
- if (hasBeenStopped) {
107
- return;
108
- }
109
- startedTime = performance.now();
110
- framesAdvanced = 0;
111
- callback();
112
- });
113
- return;
114
- }
115
- if (isBackgroundedRef.current) {
116
- reqAnimFrameCall = {
117
- type: 'timeout',
118
- // Note: Most likely, this will not be 1000 / fps, but the browser will throttle it to ~1/sec.
119
- id: setTimeout(callback, 1000 / config.fps),
120
- };
121
- }
122
- else {
123
- reqAnimFrameCall = { type: 'raf', id: requestAnimationFrame(callback) };
124
- }
125
- };
126
- queueNextFrame();
127
- const onVisibilityChange = () => {
128
- if (document.visibilityState === 'visible') {
129
- return;
130
- }
131
- // If tab goes into the background, cancel requestAnimationFrame() and update immediately.
132
- // , so the transition to setTimeout() can be fulfilled.
133
- cancelQueuedFrame();
134
- callback();
135
- };
136
- window.addEventListener('visibilitychange', onVisibilityChange);
137
- return () => {
138
- window.removeEventListener('visibilitychange', onVisibilityChange);
139
- stop();
140
- };
141
- }, [
142
- config,
143
- loop,
144
- pause,
145
- playing,
146
- setFrame,
147
- emitter,
148
- playbackRate,
149
- inFrame,
150
- outFrame,
151
- moveToBeginningWhenEnded,
152
- isBackgroundedRef,
153
- getCurrentFrame,
154
- buffering,
155
- context,
156
- ]);
157
- (0, react_1.useEffect)(() => {
158
- const interval = setInterval(() => {
159
- if (lastTimeUpdateEvent.current === getCurrentFrame()) {
160
- return;
161
- }
162
- emitter.dispatchTimeUpdate({ frame: getCurrentFrame() });
163
- lastTimeUpdateEvent.current = getCurrentFrame();
164
- }, 250);
165
- return () => clearInterval(interval);
166
- }, [emitter, getCurrentFrame]);
167
- (0, react_1.useEffect)(() => {
168
- emitter.dispatchFrameUpdate({ frame });
169
- }, [emitter, frame]);
170
- };
171
- exports.usePlayback = usePlayback;