remotion 4.0.528 → 4.0.530

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 (79) hide show
  1. package/dist/cjs/AbsoluteFill.d.ts +7 -1
  2. package/dist/cjs/AbsoluteFill.js +10 -7
  3. package/dist/cjs/HtmlInCanvas.d.ts +11 -2
  4. package/dist/cjs/HtmlInCanvas.js +62 -17
  5. package/dist/cjs/Img.d.ts +6 -0
  6. package/dist/cjs/Img.js +12 -9
  7. package/dist/cjs/Interactive.d.ts +33 -2
  8. package/dist/cjs/Interactive.js +61 -8
  9. package/dist/cjs/Sequence.d.ts +3 -2
  10. package/dist/cjs/Sequence.js +103 -32
  11. package/dist/cjs/SequenceManager.d.ts +4 -0
  12. package/dist/cjs/SequenceManager.js +6 -1
  13. package/dist/cjs/TimelineContext.d.ts +1 -1
  14. package/dist/cjs/TimelineContext.js +2 -2
  15. package/dist/cjs/animated-image/AnimatedImage.d.ts +6 -0
  16. package/dist/cjs/animated-image/AnimatedImage.js +85 -16
  17. package/dist/cjs/audio/AudioForPreview.js +2 -3
  18. package/dist/cjs/audio/html5-audio.js +18 -6
  19. package/dist/cjs/audio/props.d.ts +5 -0
  20. package/dist/cjs/calculate-media-duration.d.ts +5 -0
  21. package/dist/cjs/calculate-media-duration.js +13 -1
  22. package/dist/cjs/canvas-image/CanvasImage.d.ts +6 -2
  23. package/dist/cjs/canvas-image/CanvasImage.js +10 -8
  24. package/dist/cjs/canvas-image/props.d.ts +0 -5
  25. package/dist/cjs/effects/Solid.d.ts +6 -0
  26. package/dist/cjs/effects/Solid.js +8 -3
  27. package/dist/cjs/effects/canvas-pool.d.ts +5 -1
  28. package/dist/cjs/effects/canvas-pool.js +49 -1
  29. package/dist/cjs/effects/run-effect-chain.d.ts +1 -0
  30. package/dist/cjs/effects/run-effect-chain.js +40 -10
  31. package/dist/cjs/effects/use-effect-chain-state.js +12 -0
  32. package/dist/cjs/effects/use-memoized-effects.js +1 -1
  33. package/dist/cjs/enable-sequence-stack-traces.d.ts +11 -0
  34. package/dist/cjs/enable-sequence-stack-traces.js +24 -1
  35. package/dist/cjs/freeze.d.ts +2 -0
  36. package/dist/cjs/freeze.js +8 -3
  37. package/dist/cjs/get-effective-visual-mode-value.js +3 -2
  38. package/dist/cjs/index.d.ts +1 -1
  39. package/dist/cjs/index.js +2 -1
  40. package/dist/cjs/interactivity-schema.d.ts +44 -1
  41. package/dist/cjs/interactivity-schema.js +18 -1
  42. package/dist/cjs/internals.d.ts +61 -8
  43. package/dist/cjs/internals.js +14 -1
  44. package/dist/cjs/interpolate-keyframed-status.d.ts +7 -1
  45. package/dist/cjs/interpolate-keyframed-status.js +34 -3
  46. package/dist/cjs/interpolate.d.ts +3 -1
  47. package/dist/cjs/interpolate.js +25 -5
  48. package/dist/cjs/loop/index.d.ts +1 -4
  49. package/dist/cjs/loop/index.js +16 -11
  50. package/dist/cjs/loop/loop-context.d.ts +5 -0
  51. package/dist/cjs/loop/loop-context.js +5 -0
  52. package/dist/cjs/no-react.d.ts +6 -0
  53. package/dist/cjs/resolve-sequence-duration.d.ts +8 -0
  54. package/dist/cjs/resolve-sequence-duration.js +18 -0
  55. package/dist/cjs/sequence-order-marker.d.ts +1 -0
  56. package/dist/cjs/sequence-outline.d.ts +11 -0
  57. package/dist/cjs/sequence-outline.js +35 -0
  58. package/dist/cjs/series/index.js +7 -1
  59. package/dist/cjs/timeline-position-state.d.ts +1 -1
  60. package/dist/cjs/timeline-position-state.js +9 -8
  61. package/dist/cjs/use-media-in-timeline.d.ts +3 -5
  62. package/dist/cjs/use-media-in-timeline.js +11 -21
  63. package/dist/cjs/use-schema.d.ts +9 -3
  64. package/dist/cjs/use-schema.js +10 -1
  65. package/dist/cjs/use-sequence-registration.js +5 -3
  66. package/dist/cjs/use-timeline-seek.d.ts +1 -1
  67. package/dist/cjs/use-timeline-seek.js +1 -1
  68. package/dist/cjs/version.d.ts +1 -1
  69. package/dist/cjs/version.js +1 -1
  70. package/dist/cjs/video/OffthreadVideo.js +21 -8
  71. package/dist/cjs/video/VideoForPreview.js +2 -3
  72. package/dist/cjs/video/html5-video.js +18 -6
  73. package/dist/cjs/video/props.d.ts +5 -0
  74. package/dist/cjs/with-interactivity-schema.d.ts +3 -0
  75. package/dist/cjs/with-interactivity-schema.js +10 -2
  76. package/dist/esm/index.mjs +1018 -466
  77. package/dist/esm/no-react.mjs +27 -5
  78. package/dist/esm/version.mjs +1 -1
  79. package/package.json +2 -2
