remotion 3.2.29 → 3.2.31

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.
Files changed (105) hide show
  1. package/.turbo/turbo-build.log +5 -5
  2. package/README.md +6 -0
  3. package/dist/RemotionRoot.js +5 -4
  4. package/dist/audio/Audio.d.ts +2 -2
  5. package/dist/audio/Audio.js +15 -2
  6. package/dist/audio/AudioForDevelopment.d.ts +2 -1
  7. package/dist/audio/AudioForDevelopment.js +22 -1
  8. package/dist/audio/AudioForRendering.d.ts +3 -1
  9. package/dist/audio/AudioForRendering.js +32 -0
  10. package/dist/audio/props.d.ts +1 -1
  11. package/dist/internals.d.ts +3 -0
  12. package/dist/internals.js +2 -0
  13. package/dist/play-and-handle-not-allowed-error.js +4 -0
  14. package/dist/version.d.ts +1 -1
  15. package/dist/version.js +1 -1
  16. package/dist/video/OffthreadVideo.d.ts +1 -1
  17. package/dist/video/OffthreadVideo.js +3 -1
  18. package/dist/video/Video.d.ts +2 -2
  19. package/dist/video/Video.js +14 -2
  20. package/dist/video/VideoForDevelopment.d.ts +2 -1
  21. package/dist/video/VideoForDevelopment.js +22 -1
  22. package/dist/video/VideoForRendering.d.ts +3 -1
  23. package/dist/video/VideoForRendering.js +31 -0
  24. package/dist/video/duration-state.d.ts +9 -0
  25. package/dist/video/duration-state.js +20 -1
  26. package/dist/video/props.d.ts +1 -1
  27. package/package.json +2 -2
  28. package/.turbo/turbo-lint.log +0 -11
  29. package/.turbo/turbo-test.log +0 -405
  30. package/dist/compress-assets.d.ts +0 -7
  31. package/dist/compress-assets.js +0 -25
  32. package/dist/config/browser-executable.d.ts +0 -3
  33. package/dist/config/browser-executable.js +0 -12
  34. package/dist/config/browser.d.ts +0 -4
  35. package/dist/config/browser.js +0 -19
  36. package/dist/config/chromium-flags.d.ts +0 -10
  37. package/dist/config/chromium-flags.js +0 -34
  38. package/dist/config/codec.d.ts +0 -16
  39. package/dist/config/codec.js +0 -109
  40. package/dist/config/concurrency.d.ts +0 -3
  41. package/dist/config/concurrency.js +0 -12
  42. package/dist/config/crf.d.ts +0 -9
  43. package/dist/config/crf.js +0 -83
  44. package/dist/config/env-file.d.ts +0 -2
  45. package/dist/config/env-file.js +0 -10
  46. package/dist/config/every-nth-frame.d.ts +0 -3
  47. package/dist/config/every-nth-frame.js +0 -20
  48. package/dist/config/ffmpeg-executable.d.ts +0 -5
  49. package/dist/config/ffmpeg-executable.js +0 -21
  50. package/dist/config/frame-range.d.ts +0 -5
  51. package/dist/config/frame-range.js +0 -80
  52. package/dist/config/image-format.d.ts +0 -8
  53. package/dist/config/image-format.js +0 -37
  54. package/dist/config/image-sequence.d.ts +0 -3
  55. package/dist/config/image-sequence.js +0 -15
  56. package/dist/config/index.d.ts +0 -178
  57. package/dist/config/index.js +0 -193
  58. package/dist/config/log.d.ts +0 -7
  59. package/dist/config/log.js +0 -25
  60. package/dist/config/max-timeline-tracks.d.ts +0 -2
  61. package/dist/config/max-timeline-tracks.js +0 -24
  62. package/dist/config/number-of-gif-loops.d.ts +0 -4
  63. package/dist/config/number-of-gif-loops.js +0 -21
  64. package/dist/config/override-webpack.d.ts +0 -6
  65. package/dist/config/override-webpack.js +0 -14
  66. package/dist/config/overwrite.d.ts +0 -3
  67. package/dist/config/overwrite.js +0 -14
  68. package/dist/config/pixel-format.d.ts +0 -8
  69. package/dist/config/pixel-format.js +0 -38
  70. package/dist/config/preview-server.d.ts +0 -2
  71. package/dist/config/preview-server.js +0 -20
  72. package/dist/config/prores-profile.d.ts +0 -7
  73. package/dist/config/prores-profile.js +0 -32
  74. package/dist/config/quality.d.ts +0 -2
  75. package/dist/config/quality.js +0 -17
  76. package/dist/config/scale.d.ts +0 -3
  77. package/dist/config/scale.js +0 -15
  78. package/dist/config/still-frame.d.ts +0 -2
  79. package/dist/config/still-frame.js +0 -12
  80. package/dist/config/timeout.d.ts +0 -2
  81. package/dist/config/timeout.js +0 -17
  82. package/dist/config/webpack-caching.d.ts +0 -3
  83. package/dist/config/webpack-caching.js +0 -16
  84. package/dist/feature-flags.d.ts +0 -1
  85. package/dist/feature-flags.js +0 -7
  86. package/dist/is-audio-codec.d.ts +0 -2
  87. package/dist/is-audio-codec.js +0 -7
  88. package/dist/perf/index.d.ts +0 -5
  89. package/dist/perf/index.js +0 -35
  90. package/dist/preload-state.d.ts +0 -13
  91. package/dist/preload-state.js +0 -26
  92. package/dist/timeline-inout-position-state.d.ts +0 -12
  93. package/dist/timeline-inout-position-state.js +0 -23
  94. package/dist/timeout.d.ts +0 -2
  95. package/dist/timeout.js +0 -12
  96. package/dist/validation/validate-every-nth-frame.d.ts +0 -1
  97. package/dist/validation/validate-every-nth-frame.js +0 -21
  98. package/dist/validation/validate-frame.d.ts +0 -1
  99. package/dist/validation/validate-frame.js +0 -24
  100. package/dist/validation/validate-image-format.d.ts +0 -2
  101. package/dist/validation/validate-image-format.js +0 -9
  102. package/dist/validation/validate-opengl-renderer.d.ts +0 -4
  103. package/dist/validation/validate-opengl-renderer.js +0 -14
  104. package/dist/validation/validate-quality.d.ts +0 -1
  105. package/dist/validation/validate-quality.js +0 -21
@@ -1,5 +1,5 @@
1
- remotion:build: cache hit, replaying output fecebd0c50bd4993
2
- remotion:build: 
3
- remotion:build: > remotion@3.2.28 build /Users/jonathanburger/remotion/packages/core
4
- remotion:build: > tsc -d
5
- remotion:build: 
1
+ remotion:build: cache hit, replaying output 688a3f5cb0017c0d
2
+ remotion:build: 
3
+ remotion:build: > remotion@3.2.30 build /Users/jonathanburger/remotion/packages/core
4
+ remotion:build: > tsc -d
5
+ remotion:build: 
package/README.md CHANGED
@@ -13,6 +13,12 @@
13
13
  [![Install Size](https://packagephobia.now.sh/badge?p=remotion)](https://packagephobia.now.sh/result?p=remotion)
14
14
  <a href="https://twitter.com/remotion_dev"><img src="https://img.shields.io/twitter/follow/remotion_dev?label=Twitter&style=social" alt="Twitter"></a>
15
15
 
16
+ <p style="color: orange">
17
+ <a href="https://remotion.dev/hacktoberfest"><strong style="color: orange">
18
+ 🎃 Hack on Remotion and earn bounties! $4000 are up for grabs in Hacktoberfest.
19
+ </strong></a> <a href="https://codechem.com">Sponsored by CodeChem!</a>
20
+ </p>
21
+
16
22
  Remotion is a framework for **creating videos programmatically using React.**
17
23
 
18
24
  ## Why create videos in React?
@@ -10,6 +10,7 @@ const nonce_1 = require("./nonce");
10
10
  const prefetch_state_1 = require("./prefetch-state");
11
11
  const random_1 = require("./random");
12
12
  const timeline_position_state_1 = require("./timeline-position-state");
13
+ const duration_state_1 = require("./video/duration-state");
13
14
  const RemotionRoot = ({ children }) => {
14
15
  var _a;
15
16
  const [remotionRootId] = (0, react_1.useState)(() => String((0, random_1.random)(null)));
@@ -62,10 +63,10 @@ const RemotionRoot = ({ children }) => {
62
63
  });
63
64
  }
64
65
  }, []);
65
- return ((0, jsx_runtime_1.jsx)(nonce_1.NonceContext.Provider, { value: nonceContext, children: (0, jsx_runtime_1.jsx)(timeline_position_state_1.TimelineContext.Provider, { value: timelineContextValue, children: (0, jsx_runtime_1.jsx)(timeline_position_state_1.SetTimelineContext.Provider, { value: setTimelineContextValue, children: (0, jsx_runtime_1.jsx)(prefetch_state_1.PrefetchProvider, { children: (0, jsx_runtime_1.jsx)(CompositionManager_1.CompositionManagerProvider, { children: (0, jsx_runtime_1.jsx)(shared_audio_tags_1.SharedAudioContextProvider
66
- // In the preview, which is mostly played on Desktop, we opt out of the autoplay policy fix as described in https://github.com/remotion-dev/remotion/pull/554, as it mostly applies to mobile.
67
- , {
66
+ return ((0, jsx_runtime_1.jsx)(nonce_1.NonceContext.Provider, { value: nonceContext, children: (0, jsx_runtime_1.jsx)(timeline_position_state_1.TimelineContext.Provider, { value: timelineContextValue, children: (0, jsx_runtime_1.jsx)(timeline_position_state_1.SetTimelineContext.Provider, { value: setTimelineContextValue, children: (0, jsx_runtime_1.jsx)(prefetch_state_1.PrefetchProvider, { children: (0, jsx_runtime_1.jsx)(CompositionManager_1.CompositionManagerProvider, { children: (0, jsx_runtime_1.jsx)(duration_state_1.DurationsContextProvider, { children: (0, jsx_runtime_1.jsx)(shared_audio_tags_1.SharedAudioContextProvider
68
67
  // In the preview, which is mostly played on Desktop, we opt out of the autoplay policy fix as described in https://github.com/remotion-dev/remotion/pull/554, as it mostly applies to mobile.
69
- numberOfAudioTags: 0, children: children }) }) }) }) }) }));
68
+ , {
69
+ // In the preview, which is mostly played on Desktop, we opt out of the autoplay policy fix as described in https://github.com/remotion-dev/remotion/pull/554, as it mostly applies to mobile.
70
+ numberOfAudioTags: 0, children: children }) }) }) }) }) }) }));
70
71
  };