@@ -9,8 +9,11 @@ const enable_sequence_stack_traces_js_1 = require("./enable-sequence-stack-trace
9
9
  const freeze_js_1 = require("./freeze.js");
10
10
  const get_sequence_boundary_tolerance_js_1 = require("./get-sequence-boundary-tolerance.js");
11
11
  const interactivity_schema_js_1 = require("./interactivity-schema.js");
12
+ const loop_context_js_1 = require("./loop/loop-context.js");
13
+ const resolve_sequence_duration_js_1 = require("./resolve-sequence-duration.js");
12
14
  const sequence_crop_js_1 = require("./sequence-crop.js");
13
15
  const sequence_order_marker_js_1 = require("./sequence-order-marker.js");
16
+ const sequence_outline_js_1 = require("./sequence-outline.js");
14
17
  const SequenceContext_js_1 = require("./SequenceContext.js");
15
18
  const SequenceManager_js_1 = require("./SequenceManager.js");
16
19
  const is_inside_series_js_1 = require("./series/is-inside-series.js");
@@ -22,7 +25,7 @@ const use_video_config_js_1 = require("./use-video-config.js");
22
25
  const v5_flag_js_1 = require("./v5-flag.js");
23
26
  const with_interactivity_schema_js_1 = require("./with-interactivity-schema.js");
24
27
  const EMPTY_EFFECTS = [];
25
- const RegularSequenceRefForwardingFunction = ({ from = 0, trimBefore = 0, playbackRate = 1, freeze, durationInFrames = Infinity, children, name, height, width, showInTimeline = true, hidden = false, controls, _remotionInternalEffects, _remotionInternalLoopDisplay: loopDisplay, _remotionInternalStack: stack, _remotionInternalDocumentationLink: documentationLink, _remotionInternalSingleChildComponent: singleChildComponent, _remotionInternalPremountDisplay: premountDisplay, _remotionInternalPostmountDisplay: postmountDisplay, _remotionInternalIsMedia: isMedia, outlineRef: passedRefForOutline, cropLeft, cropRight, cropTop, cropBottom, ...other }, ref) => {
28
+ const RegularSequenceRefForwardingFunction = ({ from = 0, trimBefore = 0, playbackRate = 1, loop = false, freeze, durationInFrames, children, name, height, width, showInTimeline = true, hidden = false, controls, _remotionInternalEffects, _remotionInternalLoopDisplay: loopDisplay, _remotionInternalStack: stack, _remotionInternalDocumentationLink: documentationLink, _remotionInternalSingleChildComponent: singleChildComponent, _remotionInternalPremountDisplay: premountDisplay, _remotionInternalPostmountDisplay: postmountDisplay, _remotionInternalIsMedia: isMedia, outlineRef: passedRefForOutline, cropLeft, cropRight, cropTop, cropBottom, ...other }, ref) => {
26
29
  var _a, _b, _c, _d, _e;
27
30
  const { layout = 'absolute-fill' } = other;
28
31
  const [id] = (0, react_1.useState)(() => String(Math.random()));
@@ -48,11 +51,14 @@ const RegularSequenceRefForwardingFunction = ({ from = 0, trimBefore = 0, playba
48
51
  // @ts-expect-error
49
52
  JSON.stringify(other.style));
50
53
  }
51
- if (typeof durationInFrames !== 'number') {
52
- throw new TypeError(`You passed to durationInFrames an argument of type ${typeof durationInFrames}, but it must be a number.`);
54
+ const contentDurationInFrames = (0, resolve_sequence_duration_js_1.resolveSequenceContentDuration)({
55
+ durationInFrames,
56
+ });
57
+ if (typeof contentDurationInFrames !== 'number') {
58
+ throw new TypeError(`You passed to durationInFrames an argument of type ${typeof contentDurationInFrames}, but it must be a number.`);
53
59
  }
54
- if (durationInFrames <= 0) {
55
- throw new TypeError(`durationInFrames must be positive, but got ${durationInFrames}`);
60
+ if (contentDurationInFrames <= 0) {
61
+ throw new TypeError(`durationInFrames must be positive, but got ${contentDurationInFrames}`);
56
62
  }
57
63
  if (typeof from !== 'number') {
58
64
  throw new TypeError(`You passed to the "from" props of your <Sequence> an argument of type ${typeof from}, but it must be a number.`);
@@ -72,6 +78,12 @@ const RegularSequenceRefForwardingFunction = ({ from = 0, trimBefore = 0, playba
72
78
  if (!Number.isFinite(trimBefore)) {
73
79
  throw new TypeError(`The "trimBefore" prop of <Sequence /> must be finite, but it is ${trimBefore}.`);
74
80
  }
81
+ if (typeof loop !== 'boolean') {
82
+ throw new TypeError(`The "loop" prop of <Sequence /> must be a boolean, but is of type ${typeof loop}.`);
83
+ }
84
+ if (loop && !Number.isFinite(contentDurationInFrames)) {
85
+ throw new Error('The "loop" prop of <Sequence /> requires a finite "durationInFrames" prop, because a <Sequence /> has no intrinsic duration.');
86
+ }
75
87
  if (typeof freeze !== 'undefined' && freeze !== null) {
76
88
  if (typeof freeze !== 'number') {
77
89
  throw new TypeError(`The "freeze" prop of <Sequence /> must be a number, but is of type ${typeof freeze}.`);
@@ -96,17 +108,56 @@ const RegularSequenceRefForwardingFunction = ({ from = 0, trimBefore = 0, playba
96
108
  }
97
109
  lastPlaybackRate.current = { playbackRate, frame: absoluteFrame };
98
110
  const videoConfig = (0, use_video_config_js_1.useVideoConfig)();
99
- const effectiveRelativeFrom = from - trimBefore / playbackRate;
100
- const relativeFrom = effectiveRelativeFrom / parentPlaybackRate;
101
- const absoluteFrom = ((_b = parentSequence === null || parentSequence === void 0 ? void 0 : parentSequence.absoluteFrom) !== null && _b !== void 0 ? _b : 0) + relativeFrom;
111
+ const effectiveDurationInFrames = (0, resolve_sequence_duration_js_1.resolveSequenceDuration)({
112
+ durationInFrames,
113
+ playbackRate,
114
+ loop,
115
+ });
116
+ const windowRelativeFrom = from - trimBefore / playbackRate;
102
117
  const parentSequenceDuration = parentSequence
103
- ? Math.min(parentSequence.durationInFrames - effectiveRelativeFrom, durationInFrames)
104
- : durationInFrames;
118
+ ? Math.min(parentSequence.durationInFrames - windowRelativeFrom, effectiveDurationInFrames)
119
+ : effectiveDurationInFrames;
105
120
  const actualDurationInFrames = Math.max(0, Math.min(videoConfig.durationInFrames - from, parentSequenceDuration));
121
+ // A looped sequence repeats the child range selected by `durationInFrames`. Each
122
+ // iteration lasts `loopPeriod` parent frames and moves the clock origin,
123
+ // while the visible window stays at [from, from + effectiveDurationInFrames).
124
+ const frameInParent = (absoluteFrame - cumulatedFrom) * parentPlaybackRate;
125
+ const loopPeriod = loop && Number.isFinite(contentDurationInFrames)
126
+ ? contentDurationInFrames / playbackRate
127
+ : null;
128
+ let loopIteration = 0;
129
+ if (loopPeriod !== null) {
130
+ const loopsElapsed = (frameInParent - from) / loopPeriod;
131
+ const nearestIteration = Math.round(loopsElapsed);
132
+ // Fractional periods and nested playback rates can put an exact loop
133
+ // boundary a few floating-point units before the next iteration.
134
+ const isAtBoundary = Math.abs(loopsElapsed - nearestIteration) <=
135
+ Number.EPSILON * Math.max(1, Math.abs(loopsElapsed)) * 4;
136
+ const lastIteration = Math.ceil(actualDurationInFrames / loopPeriod) - 1;
137
+ loopIteration = Math.max(0, Math.min(lastIteration, isAtBoundary ? nearestIteration : Math.floor(loopsElapsed)));
138
+ }
139
+ const loopOffset = loopPeriod === null ? 0 : loopIteration * loopPeriod;
140
+ const clockFrom = from + loopOffset;
141
+ const effectiveRelativeFrom = clockFrom - trimBefore / playbackRate;
142
+ const relativeFrom = effectiveRelativeFrom / parentPlaybackRate;
143
+ const absoluteFrom = ((_b = parentSequence === null || parentSequence === void 0 ? void 0 : parentSequence.absoluteFrom) !== null && _b !== void 0 ? _b : 0) + relativeFrom;
144
+ // Inside a loop, the local clock ends after `durationInFrames`, except in a final
145
+ // iteration that the parent cuts short.
146
+ const localClockEnd = loopPeriod === null
147
+ ? actualDurationInFrames * playbackRate + trimBefore
148
+ : Math.min(loopPeriod, actualDurationInFrames - loopOffset) *
149
+ playbackRate +
150
+ trimBefore;
106
151
  const sequenceRegistrationEnabled = (0, react_1.useContext)(SequenceManager_js_1.SequenceRegistrationContext);
152
+ const canvasOutlinesEnabled = (0, react_1.useContext)(sequence_outline_js_1.SequenceOutlineContext);
153
+ const env = (0, use_remotion_environment_js_1.useRemotionEnvironment)();
154
+ const shouldDiscoverOutline = env.isStudio || canvasOutlinesEnabled;
155
+ const automaticOutlineRef = (0, react_1.useMemo)(() => shouldDiscoverOutline && layout === 'none' && !passedRefForOutline
156
+ ? sequence_outline_js_1.SequenceOutlineInternals.createRef()
157
+ : null, [shouldDiscoverOutline, layout, passedRefForOutline]);
107
158
  const wrapperRefForOutline = (0, react_1.useRef)(null);
108
159
  const refForOutline = other.layout === 'none'
109
- ? (passedRefForOutline !== null && passedRefForOutline !== void 0 ? passedRefForOutline : null)
160
+ ? (passedRefForOutline !== null && passedRefForOutline !== void 0 ? passedRefForOutline : automaticOutlineRef)
110
161
  : (passedRefForOutline !== null && passedRefForOutline !== void 0 ? passedRefForOutline : wrapperRefForOutline);
111
162
  const premounting = (0, react_1.useMemo)(() => {
112
163
  // || is intentional, ?? would not trigger on `false`
@@ -139,7 +190,7 @@ const RegularSequenceRefForwardingFunction = ({ from = 0, trimBefore = 0, playba
139
190
  ? parentSequenceStart -
140
191
  parentSequence.cumulatedNegativeFrom / parentPlaybackRate
141
192
  : 0;
142
- const firstFrame = Math.max(0, parentFirstFrame, cumulatedFrom + from / parentPlaybackRate);
193
+ const firstFrame = Math.max(0, parentFirstFrame, cumulatedFrom + clockFrom / parentPlaybackRate);
143
194
  const cumulatedNegativeFrom = (currentSequenceStart - firstFrame) * cumulativePlaybackRate;
144
195
  const contextValue = (0, react_1.useMemo)(() => {
145
196
  var _a, _b, _c;
@@ -149,7 +200,7 @@ const RegularSequenceRefForwardingFunction = ({ from = 0, trimBefore = 0, playba
149
200
  cumulatedFrom,
150
201
  relativeFrom,
151
202
  cumulatedNegativeFrom,
152
- durationInFrames: actualDurationInFrames * playbackRate + trimBefore,
203
+ durationInFrames: localClockEnd,
153
204
  parentFrom: (_a = parentSequence === null || parentSequence === void 0 ? void 0 : parentSequence.relativeFrom) !== null && _a !== void 0 ? _a : 0,
154
205
  id,
155
206
  height: (_b = height !== null && height !== void 0 ? height : parentSequence === null || parentSequence === void 0 ? void 0 : parentSequence.height) !== null && _b !== void 0 ? _b : null,
@@ -164,9 +215,7 @@ const RegularSequenceRefForwardingFunction = ({ from = 0, trimBefore = 0, playba
164
215
  absoluteFrom,
165
216
  relativeFrom,
166
217
  cumulativePlaybackRate,
167
- playbackRate,
168
- trimBefore,
169
- actualDurationInFrames,
218
+ localClockEnd,
170
219
  parentSequence,
171
220
  id,
172
221
  height,
@@ -177,11 +226,29 @@ const RegularSequenceRefForwardingFunction = ({ from = 0, trimBefore = 0, playba
177
226
  postmountDisplay,
178
227
  cumulatedNegativeFrom,
179
228
  ]);
229
+ const loopContextValue = (0, react_1.useMemo)(() => {
230
+ if (loopPeriod === null) {
231
+ return null;
232
+ }
233
+ return {
234
+ iteration: loopIteration,
235
+ durationInFrames: contentDurationInFrames,
236
+ };
237
+ }, [contentDurationInFrames, loopIteration, loopPeriod]);
238
+ const resolvedLoopDisplay = (0, react_1.useMemo)(() => {
239
+ if (loopDisplay || loopPeriod === null) {
240
+ return loopDisplay;
241
+ }
242
+ return {
243
+ numberOfTimes: actualDurationInFrames / loopPeriod,
244
+ startOffset: 0,
245
+ durationInFrames: loopPeriod,
246
+ };
247
+ }, [actualDurationInFrames, loopDisplay, loopPeriod]);
180
248
  const timelineClipName = (0, react_1.useMemo)(() => {
181
249
  return name !== null && name !== void 0 ? name : '';
182
250
  }, [name]);
183
251
  const resolvedDocumentationLink = documentationLink !== null && documentationLink !== void 0 ? documentationLink : 'https://www.remotion.dev/docs/sequence';
184
- const env = (0, use_remotion_environment_js_1.useRemotionEnvironment)();
185
252
  const isInsideSeries = (0, react_1.useContext)(is_inside_series_js_1.IsInsideSeriesContext);
186
253
  // Our assumption: Stack doesnt' change. After we symbolicate we assign it a nodePath
187
254
  // and if it changes, it would lead to-remounting of the sequence.
@@ -204,8 +271,8 @@ const RegularSequenceRefForwardingFunction = ({ from = 0, trimBefore = 0, playba
204
271
  ? registeredFrozenFrame === null
205
272
  ? null
206
273
  : mediaFrameAtSequenceZero +
207
- (loopDisplay
208
- ? registeredFrozenFrame % loopDisplay.durationInFrames
274
+ (resolvedLoopDisplay
275
+ ? registeredFrozenFrame % resolvedLoopDisplay.durationInFrames
209
276
  : registeredFrozenFrame) *
210
277
  isMedia.data.playbackRate
211
278
  : null;
@@ -264,7 +331,7 @@ const RegularSequenceRefForwardingFunction = ({ from = 0, trimBefore = 0, playba
264
331
  from,
265
332
  trimBefore: registeredTrimBefore,
266
333
  id,
267
- loopDisplay,
334
+ loopDisplay: resolvedLoopDisplay,
268
335
  parent: (_a = parentSequence === null || parentSequence === void 0 ? void 0 : parentSequence.id) !== null && _a !== void 0 ? _a : null,
269
336
  postmountDisplay: postmountDisplay !== null && postmountDisplay !== void 0 ? postmountDisplay : null,
270
337
  premountDisplay: premountDisplay !== null && premountDisplay !== void 0 ? premountDisplay : null,
@@ -291,7 +358,7 @@ const RegularSequenceRefForwardingFunction = ({ from = 0, trimBefore = 0, playba
291
358
  from,
292
359
  trimBefore: registeredTrimBefore,
293
360
  id,
294
- loopDisplay,
361
+ loopDisplay: resolvedLoopDisplay,
295
362
  parent: (_b = parentSequence === null || parentSequence === void 0 ? void 0 : parentSequence.id) !== null && _b !== void 0 ? _b : null,
296
363
  playbackRate: isMedia.data.playbackRate,
297
364
  postmountDisplay: postmountDisplay !== null && postmountDisplay !== void 0 ? postmountDisplay : null,
@@ -323,7 +390,7 @@ const RegularSequenceRefForwardingFunction = ({ from = 0, trimBefore = 0, playba
323
390
  type: 'sequence',
324
391
  showInTimeline,
325
392
  timelineOrder: null,
326
- loopDisplay,
393
+ loopDisplay: resolvedLoopDisplay,
327
394
  getStack: () => stackRef.current,
328
395
  premountDisplay: premountDisplay !== null && premountDisplay !== void 0 ? premountDisplay : null,
329
396
  postmountDisplay: postmountDisplay !== null && postmountDisplay !== void 0 ? postmountDisplay : null,
@@ -344,7 +411,7 @@ const RegularSequenceRefForwardingFunction = ({ from = 0, trimBefore = 0, playba
344
411
  from,
345
412
  registeredTrimBefore,
346
413
  showInTimeline,
347
- loopDisplay,
414
+ resolvedLoopDisplay,
348
415
  premountDisplay,
349
416
  postmountDisplay,
350
417
  registrationControls,
@@ -367,14 +434,13 @@ const RegularSequenceRefForwardingFunction = ({ from = 0, trimBefore = 0, playba
367
434
  id,
368
435
  });
369
436
  // Use an exclusive end so fractional clocks and frozen subframes remain visible.
370
- const frameInParent = (absoluteFrame - cumulatedFrom) * parentPlaybackRate;
371
- const endThreshold = from + durationInFrames;
437
+ const endThreshold = from + effectiveDurationInFrames;
372
438
  const boundaryTolerance = (0, get_sequence_boundary_tolerance_js_1.getSequenceBoundaryTolerance)({
373
439
  absoluteFrame,
374
440
  cumulatedFrom,
375
441
  from,
376
442
  parentPlaybackRate,
377
- durationInFrames,
443
+ durationInFrames: effectiveDurationInFrames,
378
444
  });
379
445
  const content = frameInParent - from < -boundaryTolerance
380
446
  ? null
@@ -382,6 +448,7 @@ const RegularSequenceRefForwardingFunction = ({ from = 0, trimBefore = 0, playba
382
448
  ? null
383
449
  : children;
384
450
  const frozenContent = content === null || typeof freeze === 'undefined' || freeze === null ? (content) : (jsx_runtime_1.jsx(freeze_js_1.Freeze, { frame: freeze, children: content }));
451
+ const loopedContent = frozenContent === null || loopContextValue === null ? (frozenContent) : (jsx_runtime_1.jsx(loop_context_js_1.LoopContext.Provider, { value: loopContextValue, children: frozenContent }));
385
452
  const styleIfThere = other.layout === 'none' ? undefined : other.style;
386
453
  const cropClipPath = (0, sequence_crop_js_1.getSequenceCropClipPath)({
387
454
  left: resolvedCropLeft,
@@ -416,20 +483,24 @@ const RegularSequenceRefForwardingFunction = ({ from = 0, trimBefore = 0, playba
416
483
  throw new TypeError('It is not supported to pass both a `ref` and `layout="none"` to <Sequence />.');
417
484
  }
418
485
  if (hidden) {
419
- return env.isStudio ? (jsx_runtime_1.jsx(sequence_order_marker_js_1.SequenceOrderMarker, { sequenceId: id, children: null })) : null;
486
+ return shouldDiscoverOutline ? (jsx_runtime_1.jsx(sequence_order_marker_js_1.SequenceOrderMarker, { sequenceId: id, outlineChildrenRef: automaticOutlineRef, children: null })) : null;
420
487
  }
421
- const sequence = (jsx_runtime_1.jsx(SequenceContext_js_1.SequenceContext.Provider, { value: contextValue, children: frozenContent === null ? null : other.layout === 'none' ? (frozenContent) : (jsx_runtime_1.jsx(AbsoluteFillElement_js_1.AbsoluteFillElement, { ref: sequenceRef, style: defaultStyle, className: other.className, children: frozenContent })) }));
422
- return env.isStudio ? (jsx_runtime_1.jsx(sequence_order_marker_js_1.SequenceOrderMarker, { sequenceId: id, children: sequence })) : (sequence);
488
+ const sequence = (jsx_runtime_1.jsx(SequenceContext_js_1.SequenceContext.Provider, { value: contextValue, children: loopedContent === null ? null : other.layout === 'none' ? (loopedContent) : (jsx_runtime_1.jsx(AbsoluteFillElement_js_1.AbsoluteFillElement, { ref: sequenceRef, style: defaultStyle, className: other.className, children: loopedContent })) }));
489
+ return shouldDiscoverOutline ? (jsx_runtime_1.jsx(sequence_order_marker_js_1.SequenceOrderMarker, { sequenceId: id, outlineChildrenRef: automaticOutlineRef, children: sequence })) : (sequence);
423
490
  };
424
491
  const RegularSequence = (0, react_1.forwardRef)(RegularSequenceRefForwardingFunction);
425
492
  const PremountedPostmountedSequenceRefForwardingFunction = (props, ref) => {
426
493
  if (props.layout === 'none') {
427
494
  throw new Error('`<Sequence>` with `premountFor` and `postmountFor` props does not support layout="none"');
428
495
  }
429
- const { style: passedStyle, from = 0, durationInFrames = Infinity, premountFor = 0, postmountFor = 0, styleWhilePremounted, styleWhilePostmounted, ...otherProps } = props;
496
+ const { style: passedStyle, from = 0, durationInFrames, premountFor = 0, postmountFor = 0, styleWhilePremounted, styleWhilePostmounted, ...otherProps } = props;
430
497
  const { freezeFrame, isPremountingOrPostmounting, postmountingActive, premountingActive, premountingStyle, } = (0, use_premounting_js_1.usePremounting)({
431
498
  from,
432
- durationInFrames,
499
+ durationInFrames: (0, resolve_sequence_duration_js_1.resolveSequenceDuration)({
500
+ durationInFrames,
501
+ playbackRate: otherProps.playbackRate,
502
+ loop: otherProps.loop,
503
+ }),
433
504
  premountFor,
434
505
  postmountFor,
435
506
  style: passedStyle !== null && passedStyle !== void 0 ? passedStyle : null,
@@ -437,7 +508,7 @@ const PremountedPostmountedSequenceRefForwardingFunction = (props, ref) => {
437
508
  styleWhilePostmounted: styleWhilePostmounted !== null && styleWhilePostmounted !== void 0 ? styleWhilePostmounted : null,
438
509
  hideWhilePremounted: 'opacity',
439
510
  });
440
- return (jsx_runtime_1.jsx(freeze_js_1.Freeze, { frame: freezeFrame, active: isPremountingOrPostmounting, children: jsx_runtime_1.jsx(SequenceInner, { ref: ref, from: from, durationInFrames: durationInFrames, style: premountingStyle !== null && premountingStyle !== void 0 ? premountingStyle : undefined, _remotionInternalPremountDisplay: premountFor, _remotionInternalPostmountDisplay: postmountFor, _remotionInternalIsPremounting: premountingActive, _remotionInternalIsPostmounting: postmountingActive, ...otherProps }) }));
511
+ return (jsx_runtime_1.jsx(freeze_js_1.Freeze, { frame: freezeFrame, active: isPremountingOrPostmounting, _remotionInternalIsPremounting: premountingActive, children: jsx_runtime_1.jsx(SequenceInner, { ref: ref, from: from, durationInFrames: durationInFrames, style: premountingStyle !== null && premountingStyle !== void 0 ? premountingStyle : undefined, _remotionInternalPremountDisplay: premountFor, _remotionInternalPostmountDisplay: postmountFor, _remotionInternalIsPremounting: premountingActive, _remotionInternalIsPostmounting: postmountingActive, ...otherProps }) }));
441
512
  };
442
513
  const PremountedPostmountedSequence = (0, react_1.forwardRef)(PremountedPostmountedSequenceRefForwardingFunction);
443
514
  const SequenceRefForwardingFunction = (props, ref) => {
@@ -15,6 +15,10 @@ export type SequenceNodePath = Array<string | number>;
15
15
  export declare const SequenceManager: React.Context<SequenceManagerContext>;
16
16
  export declare const SequenceManagerRefContext: React.Context<SequenceManagerRef>;
17
17
  export declare const SequenceRegistrationContext: React.Context<boolean>;
18
+ export declare const DisableSequenceRegistrationContext: React.Context<boolean>;
19
+ export declare const DisableSequenceRegistrationProvider: React.FC<{
20
+ readonly children: React.ReactNode;
21
+ }>;
18
22
  export type VisualModePropStatuses = {
19
23
  propStatuses: PropStatuses;
20
24
  };
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.SequenceManagerProvider = exports.VisualModeSettersContext = exports.VisualModeDragOverridesContext = exports.VisualModePropStatusesRefContext = exports.VisualModePropStatusesContext = exports.makeSequencePropsSubscriptionKey = exports.SequenceRegistrationContext = exports.SequenceManagerRefContext = exports.SequenceManager = void 0;
36
+ exports.SequenceManagerProvider = exports.VisualModeSettersContext = exports.VisualModeDragOverridesContext = exports.VisualModePropStatusesRefContext = exports.VisualModePropStatusesContext = exports.makeSequencePropsSubscriptionKey = exports.DisableSequenceRegistrationProvider = exports.DisableSequenceRegistrationContext = exports.SequenceRegistrationContext = exports.SequenceManagerRefContext = exports.SequenceManager = void 0;
37
37
  const jsx_runtime_1 = require("react/jsx-runtime");
38
38
  const react_1 = __importStar(require("react"));
39
39
  const sequence_order_marker_js_1 = require("./sequence-order-marker.js");
@@ -53,6 +53,11 @@ exports.SequenceManagerRefContext = react_1.default.createContext({
53
53
  current: [],
54
54
  });
55
55
  exports.SequenceRegistrationContext = react_1.default.createContext(false);
56
+ exports.DisableSequenceRegistrationContext = react_1.default.createContext(false);
57
+ const DisableSequenceRegistrationProvider = ({ children }) => {
58
+ return react_1.default.createElement(exports.DisableSequenceRegistrationContext.Provider, { value: true }, children);
59
+ };
60
+ exports.DisableSequenceRegistrationProvider = DisableSequenceRegistrationProvider;
56
61
  const makeSequencePropsSubscriptionKey = (key) => {
57
62
  return `${key.absolutePath}\0${key.nodePath.join('.')}\0${key.sequenceKeys.join('.')}\0${key.effectKeys.map((keys) => keys.join('.')).join('.')}`;
58
63
  };
@@ -20,7 +20,7 @@ export type BufferingState = Readonly<{
20
20
  }>;
21
21
  export type SetTimelineContextValue = {
22
22
  seek: TimelineSeek | null;
23
- setFrame: (u: React.SetStateAction<Record<string, number>>) => void;
23
+ setFrameWithoutSeek: (u: React.SetStateAction<Record<string, number>>) => void;
24
24
  setPlaying: (u: React.SetStateAction<boolean>) => void;
25
25
  setBuffering: (buffering: boolean) => void;
26
26
  subscribePlaying: (listener: (state: PlayingState) => void) => () => void;
@@ -13,7 +13,7 @@ const missingSetTimelineContext = () => {
13
13
  };
14
14
  exports.SetTimelineContext = (0, react_1.createContext)({
15
15
  seek: null,
16
- setFrame: missingSetTimelineContext,
16
+ setFrameWithoutSeek: missingSetTimelineContext,
17
17
  setPlaying: missingSetTimelineContext,
18
18
  setBuffering: missingSetTimelineContext,
19
19
  subscribePlaying: () => () => undefined,
@@ -88,7 +88,7 @@ const TimelineContextProvider = ({ children, frameState }) => {
88
88
  }, [playbackRate]);
89
89
  const setTimelineContextValue = (0, react_1.useMemo)(() => {
90
90
  return {
91
- setFrame,
91
+ setFrameWithoutSeek: setFrame,
92
92
  seek,
93
93
  setPlaying: (updater) => {
94
94
  const current = playingStore.store.getSnapshot().playing;
@@ -199,6 +199,12 @@ export declare const animatedImageSchema: {
199
199
  readonly hiddenFromList: false;
200
200
  readonly keyframable: false;
201
201
  };
202
+ readonly loop: {
203
+ readonly type: "boolean";
204
+ readonly default: false;
205
+ readonly description: "Loop";
206
+ readonly keyframable: false;
207
+ };
202
208
  readonly freeze: {
203
209
  readonly type: "number";
204
210
  readonly default: null;
@@ -3,11 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AnimatedImage = exports.animatedImageSchema = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
+ const react_2 = require("react");
6
7
  const cancel_render_js_1 = require("../cancel-render.js");
7
8
  const use_memoized_effects_js_1 = require("../effects/use-memoized-effects.js");
8
9
  const enable_sequence_stack_traces_js_1 = require("../enable-sequence-stack-traces.js");
9
10
  const freeze_js_1 = require("../freeze.js");
10
11
  const interactivity_schema_js_1 = require("../interactivity-schema.js");
12
+ const resolve_sequence_duration_js_1 = require("../resolve-sequence-duration.js");
11
13
  const Sequence_js_1 = require("../Sequence.js");
12
14
  const use_crop_style_js_1 = require("../use-crop-style.js");
13
15
  const use_current_frame_js_1 = require("../use-current-frame.js");
@@ -18,6 +20,7 @@ const with_interactivity_schema_js_1 = require("../with-interactivity-schema.js"
18
20
  const canvas_1 = require("./canvas");
19
21
  const decode_image_js_1 = require("./decode-image.js");
20
22
  const get_current_time_js_1 = require("./get-current-time.js");
23
+ const get_duration_in_seconds_js_1 = require("./get-duration-in-seconds.js");
21
24
  const request_init_1 = require("./request-init");
22
25
  const resolve_image_source_1 = require("./resolve-image-source");
23
26
  exports.animatedImageSchema = {
@@ -47,26 +50,26 @@ const getCanvasPropsFromSequenceProps = (props) => {
47
50
  }
48
51
  return canvasProps;
49
52
  };
50
- const AnimatedImageContent = (0, react_1.forwardRef)(({ src, width, height, onError, loopBehavior = 'loop', playbackRate = 1, fit = 'fill', requestInit, effects, controls, ...props }, canvasRef) => {
53
+ const AnimatedImageContent = (0, react_2.forwardRef)(({ src, width, height, onError, loopBehavior = 'loop', playbackRate = 1, fit = 'fill', requestInit, effects, controls, ...props }, canvasRef) => {
51
54
  var _a;
52
55
  const resolvedSrc = (0, resolve_image_source_1.resolveAnimatedImageSource)(src);
53
- const [imageDecoder, setImageDecoder] = (0, react_1.useState)(null);
56
+ const [imageDecoder, setImageDecoder] = (0, react_2.useState)(null);
54
57
  const { delayRender, continueRender } = (0, use_delay_render_js_1.useDelayRender)();
55
- const [decodeHandle] = (0, react_1.useState)(() => delayRender(`Rendering <AnimatedImage/> with src="${resolvedSrc}"`));
58
+ const [decodeHandle] = (0, react_2.useState)(() => delayRender(`Rendering <AnimatedImage/> with src="${resolvedSrc}"`));
56
59
  const frame = (0, use_current_frame_js_1.useCurrentFrame)();
57
60
  const { fps } = (0, use_video_config_js_1.useVideoConfig)();
58
61
  const currentTime = (0, get_current_time_js_1.getCurrentTime)({ frame, playbackRate, fps });
59
- const currentTimeRef = (0, react_1.useRef)(currentTime);
62
+ const currentTimeRef = (0, react_2.useRef)(currentTime);
60
63
  currentTimeRef.current = currentTime;
61
64
  const requestInitKey = (0, request_init_1.serializeRequestInit)(requestInit);
62
- const requestInitRef = (0, react_1.useRef)(requestInit);
65
+ const requestInitRef = (0, react_2.useRef)(requestInit);
63
66
  requestInitRef.current = requestInit;
64
- const ref = (0, react_1.useRef)(null);
67
+ const ref = (0, react_2.useRef)(null);
65
68
  const memoizedEffects = (0, use_memoized_effects_js_1.useMemoizedEffects)({
66
69
  effects,
67
70
  overrideId: (_a = controls === null || controls === void 0 ? void 0 : controls.overrideId) !== null && _a !== void 0 ? _a : null,
68
71
  });
69
- (0, react_1.useImperativeHandle)(canvasRef, () => {
72
+ (0, react_2.useImperativeHandle)(canvasRef, () => {
70
73
  var _a;
71
74
  const c = (_a = ref.current) === null || _a === void 0 ? void 0 : _a.getCanvas();
72
75
  if (!c) {
@@ -74,8 +77,8 @@ const AnimatedImageContent = (0, react_1.forwardRef)(({ src, width, height, onEr
74
77
  }
75
78
  return c;
76
79
  }, []);
77
- const [initialLoopBehavior] = (0, react_1.useState)(() => loopBehavior);
78
- (0, react_1.useEffect)(() => {
80
+ const [initialLoopBehavior] = (0, react_2.useState)(() => loopBehavior);
81
+ (0, react_2.useEffect)(() => {
79
82
  const controller = new AbortController();
80
83
  let cancelled = false;
81
84
  let continued = false;
@@ -130,12 +133,12 @@ const AnimatedImageContent = (0, react_1.forwardRef)(({ src, width, height, onEr
130
133
  initialLoopBehavior,
131
134
  continueRender,
132
135
  ]);
133
- (0, react_1.useEffect)(() => {
136
+ (0, react_2.useEffect)(() => {
134
137
  return () => {
135
138
  imageDecoder === null || imageDecoder === void 0 ? void 0 : imageDecoder.close();
136
139
  };
137
140
  }, [imageDecoder]);
138
- (0, react_1.useLayoutEffect)(() => {
141
+ (0, react_2.useLayoutEffect)(() => {
139
142
  if (!imageDecoder) {
140
143
  return;
141
144
  }
@@ -191,14 +194,18 @@ const AnimatedImageContent = (0, react_1.forwardRef)(({ src, width, height, onEr
191
194
  });
192
195
  AnimatedImageContent.displayName = 'AnimatedImageContent';
193
196
  const AnimatedImageInner = ({ src, width, height, onError, fit, playbackRate, loopBehavior, id, className, style, durationInFrames, from, premountFor, postmountFor, styleWhilePremounted, styleWhilePostmounted, cropLeft, cropRight, cropTop, cropBottom, requestInit, effects = [], controls, ref, ...sequenceProps }) => {
194
- const actualRef = (0, react_1.useRef)(null);
197
+ const actualRef = (0, react_2.useRef)(null);
195
198
  const memoizedEffectDefinitions = (0, use_memoized_effects_js_1.useMemoizedEffectDefinitions)(effects);
196
- (0, react_1.useImperativeHandle)(ref, () => {
199
+ (0, react_2.useImperativeHandle)(ref, () => {
197
200
  return actualRef.current;
198
201
  }, []);
199
202
  const { effectivePostmountFor, effectivePremountFor, freezeFrame, isPremountingOrPostmounting, postmountingActive, premountingActive, premountingStyle, } = (0, use_premounting_js_1.usePremounting)({
200
203
  from: from !== null && from !== void 0 ? from : 0,
201
- durationInFrames: durationInFrames !== null && durationInFrames !== void 0 ? durationInFrames : Infinity,
204
+ durationInFrames: (0, resolve_sequence_duration_js_1.resolveSequenceDuration)({
205
+ durationInFrames,
206
+ playbackRate,
207
+ loop: sequenceProps.loop,
208
+ }),
202
209
  premountFor: premountFor !== null && premountFor !== void 0 ? premountFor : null,
203
210
  postmountFor: postmountFor !== null && postmountFor !== void 0 ? postmountFor : null,
204
211
  style: style !== null && style !== void 0 ? style : null,
@@ -228,10 +235,72 @@ const AnimatedImageInner = ({ src, width, height, onError, fit, playbackRate, lo
228
235
  requestInit,
229
236
  ...canvasProps,
230
237
  };
231
- return (jsx_runtime_1.jsx(freeze_js_1.Freeze, { frame: freezeFrame, active: isPremountingOrPostmounting, children: jsx_runtime_1.jsx(Sequence_js_1.Sequence, { layout: "none", from: from !== null && from !== void 0 ? from : 0, playbackRate: playbackRate, durationInFrames: durationInFrames !== null && durationInFrames !== void 0 ? durationInFrames : Infinity, name: "<AnimatedImage>", _remotionInternalDocumentationLink: "https://www.remotion.dev/docs/animatedimage", controls: controls, _remotionInternalEffects: memoizedEffectDefinitions, _remotionInternalPremountDisplay: effectivePremountFor || null, _remotionInternalPostmountDisplay: effectivePostmountFor || null, _remotionInternalIsPremounting: premountingActive, _remotionInternalIsPostmounting: postmountingActive, ...sequenceProps, outlineRef: actualRef, children: jsx_runtime_1.jsx(AnimatedImageContent, { ...animatedImageProps, ref: actualRef, effects: effects, controls: controls }) }) }));
238
+ return (jsx_runtime_1.jsx(freeze_js_1.Freeze, { frame: freezeFrame, active: isPremountingOrPostmounting, _remotionInternalIsPremounting: premountingActive, children: jsx_runtime_1.jsx(Sequence_js_1.Sequence, { layout: "none", from: from !== null && from !== void 0 ? from : 0, playbackRate: playbackRate, durationInFrames: durationInFrames, name: "<AnimatedImage>", _remotionInternalDocumentationLink: "https://www.remotion.dev/docs/animatedimage", controls: controls, _remotionInternalEffects: memoizedEffectDefinitions, _remotionInternalPremountDisplay: effectivePremountFor || null, _remotionInternalPostmountDisplay: effectivePostmountFor || null, _remotionInternalIsPremounting: premountingActive, _remotionInternalIsPostmounting: postmountingActive, ...sequenceProps, children: jsx_runtime_1.jsx(AnimatedImageContent, { ...animatedImageProps, ref: actualRef, effects: effects, controls: controls }) }) }));
239
+ };
240
+ const AnimatedImageWithIntrinsicDuration = (props) => {
241
+ const { fps } = (0, use_video_config_js_1.useVideoConfig)();
242
+ const { delayRender, continueRender } = (0, use_delay_render_js_1.useDelayRender)();
243
+ const { src, requestInit, trimBefore } = props;
244
+ const requestInitRef = (0, react_2.useRef)(requestInit);
245
+ requestInitRef.current = requestInit;
246
+ const onErrorRef = (0, react_2.useRef)(props.onError);
247
+ onErrorRef.current = props.onError;
248
+ const [handle] = (0, react_2.useState)(() => delayRender(`Finding duration of <AnimatedImage src="${src}" />`));
249
+ const [durationInFrames, setDurationInFrames] = (0, react_2.useState)(null);
250
+ const [failed, setFailed] = (0, react_2.useState)(false);
251
+ (0, react_2.useEffect)(() => {
252
+ const controller = new AbortController();
253
+ let cancelled = false;
254
+ (0, get_duration_in_seconds_js_1.getAnimatedImageDurationInSeconds)({
255
+ resolvedSrc: (0, resolve_image_source_1.resolveAnimatedImageSource)(src),
256
+ signal: controller.signal,
257
+ requestInit: requestInitRef.current,
258
+ contentType: null,
259
+ })
260
+ .then((duration) => {
261
+ if (!cancelled) {
262
+ setDurationInFrames(Math.ceil(duration * fps) - (trimBefore !== null && trimBefore !== void 0 ? trimBefore : 0));
263
+ }
264
+ })
265
+ .catch((error) => {
266
+ if (cancelled) {
267
+ return;
268
+ }
269
+ if (onErrorRef.current) {
270
+ onErrorRef.current(error);
271
+ setFailed(true);
272
+ }
273
+ else {
274
+ (0, cancel_render_js_1.cancelRender)(error);
275
+ }
276
+ });
277
+ return () => {
278
+ cancelled = true;
279
+ controller.abort();
280
+ continueRender(handle);
281
+ };
282
+ }, [continueRender, fps, handle, src, trimBefore]);
283
+ (0, react_2.useEffect)(() => {
284
+ if (durationInFrames !== null || failed) {
285
+ continueRender(handle);
286
+ }
287
+ }, [continueRender, durationInFrames, failed, handle]);
288
+ if (durationInFrames === null || failed) {
289
+ return null;
290
+ }
291
+ return jsx_runtime_1.jsx(AnimatedImageInner, { ...props, durationInFrames: durationInFrames });
292
+ };
293
+ const AnimatedImageComponent = (props) => {
294
+ var _a;
295
+ if (props.loop && props.durationInFrames === undefined) {
296
+ const resolvedSrc = (0, resolve_image_source_1.resolveAnimatedImageSource)(props.src);
297
+ const requestInitKey = (0, request_init_1.serializeRequestInit)(props.requestInit);
298
+ return (react_1.createElement(AnimatedImageWithIntrinsicDuration, { ...props, key: `${resolvedSrc}-${requestInitKey}-${(_a = props.trimBefore) !== null && _a !== void 0 ? _a : 0}` }));
299
+ }
300
+ return jsx_runtime_1.jsx(AnimatedImageInner, { ...props });
232
301
  };
233
302
  exports.AnimatedImage = (0, with_interactivity_schema_js_1.withInteractivitySchema)({
234
- Component: AnimatedImageInner,
303
+ Component: AnimatedImageComponent,
235
304
  componentName: '<AnimatedImage>',
236
305
  componentIdentity: 'dev.remotion.remotion.AnimatedImage',
237
306
  schema: exports.animatedImageSchema,
@@ -142,7 +142,6 @@ const AudioForDevelopmentForwardRefFunction = (props, ref) => {
142
142
  loopDisplay: undefined,
143
143
  loopVolumeCurveBehavior: loopVolumeCurveBehavior !== null && loopVolumeCurveBehavior !== void 0 ? loopVolumeCurveBehavior : 'repeat',
144
144
  documentationLink: 'https://www.remotion.dev/docs/html5-audio',
145
- refForOutline: null,
146
145
  muted: isMutedForTimeline,
147
146
  });
148
147
  // putting playback before useVolume
@@ -219,9 +218,9 @@ const AudioForDevelopmentForwardRefFunction = (props, ref) => {
219
218
  };
220
219
  }, [audioRef, src]);
221
220
  if (initialShouldPreMountAudioElements) {
222
- return isStudio ? (jsx_runtime_1.jsx(sequence_order_marker_js_1.SequenceOrderMarker, { sequenceId: timelineId, children: null })) : null;
221
+ return isStudio ? (jsx_runtime_1.jsx(sequence_order_marker_js_1.SequenceOrderMarker, { sequenceId: timelineId, outlineChildrenRef: null, children: null })) : null;
223
222
  }
224
223
  const audio = (jsx_runtime_1.jsx("audio", { ref: audioRef, preload: "metadata", crossOrigin: crossOriginValue, ...propsToPass }));
225
- return isStudio ? (jsx_runtime_1.jsx(sequence_order_marker_js_1.SequenceOrderMarker, { sequenceId: timelineId, children: audio })) : (audio);
224
+ return isStudio ? (jsx_runtime_1.jsx(sequence_order_marker_js_1.SequenceOrderMarker, { sequenceId: timelineId, outlineChildrenRef: null, children: audio })) : (audio);
226
225
  };
227
226
  exports.AudioForPreview = (0, react_2.forwardRef)(AudioForDevelopmentForwardRefFunction);
@@ -16,6 +16,7 @@ const use_video_config_js_1 = require("../use-video-config.js");
16
16
  const v5_flag_js_1 = require("../v5-flag.js");
17
17
  const validate_media_props_js_1 = require("../validate-media-props.js");
18
18
  const validate_start_from_props_js_1 = require("../validate-start-from-props.js");
19
+ const validate_duration_in_frames_js_1 = require("../validation/validate-duration-in-frames.js");
19
20
  const duration_state_js_1 = require("../video/duration-state.js");
20
21
  const AudioForPreview_js_1 = require("./AudioForPreview.js");
21
22
  const AudioForRendering_js_1 = require("./AudioForRendering.js");
@@ -25,7 +26,7 @@ const AudioRefForwardingFunction = (props, ref) => {
25
26
  var _a, _b, _c, _d;
26
27
  const audioTagsContext = (0, react_1.useContext)(shared_audio_tags_js_1.SharedAudioTagsContext);
27
28
  const propsWithFreeze = props;
28
- const { startFrom, endAt, trimBefore, trimAfter, name, _remotionInternalStack, pauseWhenBuffering, showInTimeline, onError: onRemotionError, freeze, ...otherProps } = propsWithFreeze;
29
+ const { startFrom, endAt, trimBefore, trimAfter, durationInFrames, name, _remotionInternalStack, pauseWhenBuffering, showInTimeline, onError: onRemotionError, freeze, ...otherProps } = propsWithFreeze;
29
30
  const { loop, freeze: _freeze, ...propsOtherThanLoop } = propsWithFreeze;
30
31
  const { fps } = (0, use_video_config_js_1.useVideoConfig)();
31
32
  const environment = (0, use_remotion_environment_js_1.useRemotionEnvironment)();
@@ -65,32 +66,43 @@ const AudioRefForwardingFunction = (props, ref) => {
65
66
  }, [setDurations]);
66
67
  const durationFetched = (_a = durations[(0, absolute_src_js_1.getAbsoluteSrc)(preloadedSrc)]) !== null && _a !== void 0 ? _a : durations[(0, absolute_src_js_1.getAbsoluteSrc)(props.src)];
67
68
  (0, validate_start_from_props_js_1.validateMediaTrimProps)({ startFrom, endAt, trimBefore, trimAfter });
69
+ if (durationInFrames !== undefined) {
70
+ (0, validate_duration_in_frames_js_1.validateDurationInFrames)(durationInFrames, {
71
+ component: 'of the <Html5Audio /> component',
72
+ allowFloats: true,
73
+ });
74
+ }
68
75
  const { trimBeforeValue, trimAfterValue } = (0, validate_start_from_props_js_1.resolveTrimProps)({
69
76
  startFrom,
70
77
  endAt,
71
78
  trimBefore,
72
79
  trimAfter,
73
80
  });
81
+ const effectiveTrimAfter = (0, calculate_media_duration_js_1.getMediaTrimAfter)({
82
+ durationInFrames,
83
+ trimAfter: trimAfterValue,
84
+ trimBefore: trimBeforeValue,
85
+ });
74
86
  // An explicit trim end defines the loop before metadata has loaded. Waiting
75
87
  // for metadata would leave the media unmounted when seeking into later loops.
76
- const loopDuration = trimAfterValue !== null && trimAfterValue !== void 0 ? trimAfterValue : (durationFetched === undefined ? undefined : durationFetched * fps);
88
+ const loopDuration = effectiveTrimAfter !== null && effectiveTrimAfter !== void 0 ? effectiveTrimAfter : (durationFetched === undefined ? undefined : durationFetched * fps);
77
89
  if (loop && loopDuration !== undefined) {
78
90
  if (!Number.isFinite(loopDuration)) {
79
91
  return (jsx_runtime_1.jsx(exports.Html5Audio, { ...propsOtherThanLoop, ref: ref, _remotionInternalNativeLoopPassed: true }));
80
92
  }
81
93
  return (jsx_runtime_1.jsx(index_js_1.Loop, { layout: "none", durationInFrames: (0, calculate_media_duration_js_1.calculateMediaDuration)({
82
- trimAfter: trimAfterValue,
94
+ trimAfter: effectiveTrimAfter,
83
95
  mediaDurationInFrames: loopDuration,
84
96
  playbackRate: (_b = props.playbackRate) !== null && _b !== void 0 ? _b : 1,
85
97
  trimBefore: trimBeforeValue,
86
98
  }), children: jsx_runtime_1.jsx(exports.Html5Audio, { ...propsOtherThanLoop, ref: ref, _remotionInternalNativeLoopPassed: true }) }));
87
99
  }
88
100
  if (typeof trimBeforeValue !== 'undefined' ||
89
- typeof trimAfterValue !== 'undefined') {
90
- return (jsx_runtime_1.jsx(use_audio_frame_js_1.Html5MediaTrimContext.Provider, { value: trimBeforeValue !== null && trimBeforeValue !== void 0 ? trimBeforeValue : 0, children: jsx_runtime_1.jsx(Sequence_js_1.Sequence, { layout: "none", from: 0 - (trimBeforeValue !== null && trimBeforeValue !== void 0 ? trimBeforeValue : 0), showInTimeline: false, durationInFrames: trimAfterValue === undefined
101
+ typeof effectiveTrimAfter !== 'undefined') {
102
+ return (jsx_runtime_1.jsx(use_audio_frame_js_1.Html5MediaTrimContext.Provider, { value: trimBeforeValue !== null && trimBeforeValue !== void 0 ? trimBeforeValue : 0, children: jsx_runtime_1.jsx(Sequence_js_1.Sequence, { layout: "none", from: 0 - (trimBeforeValue !== null && trimBeforeValue !== void 0 ? trimBeforeValue : 0), showInTimeline: false, durationInFrames: effectiveTrimAfter === undefined
91
103
  ? undefined
92
104
  : (trimBeforeValue !== null && trimBeforeValue !== void 0 ? trimBeforeValue : 0) +
93
- (trimAfterValue - (trimBeforeValue !== null && trimBeforeValue !== void 0 ? trimBeforeValue : 0)) /
105
+ (effectiveTrimAfter - (trimBeforeValue !== null && trimBeforeValue !== void 0 ? trimBeforeValue : 0)) /
94
106
  ((_c = props.playbackRate) !== null && _c !== void 0 ? _c : 1), name: name, children: jsx_runtime_1.jsx(exports.Html5Audio, { _remotionInternalNeedsDurationCalculation: Boolean(loop), pauseWhenBuffering: shouldPauseWhenBuffering, ...otherProps, ref: ref }) }) }));
95
107
  }
96
108
  (0, validate_media_props_js_1.validateMediaProps)({