71
72
  exports.RemotionRoot = RemotionRoot;
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import type { RemotionMainAudioProps } from './props';
3
- export declare const Audio: React.ForwardRefExoticComponent<Pick<Omit<React.DetailedHTMLProps<React.AudioHTMLAttributes<HTMLAudioElement>, HTMLAudioElement>, "onEnded" | "autoPlay" | "controls" | "loop"> & {
3
+ export declare const Audio: React.ForwardRefExoticComponent<Pick<Omit<React.DetailedHTMLProps<React.AudioHTMLAttributes<HTMLAudioElement>, HTMLAudioElement>, "onEnded" | "autoPlay" | "controls"> & {
4
4
  volume?: import("../volume-prop").VolumeProp | undefined;
5
5
  playbackRate?: number | undefined;
6
- } & RemotionMainAudioProps, "id" | "key" | "defaultChecked" | "defaultValue" | "suppressContentEditableWarning" | "suppressHydrationWarning" | "accessKey" | "className" | "contentEditable" | "contextMenu" | "dir" | "draggable" | "hidden" | "lang" | "placeholder" | "slot" | "spellCheck" | "style" | "tabIndex" | "title" | "translate" | "radioGroup" | "role" | "about" | "datatype" | "inlist" | "prefix" | "property" | "resource" | "typeof" | "vocab" | "autoCapitalize" | "autoCorrect" | "autoSave" | "color" | "itemProp" | "itemScope" | "itemType" | "itemID" | "itemRef" | "results" | "security" | "unselectable" | "inputMode" | "is" | "aria-activedescendant" | "aria-atomic" | "aria-autocomplete" | "aria-busy" | "aria-checked" | "aria-colcount" | "aria-colindex" | "aria-colspan" | "aria-controls" | "aria-current" | "aria-describedby" | "aria-details" | "aria-disabled" | "aria-dropeffect" | "aria-errormessage" | "aria-expanded" | "aria-flowto" | "aria-grabbed" | "aria-haspopup" | "aria-hidden" | "aria-invalid" | "aria-keyshortcuts" | "aria-label" | "aria-labelledby" | "aria-level" | "aria-live" | "aria-modal" | "aria-multiline" | "aria-multiselectable" | "aria-orientation" | "aria-owns" | "aria-placeholder" | "aria-posinset" | "aria-pressed" | "aria-readonly" | "aria-relevant" | "aria-required" | "aria-roledescription" | "aria-rowcount" | "aria-rowindex" | "aria-rowspan" | "aria-selected" | "aria-setsize" | "aria-sort" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "children" | "dangerouslySetInnerHTML" | "onCopy" | "onCopyCapture" | "onCut" | "onCutCapture" | "onPaste" | "onPasteCapture" | "onCompositionEnd" | "onCompositionEndCapture" | "onCompositionStart" | "onCompositionStartCapture" | "onCompositionUpdate" | "onCompositionUpdateCapture" | "onFocus" | "onFocusCapture" | "onBlur" | "onBlurCapture" | "onChange" | "onChangeCapture" | "onBeforeInput" | "onBeforeInputCapture" | "onInput" | "onInputCapture" | "onReset" | "onResetCapture" | "onSubmit" | "onSubmitCapture" | "onInvalid" | "onInvalidCapture" | "onLoad" | "onLoadCapture" | "onError" | "onErrorCapture" | "onKeyDown" | "onKeyDownCapture" | "onKeyPress" | "onKeyPressCapture" | "onKeyUp" | "onKeyUpCapture" | "onAbort" | "onAbortCapture" | "onCanPlay" | "onCanPlayCapture" | "onCanPlayThrough" | "onCanPlayThroughCapture" | "onDurationChange" | "onDurationChangeCapture" | "onEmptied" | "onEmptiedCapture" | "onEncrypted" | "onEncryptedCapture" | "onEndedCapture" | "onLoadedData" | "onLoadedDataCapture" | "onLoadedMetadata" | "onLoadedMetadataCapture" | "onLoadStart" | "onLoadStartCapture" | "onPause" | "onPauseCapture" | "onPlay" | "onPlayCapture" | "onPlaying" | "onPlayingCapture" | "onProgress" | "onProgressCapture" | "onRateChange" | "onRateChangeCapture" | "onSeeked" | "onSeekedCapture" | "onSeeking" | "onSeekingCapture" | "onStalled" | "onStalledCapture" | "onSuspend" | "onSuspendCapture" | "onTimeUpdate" | "onTimeUpdateCapture" | "onVolumeChange" | "onVolumeChangeCapture" | "onWaiting" | "onWaitingCapture" | "onAuxClick" | "onAuxClickCapture" | "onClick" | "onClickCapture" | "onContextMenu" | "onContextMenuCapture" | "onDoubleClick" | "onDoubleClickCapture" | "onDrag" | "onDragCapture" | "onDragEnd" | "onDragEndCapture" | "onDragEnter" | "onDragEnterCapture" | "onDragExit" | "onDragExitCapture" | "onDragLeave" | "onDragLeaveCapture" | "onDragOver" | "onDragOverCapture" | "onDragStart" | "onDragStartCapture" | "onDrop" | "onDropCapture" | "onMouseDown" | "onMouseDownCapture" | "onMouseEnter" | "onMouseLeave" | "onMouseMove" | "onMouseMoveCapture" | "onMouseOut" | "onMouseOutCapture" | "onMouseOver" | "onMouseOverCapture" | "onMouseUp" | "onMouseUpCapture" | "onSelect" | "onSelectCapture" | "onTouchCancel" | "onTouchCancelCapture" | "onTouchEnd" | "onTouchEndCapture" | "onTouchMove" | "onTouchMoveCapture" | "onTouchStart" | "onTouchStartCapture" | "onPointerDown" | "onPointerDownCapture" | "onPointerMove" | "onPointerMoveCapture" | "onPointerUp" | "onPointerUpCapture" | "onPointerCancel" | "onPointerCancelCapture" | "onPointerEnter" | "onPointerEnterCapture" | "onPointerLeave" | "onPointerLeaveCapture" | "onPointerOver" | "onPointerOverCapture" | "onPointerOut" | "onPointerOutCapture" | "onGotPointerCapture" | "onGotPointerCaptureCapture" | "onLostPointerCapture" | "onLostPointerCaptureCapture" | "onScroll" | "onScrollCapture" | "onWheel" | "onWheelCapture" | "onAnimationStart" | "onAnimationStartCapture" | "onAnimationEnd" | "onAnimationEndCapture" | "onAnimationIteration" | "onAnimationIterationCapture" | "onTransitionEnd" | "onTransitionEndCapture" | "src" | "volume" | "playbackRate" | "controlsList" | "crossOrigin" | "mediaGroup" | "muted" | "playsInline" | "preload" | keyof RemotionMainAudioProps> & React.RefAttributes<HTMLAudioElement>>;
6
+ } & RemotionMainAudioProps, "id" | "key" | "defaultChecked" | "defaultValue" | "suppressContentEditableWarning" | "suppressHydrationWarning" | "accessKey" | "className" | "contentEditable" | "contextMenu" | "dir" | "draggable" | "hidden" | "lang" | "placeholder" | "slot" | "spellCheck" | "style" | "tabIndex" | "title" | "translate" | "radioGroup" | "role" | "about" | "datatype" | "inlist" | "prefix" | "property" | "resource" | "typeof" | "vocab" | "autoCapitalize" | "autoCorrect" | "autoSave" | "color" | "itemProp" | "itemScope" | "itemType" | "itemID" | "itemRef" | "results" | "security" | "unselectable" | "inputMode" | "is" | "aria-activedescendant" | "aria-atomic" | "aria-autocomplete" | "aria-busy" | "aria-checked" | "aria-colcount" | "aria-colindex" | "aria-colspan" | "aria-controls" | "aria-current" | "aria-describedby" | "aria-details" | "aria-disabled" | "aria-dropeffect" | "aria-errormessage" | "aria-expanded" | "aria-flowto" | "aria-grabbed" | "aria-haspopup" | "aria-hidden" | "aria-invalid" | "aria-keyshortcuts" | "aria-label" | "aria-labelledby" | "aria-level" | "aria-live" | "aria-modal" | "aria-multiline" | "aria-multiselectable" | "aria-orientation" | "aria-owns" | "aria-placeholder" | "aria-posinset" | "aria-pressed" | "aria-readonly" | "aria-relevant" | "aria-required" | "aria-roledescription" | "aria-rowcount" | "aria-rowindex" | "aria-rowspan" | "aria-selected" | "aria-setsize" | "aria-sort" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "children" | "dangerouslySetInnerHTML" | "onCopy" | "onCopyCapture" | "onCut" | "onCutCapture" | "onPaste" | "onPasteCapture" | "onCompositionEnd" | "onCompositionEndCapture" | "onCompositionStart" | "onCompositionStartCapture" | "onCompositionUpdate" | "onCompositionUpdateCapture" | "onFocus" | "onFocusCapture" | "onBlur" | "onBlurCapture" | "onChange" | "onChangeCapture" | "onBeforeInput" | "onBeforeInputCapture" | "onInput" | "onInputCapture" | "onReset" | "onResetCapture" | "onSubmit" | "onSubmitCapture" | "onInvalid" | "onInvalidCapture" | "onLoad" | "onLoadCapture" | "onError" | "onErrorCapture" | "onKeyDown" | "onKeyDownCapture" | "onKeyPress" | "onKeyPressCapture" | "onKeyUp" | "onKeyUpCapture" | "onAbort" | "onAbortCapture" | "onCanPlay" | "onCanPlayCapture" | "onCanPlayThrough" | "onCanPlayThroughCapture" | "onDurationChange" | "onDurationChangeCapture" | "onEmptied" | "onEmptiedCapture" | "onEncrypted" | "onEncryptedCapture" | "onEndedCapture" | "onLoadedData" | "onLoadedDataCapture" | "onLoadedMetadata" | "onLoadedMetadataCapture" | "onLoadStart" | "onLoadStartCapture" | "onPause" | "onPauseCapture" | "onPlay" | "onPlayCapture" | "onPlaying" | "onPlayingCapture" | "onProgress" | "onProgressCapture" | "onRateChange" | "onRateChangeCapture" | "onSeeked" | "onSeekedCapture" | "onSeeking" | "onSeekingCapture" | "onStalled" | "onStalledCapture" | "onSuspend" | "onSuspendCapture" | "onTimeUpdate" | "onTimeUpdateCapture" | "onVolumeChange" | "onVolumeChangeCapture" | "onWaiting" | "onWaitingCapture" | "onAuxClick" | "onAuxClickCapture" | "onClick" | "onClickCapture" | "onContextMenu" | "onContextMenuCapture" | "onDoubleClick" | "onDoubleClickCapture" | "onDrag" | "onDragCapture" | "onDragEnd" | "onDragEndCapture" | "onDragEnter" | "onDragEnterCapture" | "onDragExit" | "onDragExitCapture" | "onDragLeave" | "onDragLeaveCapture" | "onDragOver" | "onDragOverCapture" | "onDragStart" | "onDragStartCapture" | "onDrop" | "onDropCapture" | "onMouseDown" | "onMouseDownCapture" | "onMouseEnter" | "onMouseLeave" | "onMouseMove" | "onMouseMoveCapture" | "onMouseOut" | "onMouseOutCapture" | "onMouseOver" | "onMouseOverCapture" | "onMouseUp" | "onMouseUpCapture" | "onSelect" | "onSelectCapture" | "onTouchCancel" | "onTouchCancelCapture" | "onTouchEnd" | "onTouchEndCapture" | "onTouchMove" | "onTouchMoveCapture" | "onTouchStart" | "onTouchStartCapture" | "onPointerDown" | "onPointerDownCapture" | "onPointerMove" | "onPointerMoveCapture" | "onPointerUp" | "onPointerUpCapture" | "onPointerCancel" | "onPointerCancelCapture" | "onPointerEnter" | "onPointerEnterCapture" | "onPointerLeave" | "onPointerLeaveCapture" | "onPointerOver" | "onPointerOverCapture" | "onPointerOut" | "onPointerOutCapture" | "onGotPointerCapture" | "onGotPointerCaptureCapture" | "onLostPointerCapture" | "onLostPointerCaptureCapture" | "onScroll" | "onScrollCapture" | "onWheel" | "onWheelCapture" | "onAnimationStart" | "onAnimationStartCapture" | "onAnimationEnd" | "onAnimationEndCapture" | "onAnimationIteration" | "onAnimationIterationCapture" | "onTransitionEnd" | "onTransitionEndCapture" | "src" | "volume" | "playbackRate" | "controlsList" | "crossOrigin" | "loop" | "mediaGroup" | "muted" | "playsInline" | "preload" | keyof RemotionMainAudioProps> & React.RefAttributes<HTMLAudioElement>>;
@@ -4,19 +4,32 @@ exports.Audio = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  const get_environment_1 = require("../get-environment");
7
+ const loop_1 = require("../loop");
7
8
  const Sequence_1 = require("../Sequence");
9
+ const use_video_config_1 = require("../use-video-config");
8
10
  const validate_media_props_1 = require("../validate-media-props");
9
11
  const validate_start_from_props_1 = require("../validate-start-from-props");
12
+ const duration_state_1 = require("../video/duration-state");
10
13
  const AudioForDevelopment_1 = require("./AudioForDevelopment");
11
14
  const AudioForRendering_1 = require("./AudioForRendering");
12
15
  const shared_audio_tags_1 = require("./shared-audio-tags");
13
16
  const AudioRefForwardingFunction = (props, ref) => {
14
17
  const audioContext = (0, react_1.useContext)(shared_audio_tags_1.SharedAudioContext);
15
18
  const { startFrom, endAt, ...otherProps } = props;
19
+ const { loop, ...propsOtherThanLoop } = props;
20
+ const { fps } = (0, use_video_config_1.useVideoConfig)();
21
+ const { durations, setDurations } = (0, react_1.useContext)(duration_state_1.DurationsContext);
16
22
  const onError = (0, react_1.useCallback)((e) => {
17
23
  console.log(e.currentTarget.error);
18
24
  throw new Error(`Could not play audio with src ${otherProps.src}: ${e.currentTarget.error}. See https://remotion.dev/docs/media-playback-error for help.`);
19
25
  }, [otherProps.src]);
26
+ const onDuration = (0, react_1.useCallback)((src, durationInSeconds) => {
27
+ setDurations({ type: 'got-duration', durationInSeconds, src });
28
+ }, [setDurations]);
29
+ if (loop && props.src && durations[props.src] !== undefined) {
30
+ const duration = Math.floor(durations[props.src] * fps);
31
+ return ((0, jsx_runtime_1.jsx)(loop_1.Loop, { layout: "none", durationInFrames: duration, children: (0, jsx_runtime_1.jsx)(exports.Audio, { ...propsOtherThanLoop, ref: ref }) }));
32
+ }
20
33
  if (typeof startFrom !== 'undefined' || typeof endAt !== 'undefined') {
21
34
  (0, validate_start_from_props_1.validateStartFromProps)(startFrom, endAt);
22
35
  const startFromFrameNo = startFrom !== null && startFrom !== void 0 ? startFrom : 0;
@@ -25,8 +38,8 @@ const AudioRefForwardingFunction = (props, ref) => {
25
38
  }
26
39
  (0, validate_media_props_1.validateMediaProps)(props, 'Audio');
27
40
  if ((0, get_environment_1.getRemotionEnvironment)() === 'rendering') {
28
- return (0, jsx_runtime_1.jsx)(AudioForRendering_1.AudioForRendering, { ...props, ref: ref, onError: onError });
41
+ return ((0, jsx_runtime_1.jsx)(AudioForRendering_1.AudioForRendering, { onDuration: onDuration, ...props, ref: ref, onError: onError }));
29
42
  }
30
- return ((0, jsx_runtime_1.jsx)(AudioForDevelopment_1.AudioForDevelopment, { shouldPreMountAudioTags: audioContext !== null && audioContext.numberOfAudioTags > 0, ...props, ref: ref, onError: onError }));
43
+ return ((0, jsx_runtime_1.jsx)(AudioForDevelopment_1.AudioForDevelopment, { shouldPreMountAudioTags: audioContext !== null && audioContext.numberOfAudioTags > 0, ...props, ref: ref, onError: onError, onDuration: onDuration }));
31
44
  };
32
45
  exports.Audio = (0, react_1.forwardRef)(AudioRefForwardingFunction);
@@ -1,8 +1,9 @@
1
1
  import type { ForwardRefExoticComponent, RefAttributes } from 'react';
2
2
  import React from 'react';
3
- export declare const AudioForDevelopment: ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.AudioHTMLAttributes<HTMLAudioElement>, HTMLAudioElement>, "onEnded" | "autoPlay" | "controls" | "loop"> & {
3
+ export declare const AudioForDevelopment: ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.AudioHTMLAttributes<HTMLAudioElement>, HTMLAudioElement>, "onEnded" | "autoPlay" | "controls"> & {
4
4
  volume?: import("../volume-prop").VolumeProp | undefined;
5
5
  playbackRate?: number | undefined;
6
6
  } & {
7
7
  shouldPreMountAudioTags: boolean;
8
+ onDuration: (src: string, durationInSeconds: number) => void;
8
9
  } & RefAttributes<HTMLAudioElement>>;
@@ -21,7 +21,7 @@ const AudioForDevelopmentForwardRefFunction = (props, ref) => {
21
21
  const [mediaVolume] = (0, volume_position_state_1.useMediaVolumeState)();
22
22
  const [mediaMuted] = (0, volume_position_state_1.useMediaMutedState)();
23
23
  const volumePropFrame = (0, use_audio_frame_1.useFrameForVolumeProp)();
24
- const { volume, muted, playbackRate, shouldPreMountAudioTags, src, ...nativeProps } = props;
24
+ const { volume, muted, playbackRate, shouldPreMountAudioTags, src, onDuration, ...nativeProps } = props;
25
25
  if (!src) {
26
26
  throw new TypeError("No 'src' was passed to <Audio>.");
27
27
  }
@@ -63,6 +63,27 @@ const AudioForDevelopmentForwardRefFunction = (props, ref) => {
63
63
  (0, react_1.useImperativeHandle)(ref, () => {
64
64
  return audioRef.current;
65
65
  }, [audioRef]);
66
+ const currentOnDurationCallback = (0, react_1.useRef)();
67
+ currentOnDurationCallback.current = onDuration;
68
+ (0, react_1.useEffect)(() => {
69
+ var _a;
70
+ const { current } = audioRef;
71
+ if (!current) {
72
+ return;
73
+ }
74
+ if (current.duration) {
75
+ (_a = currentOnDurationCallback.current) === null || _a === void 0 ? void 0 : _a.call(currentOnDurationCallback, src, current.duration);
76
+ return;
77
+ }
78
+ const onLoadedMetadata = () => {
79
+ var _a;
80
+ (_a = currentOnDurationCallback.current) === null || _a === void 0 ? void 0 : _a.call(currentOnDurationCallback, src, current.duration);
81
+ };
82
+ current.addEventListener('loadedmetadata', onLoadedMetadata);
83
+ return () => {
84
+ current.removeEventListener('loadedmetadata', onLoadedMetadata);
85
+ };
86
+ }, [audioRef, src]);
66
87
  if (initialShouldPreMountAudioElements) {
67
88
  return null;
68
89
  }
@@ -1,6 +1,8 @@
1
1
  import type { ForwardRefExoticComponent, RefAttributes } from 'react';
2
2
  import React from 'react';
3
- export declare const AudioForRendering: ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.AudioHTMLAttributes<HTMLAudioElement>, HTMLAudioElement>, "onEnded" | "autoPlay" | "controls" | "loop"> & {
3
+ export declare const AudioForRendering: ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.AudioHTMLAttributes<HTMLAudioElement>, HTMLAudioElement>, "onEnded" | "autoPlay" | "controls"> & {
4
4
  volume?: import("../volume-prop").VolumeProp | undefined;
5
5
  playbackRate?: number | undefined;
6
+ } & {
7
+ onDuration: (src: string, durationInSeconds: number) => void;
6
8
  } & RefAttributes<HTMLAudioElement>>;
@@ -5,6 +5,8 @@ const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  const absolute_src_1 = require("../absolute-src");
7
7
  const CompositionManager_1 = require("../CompositionManager");
8
+ const delay_render_1 = require("../delay-render");
9
+ const get_environment_1 = require("../get-environment");
8
10
  const random_1 = require("../random");
9
11
  const Sequence_1 = require("../Sequence");
10
12
  const timeline_position_state_1 = require("../timeline-position-state");
@@ -70,6 +72,36 @@ const AudioForRenderingRefForwardingFunction = (props, ref) => {
70
72
  playbackRate,
71
73
  props.playbackRate,
72
74
  ]);
75
+ const { src, onDuration } = props;
76
+ // If audio source switches, make new handle
77
+ if ((0, get_environment_1.getRemotionEnvironment)() === 'rendering') {
78
+ // eslint-disable-next-line react-hooks/rules-of-hooks
79
+ (0, react_1.useLayoutEffect)(() => {
80
+ if (process.env.NODE_ENV === 'test') {
81
+ return;
82
+ }
83
+ const newHandle = (0, delay_render_1.delayRender)('Loading <Audio> duration with src=' + src);
84
+ const { current } = audioRef;
85
+ const didLoad = () => {
86
+ if (current) {
87
+ onDuration(src, current.duration);
88
+ }
89
+ (0, delay_render_1.continueRender)(newHandle);
90
+ };
91
+ if (current === null || current === void 0 ? void 0 : current.duration) {
92
+ onDuration(src, current.duration);
93
+ (0, delay_render_1.continueRender)(newHandle);
94
+ }
95
+ else {
96
+ current === null || current === void 0 ? void 0 : current.addEventListener('loadedmetadata', didLoad, { once: true });
97
+ }
98
+ // If tag gets unmounted, clear pending handles because video metadata is not going to load
99
+ return () => {
100
+ current === null || current === void 0 ? void 0 : current.removeEventListener('loadedmetadata', didLoad);
101
+ (0, delay_render_1.continueRender)(newHandle);
102
+ };
103
+ }, [src, onDuration]);
104
+ }
73
105
  return (0, jsx_runtime_1.jsx)("audio", { ref: audioRef, ...nativeProps });
74
106
  };
75
107
  exports.AudioForRendering = (0, react_1.forwardRef)(AudioForRenderingRefForwardingFunction);
@@ -4,7 +4,7 @@ export declare type RemotionMainAudioProps = {
4
4
  startFrom?: number;
5
5
  endAt?: number;
6
6
  };
7
- export declare type RemotionAudioProps = Omit<React.DetailedHTMLProps<React.AudioHTMLAttributes<HTMLAudioElement>, HTMLAudioElement>, 'autoPlay' | 'controls' | 'loop' | 'onEnded'> & {
7
+ export declare type RemotionAudioProps = Omit<React.DetailedHTMLProps<React.AudioHTMLAttributes<HTMLAudioElement>, HTMLAudioElement>, 'autoPlay' | 'controls' | 'onEnded'> & {
8
8
  volume?: VolumeProp;
9
9
  playbackRate?: number;
10
10
  };
@@ -82,6 +82,9 @@ export declare const Internals: {
82
82
  PrefetchProvider: import("react").FC<{
83
83
  children: import("react").ReactNode;
84
84
  }>;
85
+ DurationsContextProvider: import("react").FC<{
86
+ children: import("react").ReactNode;
87
+ }>;
85
88
  };
86
89
  declare type WebpackConfiguration = Configuration;
87
90
  declare type WebpackOverrideFn = (currentConfiguration: WebpackConfiguration) => WebpackConfiguration;
package/dist/internals.js CHANGED
@@ -48,6 +48,7 @@ const validate_dimensions_1 = require("./validation/validate-dimensions");
48
48
  const validate_duration_in_frames_1 = require("./validation/validate-duration-in-frames");
49
49
  const validate_fps_1 = require("./validation/validate-fps");
50
50
  const validate_offthreadvideo_image_format_1 = require("./validation/validate-offthreadvideo-image-format");
51
+ const duration_state_1 = require("./video/duration-state");
51
52
  const volume_position_state_1 = require("./volume-position-state");
52
53
  const wrap_remotion_context_1 = require("./wrap-remotion-context");
53
54
  const Timeline = TimelinePosition;
@@ -90,4 +91,5 @@ exports.Internals = {
90
91
  CanUseRemotionHooks: CanUseRemotionHooks_1.CanUseRemotionHooks,
91
92
  enableLegacyRemotionConfig: config_1.enableLegacyRemotionConfig,
92
93
  PrefetchProvider: prefetch_state_1.PrefetchProvider,
94
+ DurationsContextProvider: duration_state_1.DurationsContextProvider,
93
95
  };
@@ -28,6 +28,10 @@ const playAndHandleNotAllowedError = (mediaRef, mediaType) => {
28
28
  if (err.message.includes('request was interrupted by a new load request')) {
29
29
  return;
30
30
  }
31
+ // Audio tag got unmounted
32
+ if (err.message.includes('because the media was removed from the document')) {
33
+ return;
34
+ }
31
35
  console.log(`Could not play ${mediaType} due to following error: `, err);
32
36
  if (!current.muted) {
33
37
  console.log(`The video will be muted and we'll retry playing it.`, err);
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const VERSION = "3.2.29";
1
+ export declare const VERSION = "3.2.31";
package/dist/version.js CHANGED
@@ -2,4 +2,4 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VERSION = void 0;
4
4
  // Automatically generated on publish
5
- exports.VERSION = '3.2.29';
5
+ exports.VERSION = '3.2.31';
@@ -1,3 +1,3 @@
1
1
  import React from 'react';
2
2
  import type { OffthreadVideoProps, RemotionMainVideoProps } from './props';
3
- export declare const OffthreadVideo: React.FC<OffthreadVideoProps & RemotionMainVideoProps>;
3
+ export declare const OffthreadVideo: React.FC<Omit<OffthreadVideoProps & RemotionMainVideoProps, 'loop'>>;
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.OffthreadVideo = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_1 = require("react");
5
6
  const get_environment_1 = require("../get-environment");
6
7
  const Sequence_1 = require("../Sequence");
7
8
  const validate_media_props_1 = require("../validate-media-props");
@@ -11,6 +12,7 @@ const OffthreadVideoForRendering_1 = require("./OffthreadVideoForRendering");
11
12
  const VideoForDevelopment_1 = require("./VideoForDevelopment");
12
13
  const OffthreadVideo = (props) => {
13
14
  const { startFrom, endAt, ...otherProps } = props;
15
+ const onDuration = (0, react_1.useCallback)(() => undefined, []);
14
16
  if (typeof startFrom !== 'undefined' || typeof endAt !== 'undefined') {
15
17
  (0, validate_start_from_props_1.validateStartFromProps)(startFrom, endAt);
16
18
  const startFromFrameNo = startFrom !== null && startFrom !== void 0 ? startFrom : 0;
@@ -22,6 +24,6 @@ const OffthreadVideo = (props) => {
22
24
  if ((0, get_environment_1.getRemotionEnvironment)() === 'rendering') {
23
25
  return (0, jsx_runtime_1.jsx)(OffthreadVideoForRendering_1.OffthreadVideoForRendering, { ...otherProps });
24
26
  }
25
- return (0, jsx_runtime_1.jsx)(VideoForDevelopment_1.VideoForDevelopment, { onlyWarnForMediaSeekingError: true, ...otherProps });
27
+ return ((0, jsx_runtime_1.jsx)(VideoForDevelopment_1.VideoForDevelopment, { onDuration: onDuration, onlyWarnForMediaSeekingError: true, ...otherProps }));
26
28
  };
27
29
  exports.OffthreadVideo = OffthreadVideo;
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import type { RemotionMainVideoProps } from './props';
3
- export declare const Video: React.ForwardRefExoticComponent<Pick<Omit<React.DetailedHTMLProps<React.VideoHTMLAttributes<HTMLVideoElement>, HTMLVideoElement>, "onEnded" | "autoPlay" | "controls" | "loop"> & {
3
+ export declare const Video: React.ForwardRefExoticComponent<Pick<Omit<React.DetailedHTMLProps<React.VideoHTMLAttributes<HTMLVideoElement>, HTMLVideoElement>, "onEnded" | "autoPlay" | "controls"> & {
4
4
  volume?: import("../volume-prop").VolumeProp | undefined;
5
5
  playbackRate?: number | undefined;
6
- } & RemotionMainVideoProps, "id" | "height" | "width" | "key" | "defaultChecked" | "defaultValue" | "suppressContentEditableWarning" | "suppressHydrationWarning" | "accessKey" | "className" | "contentEditable" | "contextMenu" | "dir" | "draggable" | "hidden" | "lang" | "placeholder" | "slot" | "spellCheck" | "style" | "tabIndex" | "title" | "translate" | "radioGroup" | "role" | "about" | "datatype" | "inlist" | "prefix" | "property" | "resource" | "typeof" | "vocab" | "autoCapitalize" | "autoCorrect" | "autoSave" | "color" | "itemProp" | "itemScope" | "itemType" | "itemID" | "itemRef" | "results" | "security" | "unselectable" | "inputMode" | "is" | "aria-activedescendant" | "aria-atomic" | "aria-autocomplete" | "aria-busy" | "aria-checked" | "aria-colcount" | "aria-colindex" | "aria-colspan" | "aria-controls" | "aria-current" | "aria-describedby" | "aria-details" | "aria-disabled" | "aria-dropeffect" | "aria-errormessage" | "aria-expanded" | "aria-flowto" | "aria-grabbed" | "aria-haspopup" | "aria-hidden" | "aria-invalid" | "aria-keyshortcuts" | "aria-label" | "aria-labelledby" | "aria-level" | "aria-live" | "aria-modal" | "aria-multiline" | "aria-multiselectable" | "aria-orientation" | "aria-owns" | "aria-placeholder" | "aria-posinset" | "aria-pressed" | "aria-readonly" | "aria-relevant" | "aria-required" | "aria-roledescription" | "aria-rowcount" | "aria-rowindex" | "aria-rowspan" | "aria-selected" | "aria-setsize" | "aria-sort" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "children" | "dangerouslySetInnerHTML" | "onCopy" | "onCopyCapture" | "onCut" | "onCutCapture" | "onPaste" | "onPasteCapture" | "onCompositionEnd" | "onCompositionEndCapture" | "onCompositionStart" | "onCompositionStartCapture" | "onCompositionUpdate" | "onCompositionUpdateCapture" | "onFocus" | "onFocusCapture" | "onBlur" | "onBlurCapture" | "onChange" | "onChangeCapture" | "onBeforeInput" | "onBeforeInputCapture" | "onInput" | "onInputCapture" | "onReset" | "onResetCapture" | "onSubmit" | "onSubmitCapture" | "onInvalid" | "onInvalidCapture" | "onLoad" | "onLoadCapture" | "onError" | "onErrorCapture" | "onKeyDown" | "onKeyDownCapture" | "onKeyPress" | "onKeyPressCapture" | "onKeyUp" | "onKeyUpCapture" | "onAbort" | "onAbortCapture" | "onCanPlay" | "onCanPlayCapture" | "onCanPlayThrough" | "onCanPlayThroughCapture" | "onDurationChange" | "onDurationChangeCapture" | "onEmptied" | "onEmptiedCapture" | "onEncrypted" | "onEncryptedCapture" | "onEndedCapture" | "onLoadedData" | "onLoadedDataCapture" | "onLoadedMetadata" | "onLoadedMetadataCapture" | "onLoadStart" | "onLoadStartCapture" | "onPause" | "onPauseCapture" | "onPlay" | "onPlayCapture" | "onPlaying" | "onPlayingCapture" | "onProgress" | "onProgressCapture" | "onRateChange" | "onRateChangeCapture" | "onSeeked" | "onSeekedCapture" | "onSeeking" | "onSeekingCapture" | "onStalled" | "onStalledCapture" | "onSuspend" | "onSuspendCapture" | "onTimeUpdate" | "onTimeUpdateCapture" | "onVolumeChange" | "onVolumeChangeCapture" | "onWaiting" | "onWaitingCapture" | "onAuxClick" | "onAuxClickCapture" | "onClick" | "onClickCapture" | "onContextMenu" | "onContextMenuCapture" | "onDoubleClick" | "onDoubleClickCapture" | "onDrag" | "onDragCapture" | "onDragEnd" | "onDragEndCapture" | "onDragEnter" | "onDragEnterCapture" | "onDragExit" | "onDragExitCapture" | "onDragLeave" | "onDragLeaveCapture" | "onDragOver" | "onDragOverCapture" | "onDragStart" | "onDragStartCapture" | "onDrop" | "onDropCapture" | "onMouseDown" | "onMouseDownCapture" | "onMouseEnter" | "onMouseLeave" | "onMouseMove" | "onMouseMoveCapture" | "onMouseOut" | "onMouseOutCapture" | "onMouseOver" | "onMouseOverCapture" | "onMouseUp" | "onMouseUpCapture" | "onSelect" | "onSelectCapture" | "onTouchCancel" | "onTouchCancelCapture" | "onTouchEnd" | "onTouchEndCapture" | "onTouchMove" | "onTouchMoveCapture" | "onTouchStart" | "onTouchStartCapture" | "onPointerDown" | "onPointerDownCapture" | "onPointerMove" | "onPointerMoveCapture" | "onPointerUp" | "onPointerUpCapture" | "onPointerCancel" | "onPointerCancelCapture" | "onPointerEnter" | "onPointerEnterCapture" | "onPointerLeave" | "onPointerLeaveCapture" | "onPointerOver" | "onPointerOverCapture" | "onPointerOut" | "onPointerOutCapture" | "onGotPointerCapture" | "onGotPointerCaptureCapture" | "onLostPointerCapture" | "onLostPointerCaptureCapture" | "onScroll" | "onScrollCapture" | "onWheel" | "onWheelCapture" | "onAnimationStart" | "onAnimationStartCapture" | "onAnimationEnd" | "onAnimationEndCapture" | "onAnimationIteration" | "onAnimationIterationCapture" | "onTransitionEnd" | "onTransitionEndCapture" | "src" | "volume" | "playbackRate" | "controlsList" | "crossOrigin" | "mediaGroup" | "muted" | "playsInline" | "preload" | "poster" | "disablePictureInPicture" | "disableRemotePlayback" | keyof RemotionMainVideoProps> & React.RefAttributes<HTMLVideoElement>>;
6
+ } & RemotionMainVideoProps, "id" | "height" | "width" | "key" | "defaultChecked" | "defaultValue" | "suppressContentEditableWarning" | "suppressHydrationWarning" | "accessKey" | "className" | "contentEditable" | "contextMenu" | "dir" | "draggable" | "hidden" | "lang" | "placeholder" | "slot" | "spellCheck" | "style" | "tabIndex" | "title" | "translate" | "radioGroup" | "role" | "about" | "datatype" | "inlist" | "prefix" | "property" | "resource" | "typeof" | "vocab" | "autoCapitalize" | "autoCorrect" | "autoSave" | "color" | "itemProp" | "itemScope" | "itemType" | "itemID" | "itemRef" | "results" | "security" | "unselectable" | "inputMode" | "is" | "aria-activedescendant" | "aria-atomic" | "aria-autocomplete" | "aria-busy" | "aria-checked" | "aria-colcount" | "aria-colindex" | "aria-colspan" | "aria-controls" | "aria-current" | "aria-describedby" | "aria-details" | "aria-disabled" | "aria-dropeffect" | "aria-errormessage" | "aria-expanded" | "aria-flowto" | "aria-grabbed" | "aria-haspopup" | "aria-hidden" | "aria-invalid" | "aria-keyshortcuts" | "aria-label" | "aria-labelledby" | "aria-level" | "aria-live" | "aria-modal" | "aria-multiline" | "aria-multiselectable" | "aria-orientation" | "aria-owns" | "aria-placeholder" | "aria-posinset" | "aria-pressed" | "aria-readonly" | "aria-relevant" | "aria-required" | "aria-roledescription" | "aria-rowcount" | "aria-rowindex" | "aria-rowspan" | "aria-selected" | "aria-setsize" | "aria-sort" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "children" | "dangerouslySetInnerHTML" | "onCopy" | "onCopyCapture" | "onCut" | "onCutCapture" | "onPaste" | "onPasteCapture" | "onCompositionEnd" | "onCompositionEndCapture" | "onCompositionStart" | "onCompositionStartCapture" | "onCompositionUpdate" | "onCompositionUpdateCapture" | "onFocus" | "onFocusCapture" | "onBlur" | "onBlurCapture" | "onChange" | "onChangeCapture" | "onBeforeInput" | "onBeforeInputCapture" | "onInput" | "onInputCapture" | "onReset" | "onResetCapture" | "onSubmit" | "onSubmitCapture" | "onInvalid" | "onInvalidCapture" | "onLoad" | "onLoadCapture" | "onError" | "onErrorCapture" | "onKeyDown" | "onKeyDownCapture" | "onKeyPress" | "onKeyPressCapture" | "onKeyUp" | "onKeyUpCapture" | "onAbort" | "onAbortCapture" | "onCanPlay" | "onCanPlayCapture" | "onCanPlayThrough" | "onCanPlayThroughCapture" | "onDurationChange" | "onDurationChangeCapture" | "onEmptied" | "onEmptiedCapture" | "onEncrypted" | "onEncryptedCapture" | "onEndedCapture" | "onLoadedData" | "onLoadedDataCapture" | "onLoadedMetadata" | "onLoadedMetadataCapture" | "onLoadStart" | "onLoadStartCapture" | "onPause" | "onPauseCapture" | "onPlay" | "onPlayCapture" | "onPlaying" | "onPlayingCapture" | "onProgress" | "onProgressCapture" | "onRateChange" | "onRateChangeCapture" | "onSeeked" | "onSeekedCapture" | "onSeeking" | "onSeekingCapture" | "onStalled" | "onStalledCapture" | "onSuspend" | "onSuspendCapture" | "onTimeUpdate" | "onTimeUpdateCapture" | "onVolumeChange" | "onVolumeChangeCapture" | "onWaiting" | "onWaitingCapture" | "onAuxClick" | "onAuxClickCapture" | "onClick" | "onClickCapture" | "onContextMenu" | "onContextMenuCapture" | "onDoubleClick" | "onDoubleClickCapture" | "onDrag" | "onDragCapture" | "onDragEnd" | "onDragEndCapture" | "onDragEnter" | "onDragEnterCapture" | "onDragExit" | "onDragExitCapture" | "onDragLeave" | "onDragLeaveCapture" | "onDragOver" | "onDragOverCapture" | "onDragStart" | "onDragStartCapture" | "onDrop" | "onDropCapture" | "onMouseDown" | "onMouseDownCapture" | "onMouseEnter" | "onMouseLeave" | "onMouseMove" | "onMouseMoveCapture" | "onMouseOut" | "onMouseOutCapture" | "onMouseOver" | "onMouseOverCapture" | "onMouseUp" | "onMouseUpCapture" | "onSelect" | "onSelectCapture" | "onTouchCancel" | "onTouchCancelCapture" | "onTouchEnd" | "onTouchEndCapture" | "onTouchMove" | "onTouchMoveCapture" | "onTouchStart" | "onTouchStartCapture" | "onPointerDown" | "onPointerDownCapture" | "onPointerMove" | "onPointerMoveCapture" | "onPointerUp" | "onPointerUpCapture" | "onPointerCancel" | "onPointerCancelCapture" | "onPointerEnter" | "onPointerEnterCapture" | "onPointerLeave" | "onPointerLeaveCapture" | "onPointerOver" | "onPointerOverCapture" | "onPointerOut" | "onPointerOutCapture" | "onGotPointerCapture" | "onGotPointerCaptureCapture" | "onLostPointerCapture" | "onLostPointerCaptureCapture" | "onScroll" | "onScrollCapture" | "onWheel" | "onWheelCapture" | "onAnimationStart" | "onAnimationStartCapture" | "onAnimationEnd" | "onAnimationEndCapture" | "onAnimationIteration" | "onAnimationIterationCapture" | "onTransitionEnd" | "onTransitionEndCapture" | "src" | "volume" | "playbackRate" | "controlsList" | "crossOrigin" | "loop" | "mediaGroup" | "muted" | "playsInline" | "preload" | "poster" | "disablePictureInPicture" | "disableRemotePlayback" | keyof RemotionMainVideoProps> & React.RefAttributes<HTMLVideoElement>>;
@@ -4,16 +4,28 @@ exports.Video = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  const get_environment_1 = require("../get-environment");
7
+ const loop_1 = require("../loop");
7
8
  const Sequence_1 = require("../Sequence");
9
+ const use_video_config_1 = require("../use-video-config");
8
10
  const validate_media_props_1 = require("../validate-media-props");
9
11
  const validate_start_from_props_1 = require("../validate-start-from-props");
12
+ const duration_state_1 = require("./duration-state");
10
13
  const VideoForDevelopment_1 = require("./VideoForDevelopment");
11
14
  const VideoForRendering_1 = require("./VideoForRendering");
12
15
  const VideoForwardingFunction = (props, ref) => {
13
16
  const { startFrom, endAt, ...otherProps } = props;
17
+ const { loop, ...propsOtherThanLoop } = props;
18
+ const { fps } = (0, use_video_config_1.useVideoConfig)();
19
+ const { durations, setDurations } = (0, react_1.useContext)(duration_state_1.DurationsContext);
14
20
  if (typeof ref === 'string') {
15
21
  throw new Error('string refs are not supported');
16
22
  }
23
+ const onDuration = (0, react_1.useCallback)((src, durationInSeconds) => {
24
+ setDurations({ type: 'got-duration', durationInSeconds, src });
25
+ }, [setDurations]);
26
+ if (loop && props.src && durations[props.src] !== undefined) {
27
+ return ((0, jsx_runtime_1.jsx)(loop_1.Loop, { durationInFrames: Math.round(durations[props.src] * fps), children: (0, jsx_runtime_1.jsx)(exports.Video, { ...propsOtherThanLoop, ref: ref }) }));
28
+ }
17
29
  if (typeof startFrom !== 'undefined' || typeof endAt !== 'undefined') {
18
30
  (0, validate_start_from_props_1.validateStartFromProps)(startFrom, endAt);
19
31
  const startFromFrameNo = startFrom !== null && startFrom !== void 0 ? startFrom : 0;
@@ -22,8 +34,8 @@ const VideoForwardingFunction = (props, ref) => {
22
34
  }
23
35
  (0, validate_media_props_1.validateMediaProps)(props, 'Video');
24
36
  if ((0, get_environment_1.getRemotionEnvironment)() === 'rendering') {
25
- return (0, jsx_runtime_1.jsx)(VideoForRendering_1.VideoForRendering, { ...otherProps, ref: ref });
37
+ return ((0, jsx_runtime_1.jsx)(VideoForRendering_1.VideoForRendering, { onDuration: onDuration, ...otherProps, ref: ref }));
26
38
  }
27
- return ((0, jsx_runtime_1.jsx)(VideoForDevelopment_1.VideoForDevelopment, { onlyWarnForMediaSeekingError: false, ...otherProps, ref: ref }));
39
+ return ((0, jsx_runtime_1.jsx)(VideoForDevelopment_1.VideoForDevelopment, { onlyWarnForMediaSeekingError: false, ...otherProps, ref: ref, onDuration: onDuration }));
28
40
  };
29
41
  exports.Video = (0, react_1.forwardRef)(VideoForwardingFunction);
@@ -1,8 +1,9 @@
1
1
  import type { ForwardRefExoticComponent, RefAttributes } from 'react';
2
2
  import React from 'react';
3
- export declare const VideoForDevelopment: ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.VideoHTMLAttributes<HTMLVideoElement>, HTMLVideoElement>, "onEnded" | "autoPlay" | "controls" | "loop"> & {
3
+ export declare const VideoForDevelopment: ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.VideoHTMLAttributes<HTMLVideoElement>, HTMLVideoElement>, "onEnded" | "autoPlay" | "controls"> & {
4
4
  volume?: import("../volume-prop").VolumeProp | undefined;
5
5
  playbackRate?: number | undefined;
6
6
  } & {
7
7
  onlyWarnForMediaSeekingError: boolean;
8
+ onDuration: (src: string, durationInSeconds: number) => void;
8
9
  } & RefAttributes<HTMLVideoElement>>;
@@ -14,7 +14,7 @@ const VideoForDevelopmentRefForwardingFunction = (props, ref) => {
14
14
  var _a;
15
15
  const videoRef = (0, react_1.useRef)(null);
16
16
  const volumePropFrame = (0, use_audio_frame_1.useFrameForVolumeProp)();
17
- const { volume, muted, playbackRate, onlyWarnForMediaSeekingError, src, ...nativeProps } = props;
17
+ const { volume, muted, playbackRate, onlyWarnForMediaSeekingError, src, onDuration, ...nativeProps } = props;
18
18
  const actualVolume = (0, use_media_tag_volume_1.useMediaTagVolume)(videoRef);
19
19
  const [mediaVolume] = (0, volume_position_state_1.useMediaVolumeState)();
20
20
  const [mediaMuted] = (0, volume_position_state_1.useMediaMutedState)();
@@ -63,6 +63,27 @@ const VideoForDevelopmentRefForwardingFunction = (props, ref) => {
63
63
  current.removeEventListener('error', errorHandler);
64
64
  };
65
65
  }, [src]);
66
+ const currentOnDurationCallback = (0, react_1.useRef)();
67
+ currentOnDurationCallback.current = onDuration;
68
+ (0, react_1.useEffect)(() => {
69
+ var _a;
70
+ const { current } = videoRef;
71
+ if (!current) {
72
+ return;
73
+ }
74
+ if (current.duration) {
75
+ (_a = currentOnDurationCallback.current) === null || _a === void 0 ? void 0 : _a.call(currentOnDurationCallback, src, current.duration);
76
+ return;
77
+ }
78
+ const onLoadedMetadata = () => {
79
+ var _a;
80
+ (_a = currentOnDurationCallback.current) === null || _a === void 0 ? void 0 : _a.call(currentOnDurationCallback, src, current.duration);
81
+ };
82
+ current.addEventListener('loadedmetadata', onLoadedMetadata);
83
+ return () => {
84
+ current.removeEventListener('loadedmetadata', onLoadedMetadata);
85
+ };
86
+ }, [src]);
66
87
  return ((0, jsx_runtime_1.jsx)("video", { ref: videoRef, muted: muted || mediaMuted, playsInline: true, src: actualSrc, ...nativeProps }));
67
88
  };
68
89
  // Copy types from forwardRef but not necessary to remove ref
@@ -1,6 +1,8 @@
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>, "onEnded" | "autoPlay" | "controls" | "loop"> & {
3
+ export declare const VideoForRendering: ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.VideoHTMLAttributes<HTMLVideoElement>, HTMLVideoElement>, "onEnded" | "autoPlay" | "controls"> & {
4
4
  volume?: import("../volume-prop").VolumeProp | undefined;
5
5
  playbackRate?: number | undefined;
6
+ } & {
7
+ onDuration: (src: string, durationInSeconds: number) => void;
6
8
  } & RefAttributes<HTMLVideoElement>>;
@@ -7,6 +7,7 @@ const absolute_src_1 = require("../absolute-src");
7
7
  const use_audio_frame_1 = require("../audio/use-audio-frame");
8
8
  const CompositionManager_1 = require("../CompositionManager");
9
9
  const delay_render_1 = require("../delay-render");
10
+ const get_environment_1 = require("../get-environment");
10
11
  const is_approximately_the_same_1 = require("../is-approximately-the-same");
11
12
  const random_1 = require("../random");
12
13
  const Sequence_1 = require("../Sequence");
@@ -163,6 +164,36 @@ const VideoForRenderingForwardFunction = ({ onError, volume: volumeProp, playbac
163
164
  frame,
164
165
  mediaStartsAt,
165
166
  ]);
167
+ const { src, onDuration } = props;
168
+ // If video source switches, make new handle
169
+ if ((0, get_environment_1.getRemotionEnvironment)() === 'rendering') {
170
+ // eslint-disable-next-line react-hooks/rules-of-hooks
171
+ (0, react_1.useLayoutEffect)(() => {
172
+ if (process.env.NODE_ENV === 'test') {
173
+ return;
174
+ }
175
+ const newHandle = (0, delay_render_1.delayRender)('Loading <Video> duration with src=' + src);
176
+ const { current } = videoRef;
177
+ const didLoad = () => {
178
+ if (current) {
179
+ onDuration(src, current.duration);
180
+ }
181
+ (0, delay_render_1.continueRender)(newHandle);
182
+ };
183
+ if (current === null || current === void 0 ? void 0 : current.duration) {
184
+ onDuration(src, current.duration);
185
+ (0, delay_render_1.continueRender)(newHandle);
186
+ }
187
+ else {
188
+ current === null || current === void 0 ? void 0 : current.addEventListener('loadedmetadata', didLoad, { once: true });
189
+ }
190
+ // If tag gets unmounted, clear pending handles because video metadata is not going to load
191
+ return () => {
192
+ current === null || current === void 0 ? void 0 : current.removeEventListener('loadedmetadata', didLoad);
193
+ (0, delay_render_1.continueRender)(newHandle);
194
+ };
195
+ }, [src, onDuration]);
196
+ }
166
197
  return (0, jsx_runtime_1.jsx)("video", { ref: videoRef, ...props, onError: onError });
167
198
  };
168
199
  exports.VideoForRendering = (0, react_1.forwardRef)(VideoForRenderingForwardFunction);
@@ -1,3 +1,4 @@
1
+ import React from 'react';
1
2
  declare type DurationState = Record<string, number>;
2
3
  declare type DurationAction = {
3
4
  type: 'got-duration';
@@ -5,4 +6,12 @@ declare type DurationAction = {
5
6
  durationInSeconds: number;
6
7
  };
7
8
  export declare const durationReducer: (state: DurationState, action: DurationAction) => DurationState;
9
+ declare type TDurationsContext = {
10
+ durations: DurationState;
11
+ setDurations: React.Dispatch<DurationAction>;
12
+ };
13
+ export declare const DurationsContext: React.Context<TDurationsContext>;
14
+ export declare const DurationsContextProvider: React.FC<{
15
+ children: React.ReactNode;
16
+ }>;
8
17
  export {};
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.durationReducer = void 0;
3
+ exports.DurationsContextProvider = exports.DurationsContext = exports.durationReducer = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_1 = require("react");
4
6
  const durationReducer = (state, action) => {
5
7
  switch (action.type) {
6
8
  case 'got-duration':
@@ -13,3 +15,20 @@ const durationReducer = (state, action) => {
13
15
  }
14
16
  };
15
17
  exports.durationReducer = durationReducer;
18
+ exports.DurationsContext = (0, react_1.createContext)({
19
+ durations: {},
20
+ setDurations: () => {
21
+ throw new Error('context missing');
22
+ },
23
+ });
24
+ const DurationsContextProvider = ({ children }) => {
25
+ const [durations, setDurations] = (0, react_1.useReducer)(exports.durationReducer, {});
26
+ const value = (0, react_1.useMemo)(() => {
27
+ return {
28
+ durations,
29
+ setDurations,
30
+ };
31
+ }, [durations]);
32
+ return ((0, jsx_runtime_1.jsx)(exports.DurationsContext.Provider, { value: value, children: children }));
33
+ };
34
+ exports.DurationsContextProvider = DurationsContextProvider;
@@ -4,7 +4,7 @@ export declare type RemotionMainVideoProps = {
4
4
  startFrom?: number;
5
5
  endAt?: number;
6
6
  };
7
- export declare type RemotionVideoProps = Omit<React.DetailedHTMLProps<React.VideoHTMLAttributes<HTMLVideoElement>, HTMLVideoElement>, 'autoPlay' | 'controls' | 'loop' | 'onEnded'> & {
7
+ export declare type RemotionVideoProps = Omit<React.DetailedHTMLProps<React.VideoHTMLAttributes<HTMLVideoElement>, HTMLVideoElement>, 'autoPlay' | 'controls' | 'onEnded'> & {
8
8
  volume?: VolumeProp;
9
9
  playbackRate?: number;
10
10
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "remotion",
3
- "version": "3.2.29",
3
+ "version": "3.2.31",
4
4
  "description": "Render videos in React",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -54,5 +54,5 @@
54
54
  "publishConfig": {
55
55
  "access": "public"
56
56
  },
57
- "gitHead": "9a2ff4d68324af8d1fe55ebdf94bdadccf446a10"
57
+ "gitHead": "f011b454d78903e548c32f548d8fef642c5ff7a6"
58
58
  }
@@ -1,11 +0,0 @@
1
- remotion:lint: cache hit, replaying output a84ebb2d28d1ea54
2
- remotion:lint: 
3
- remotion:lint: > remotion@3.2.12 lint /Users/jonathanburger/remotion/packages/core
4
- remotion:lint: > eslint src --ext ts,tsx
5
- remotion:lint: 
6
- remotion:lint: 
7
- remotion:lint: /Users/jonathanburger/remotion/packages/core/src/use-lazy-component.ts
8
- remotion:lint:  10:50 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any
9
- remotion:lint: 
10
- remotion:lint: ✖ 1 problem (0 errors, 1 warning)
11
- remotion:lint: