@remotion/media 4.0.431 → 4.0.433

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 (68) hide show
  1. package/dist/audio/audio-for-preview.d.ts +5 -2
  2. package/dist/audio/audio-preview-iterator.d.ts +16 -9
  3. package/dist/audio/audio.d.ts +1 -1
  4. package/dist/audio/props.d.ts +1 -0
  5. package/dist/audio-iterator-manager.d.ts +24 -13
  6. package/dist/debug-overlay/preview-overlay.d.ts +24 -14
  7. package/dist/esm/index.mjs +827 -597
  8. package/dist/index.d.ts +32 -2
  9. package/dist/make-iterator-with-priming.d.ts +6 -0
  10. package/dist/media-player.d.ts +12 -7
  11. package/dist/prewarm-iterator-for-looping.d.ts +3 -2
  12. package/dist/set-global-time-anchor.d.ts +11 -0
  13. package/dist/shared-audio-context-for-media-player.d.ts +8 -0
  14. package/dist/use-common-effects.d.ts +32 -0
  15. package/dist/video/props.d.ts +1 -0
  16. package/dist/video/video-for-preview.d.ts +5 -2
  17. package/dist/video/video.d.ts +31 -2
  18. package/package.json +4 -4
  19. package/dist/audio/allow-wait.d.ts +0 -6
  20. package/dist/audio/allow-wait.js +0 -15
  21. package/dist/audio/audio-for-preview.js +0 -304
  22. package/dist/audio/audio-for-rendering.js +0 -194
  23. package/dist/audio/audio-preview-iterator.js +0 -176
  24. package/dist/audio/audio.js +0 -20
  25. package/dist/audio/props.js +0 -1
  26. package/dist/audio-extraction/audio-cache.js +0 -66
  27. package/dist/audio-extraction/audio-iterator.js +0 -132
  28. package/dist/audio-extraction/audio-manager.js +0 -113
  29. package/dist/audio-extraction/extract-audio.js +0 -132
  30. package/dist/audio-iterator-manager.js +0 -228
  31. package/dist/browser-can-use-webgl2.js +0 -13
  32. package/dist/caches.js +0 -61
  33. package/dist/calculate-playbacktime.js +0 -4
  34. package/dist/convert-audiodata/apply-volume.js +0 -17
  35. package/dist/convert-audiodata/combine-audiodata.js +0 -23
  36. package/dist/convert-audiodata/convert-audiodata.js +0 -73
  37. package/dist/convert-audiodata/resample-audiodata.js +0 -94
  38. package/dist/debug-overlay/preview-overlay.js +0 -42
  39. package/dist/extract-frame-and-audio.js +0 -101
  40. package/dist/get-sink.js +0 -15
  41. package/dist/get-time-in-seconds.js +0 -40
  42. package/dist/helpers/round-to-4-digits.js +0 -4
  43. package/dist/index.js +0 -12
  44. package/dist/is-network-error.d.ts +0 -6
  45. package/dist/is-network-error.js +0 -17
  46. package/dist/is-type-of-error.js +0 -20
  47. package/dist/looped-frame.js +0 -10
  48. package/dist/media-player.js +0 -431
  49. package/dist/nonce-manager.js +0 -13
  50. package/dist/prewarm-iterator-for-looping.js +0 -56
  51. package/dist/render-timestamp-range.js +0 -9
  52. package/dist/show-in-timeline.js +0 -31
  53. package/dist/use-media-in-timeline.js +0 -103
  54. package/dist/video/props.js +0 -1
  55. package/dist/video/video-for-preview.js +0 -331
  56. package/dist/video/video-for-rendering.js +0 -263
  57. package/dist/video/video-preview-iterator.js +0 -122
  58. package/dist/video/video.js +0 -35
  59. package/dist/video-extraction/add-broadcast-channel-listener.js +0 -125
  60. package/dist/video-extraction/extract-frame-via-broadcast-channel.js +0 -113
  61. package/dist/video-extraction/extract-frame.js +0 -85
  62. package/dist/video-extraction/get-allocation-size.js +0 -6
  63. package/dist/video-extraction/get-frames-since-keyframe.js +0 -108
  64. package/dist/video-extraction/keyframe-bank.js +0 -159
  65. package/dist/video-extraction/keyframe-manager.js +0 -206
  66. package/dist/video-extraction/remember-actual-matroska-timestamps.js +0 -19
  67. package/dist/video-extraction/rotate-frame.js +0 -34
  68. package/dist/video-iterator-manager.js +0 -109
@@ -37,19 +37,12 @@ var __callDispose = (stack, error, hasError) => {
37
37
  };
38
38
 
39
39
  // src/audio/audio.tsx
40
- import { Internals as Internals15, useRemotionEnvironment as useRemotionEnvironment2 } from "remotion";
40
+ import { Internals as Internals19, useRemotionEnvironment as useRemotionEnvironment2 } from "remotion";
41
41
 
42
42
  // src/audio/audio-for-preview.tsx
43
+ import { useContext as useContext3, useEffect as useEffect2, useMemo as useMemo2, useRef, useState as useState2 } from "react";
43
44
  import {
44
- useContext as useContext2,
45
- useEffect as useEffect2,
46
- useLayoutEffect,
47
- useMemo as useMemo2,
48
- useRef,
49
- useState as useState2
50
- } from "react";
51
- import {
52
- Internals as Internals6,
45
+ Internals as Internals10,
53
46
  Audio as RemotionAudio,
54
47
  useBufferState,
55
48
  useCurrentFrame as useCurrentFrame2,
@@ -109,27 +102,65 @@ var calculateEndTime = ({
109
102
 
110
103
  // src/media-player.ts
111
104
  import { ALL_FORMATS, Input, UrlSource } from "mediabunny";
112
- import { Internals as Internals3 } from "remotion";
105
+ import { Internals as Internals6 } from "remotion";
113
106
 
114
107
  // src/audio-iterator-manager.ts
115
108
  import { AudioBufferSink, InputDisposedError } from "mediabunny";
109
+ import { Internals as Internals4 } from "remotion";
110
+
111
+ // src/audio/audio-preview-iterator.ts
112
+ import { Internals as Internals3 } from "remotion";
116
113
 
117
114
  // src/helpers/round-to-4-digits.ts
118
115
  var roundTo4Digits = (timestamp) => {
119
116
  return Math.round(timestamp * 1000) / 1000;
120
117
  };
121
118
 
119
+ // src/set-global-time-anchor.ts
120
+ import { Internals as Internals2 } from "remotion";
121
+ var ALLOWED_GLOBAL_TIME_ANCHOR_SHIFT = 0.1;
122
+ var setGlobalTimeAnchor = ({
123
+ audioContext,
124
+ audioSyncAnchor,
125
+ absoluteTimeInSeconds,
126
+ globalPlaybackRate,
127
+ debugAudioScheduling,
128
+ logLevel
129
+ }) => {
130
+ const newAnchor = audioContext.currentTime - absoluteTimeInSeconds / globalPlaybackRate;
131
+ const shift = (newAnchor - audioSyncAnchor.value) * globalPlaybackRate;
132
+ if (Math.abs(shift) < ALLOWED_GLOBAL_TIME_ANCHOR_SHIFT) {
133
+ return;
134
+ }
135
+ if (debugAudioScheduling) {
136
+ Internals2.Log.info({ logLevel, tag: "audio-scheduling" }, "Anchor changed from %s to %s with shift %s", audioSyncAnchor.value, newAnchor, shift);
137
+ }
138
+ audioSyncAnchor.value = newAnchor;
139
+ };
140
+
122
141
  // src/audio/audio-preview-iterator.ts
123
- var makeAudioIterator = (startFromSecond, cache) => {
142
+ var makeAudioIterator = (startFromSecond, maximumTimestamp, cache, debugAudioScheduling) => {
124
143
  let destroyed = false;
125
- const iterator = cache.makeIteratorOrUsePrewarmed(startFromSecond);
144
+ const iterator = cache.makeIteratorOrUsePrewarmed(startFromSecond, maximumTimestamp);
126
145
  const queuedAudioNodes = [];
127
146
  const audioChunksForAfterResuming = [];
128
147
  let mostRecentTimestamp = -Infinity;
129
148
  let pendingNext = null;
130
- const cleanupAudioQueue = () => {
149
+ const cleanupAudioQueue = (audioContext) => {
131
150
  for (const node of queuedAudioNodes) {
132
- node.node.stop();
151
+ try {
152
+ const currentlyHearing = audioContext.getOutputTimestamp().contextTime;
153
+ const nodeEndTime = node.scheduledTime + node.buffer.duration / node.playbackRate;
154
+ const isAlreadyPlaying = node.scheduledTime - ALLOWED_GLOBAL_TIME_ANCHOR_SHIFT < audioContext.currentTime;
155
+ const shouldKeep = isAlreadyPlaying;
156
+ if (shouldKeep) {
157
+ continue;
158
+ }
159
+ if (debugAudioScheduling) {
160
+ Internals3.Log.info({ logLevel: "trace", tag: "audio-scheduling" }, `Stopping node ${node.timestamp.toFixed(3)}, currently hearing = ${currentlyHearing.toFixed(3)} currentTime = ${audioContext.currentTime.toFixed(3)} nodeEndTime = ${nodeEndTime.toFixed(3)} scheduledTime = ${node.scheduledTime.toFixed(3)}`);
161
+ }
162
+ node.node.stop();
163
+ } catch {}
133
164
  }
134
165
  queuedAudioNodes.length = 0;
135
166
  };
@@ -238,26 +269,34 @@ var makeAudioIterator = (startFromSecond, cache) => {
238
269
  const removeAndReturnAllQueuedAudioNodes = () => {
239
270
  const nodes = queuedAudioNodes.slice();
240
271
  for (const node of nodes) {
241
- node.node.stop();
272
+ try {
273
+ node.node.stop();
274
+ } catch {}
242
275
  }
243
276
  queuedAudioNodes.length = 0;
244
277
  return nodes;
245
278
  };
246
- const addChunkForAfterResuming = (buffer, timestamp, maxDuration) => {
247
- audioChunksForAfterResuming.push({ buffer, timestamp, maxDuration });
279
+ const addChunkForAfterResuming = (buffer, timestamp) => {
280
+ audioChunksForAfterResuming.push({
281
+ buffer,
282
+ timestamp
283
+ });
248
284
  };
249
285
  const moveQueuedChunksToPauseQueue = () => {
250
286
  const toQueue = removeAndReturnAllQueuedAudioNodes();
251
287
  for (const chunk of toQueue) {
252
- addChunkForAfterResuming(chunk.buffer, chunk.timestamp, chunk.maxDuration);
288
+ addChunkForAfterResuming(chunk.buffer, chunk.timestamp);
289
+ }
290
+ if (debugAudioScheduling && toQueue.length > 0) {
291
+ Internals3.Log.trace({ logLevel: "trace", tag: "audio-scheduling" }, `Moved ${toQueue.length} ${toQueue.length === 1 ? "chunk" : "chunks"} to pause queue (${toQueue[0].timestamp.toFixed(3)}-${toQueue[toQueue.length - 1].timestamp + toQueue[toQueue.length - 1].buffer.duration.toFixed(3)})`);
253
292
  }
254
293
  };
255
294
  const getNumberOfChunksAfterResuming = () => {
256
295
  return audioChunksForAfterResuming.length;
257
296
  };
258
297
  return {
259
- destroy: () => {
260
- cleanupAudioQueue();
298
+ destroy: (audioContext) => {
299
+ cleanupAudioQueue(audioContext);
261
300
  destroyed = true;
262
301
  iterator.return().catch(() => {
263
302
  return;
@@ -274,8 +313,20 @@ var makeAudioIterator = (startFromSecond, cache) => {
274
313
  isDestroyed: () => {
275
314
  return destroyed;
276
315
  },
277
- addQueuedAudioNode: (node, timestamp, buffer, maxDuration) => {
278
- queuedAudioNodes.push({ node, timestamp, buffer, maxDuration });
316
+ addQueuedAudioNode: ({
317
+ node,
318
+ timestamp,
319
+ buffer,
320
+ scheduledTime,
321
+ playbackRate
322
+ }) => {
323
+ queuedAudioNodes.push({
324
+ node,
325
+ timestamp,
326
+ buffer,
327
+ scheduledTime,
328
+ playbackRate
329
+ });
279
330
  },
280
331
  removeQueuedAudioNode: (node) => {
281
332
  const index = queuedAudioNodes.findIndex((n) => n.node === node);
@@ -321,6 +372,122 @@ var isAlreadyQueued = (time, queuedPeriod) => {
321
372
  return time >= queuedPeriod.from && time < queuedPeriod.until;
322
373
  };
323
374
 
375
+ // src/make-iterator-with-priming.ts
376
+ var AUDIO_PRIMING_SECONDS = 0.5;
377
+ var PREDECODE_AHEAD_SECONDS = 8;
378
+ function makePredecodingIterator(inner) {
379
+ const buffer = [];
380
+ let consumerEndTime = 0;
381
+ let innerDone = false;
382
+ let returned = false;
383
+ let fetching = false;
384
+ let waiter = null;
385
+ const prefetch = () => {
386
+ if (fetching || returned || innerDone) {
387
+ return;
388
+ }
389
+ const lastBuffered = buffer.length > 0 ? buffer[buffer.length - 1] : null;
390
+ const bufferedEndTime = lastBuffered ? lastBuffered.timestamp + lastBuffered.duration : consumerEndTime;
391
+ if (bufferedEndTime >= consumerEndTime + PREDECODE_AHEAD_SECONDS) {
392
+ return;
393
+ }
394
+ fetching = true;
395
+ inner.next().then((result) => {
396
+ fetching = false;
397
+ if (returned) {
398
+ return;
399
+ }
400
+ if (result.done) {
401
+ innerDone = true;
402
+ if (waiter) {
403
+ const w = waiter;
404
+ waiter = null;
405
+ w({ value: undefined, done: true });
406
+ }
407
+ return;
408
+ }
409
+ if (waiter) {
410
+ const w = waiter;
411
+ waiter = null;
412
+ const buf = result.value;
413
+ consumerEndTime = buf.timestamp + buf.duration;
414
+ w({ value: buf, done: false });
415
+ prefetch();
416
+ return;
417
+ }
418
+ buffer.push(result.value);
419
+ prefetch();
420
+ }, () => {
421
+ fetching = false;
422
+ innerDone = true;
423
+ if (waiter) {
424
+ const w = waiter;
425
+ waiter = null;
426
+ w({ value: undefined, done: true });
427
+ }
428
+ });
429
+ };
430
+ prefetch();
431
+ const _return = () => {
432
+ returned = true;
433
+ buffer.length = 0;
434
+ if (waiter) {
435
+ const w = waiter;
436
+ waiter = null;
437
+ w({ value: undefined, done: true });
438
+ }
439
+ inner.return(undefined);
440
+ return Promise.resolve({ value: undefined, done: true });
441
+ };
442
+ const iterator = {
443
+ next() {
444
+ if (buffer.length > 0) {
445
+ const buf = buffer.shift();
446
+ consumerEndTime = buf.timestamp + buf.duration;
447
+ prefetch();
448
+ return Promise.resolve({ value: buf, done: false });
449
+ }
450
+ if (innerDone) {
451
+ return Promise.resolve({
452
+ value: undefined,
453
+ done: true
454
+ });
455
+ }
456
+ return new Promise((resolve) => {
457
+ waiter = resolve;
458
+ prefetch();
459
+ });
460
+ },
461
+ return: _return,
462
+ throw(e) {
463
+ returned = true;
464
+ buffer.length = 0;
465
+ return inner.throw(e);
466
+ },
467
+ [Symbol.asyncIterator]() {
468
+ return iterator;
469
+ }
470
+ };
471
+ return iterator;
472
+ }
473
+ async function* makeIteratorWithPrimingInner(audioSink, timeToSeek, maximumTimestamp) {
474
+ const primingStart = Math.max(0, timeToSeek - AUDIO_PRIMING_SECONDS);
475
+ const iterator = audioSink.buffers(primingStart, maximumTimestamp);
476
+ for await (const buffer of iterator) {
477
+ if (buffer.timestamp + buffer.duration <= timeToSeek) {
478
+ continue;
479
+ }
480
+ yield buffer;
481
+ }
482
+ }
483
+ var makeIteratorWithPriming = ({
484
+ audioSink,
485
+ timeToSeek,
486
+ maximumTimestamp
487
+ }) => {
488
+ return makePredecodingIterator(makeIteratorWithPrimingInner(audioSink, timeToSeek, maximumTimestamp));
489
+ };
490
+
324
491
  // src/prewarm-iterator-for-looping.ts
325
492
  var makePrewarmedVideoIteratorCache = (videoSink) => {
326
493
  const prewarmedVideoIterators = new Map;
@@ -350,20 +517,30 @@ var makePrewarmedVideoIteratorCache = (videoSink) => {
350
517
  destroy
351
518
  };
352
519
  };
520
+ var makeKey = (timeToSeek, maximumTimestamp) => {
521
+ return `${timeToSeek}-${maximumTimestamp}`;
522
+ };
353
523
  var makePrewarmedAudioIteratorCache = (audioSink) => {
354
524
  const prewarmedAudioIterators = new Map;
355
- const prewarmIteratorForLooping = ({ timeToSeek }) => {
356
- if (!prewarmedAudioIterators.has(timeToSeek)) {
357
- prewarmedAudioIterators.set(timeToSeek, audioSink.buffers(timeToSeek));
525
+ const prewarmIteratorForLooping = ({
526
+ timeToSeek,
527
+ maximumTimestamp
528
+ }) => {
529
+ if (!prewarmedAudioIterators.has(makeKey(timeToSeek, maximumTimestamp))) {
530
+ prewarmedAudioIterators.set(makeKey(timeToSeek, maximumTimestamp), makeIteratorWithPriming({ audioSink, timeToSeek, maximumTimestamp }));
358
531
  }
359
532
  };
360
- const makeIteratorOrUsePrewarmed = (timeToSeek) => {
361
- const prewarmedIterator = prewarmedAudioIterators.get(timeToSeek);
533
+ const makeIteratorOrUsePrewarmed = (timeToSeek, maximumTimestamp) => {
534
+ const prewarmedIterator = prewarmedAudioIterators.get(makeKey(timeToSeek, maximumTimestamp));
362
535
  if (prewarmedIterator) {
363
- prewarmedAudioIterators.delete(timeToSeek);
536
+ prewarmedAudioIterators.delete(makeKey(timeToSeek, maximumTimestamp));
364
537
  return prewarmedIterator;
365
538
  }
366
- const iterator = audioSink.buffers(timeToSeek);
539
+ const iterator = makeIteratorWithPriming({
540
+ audioSink,
541
+ timeToSeek,
542
+ maximumTimestamp
543
+ });
367
544
  return iterator;
368
545
  };
369
546
  const destroy = () => {
@@ -405,11 +582,14 @@ var audioIteratorManager = ({
405
582
  mediaTimestamp,
406
583
  playbackRate,
407
584
  scheduleAudioNode,
408
- maxDuration
585
+ debugAudioScheduling
409
586
  }) => {
410
587
  if (!audioBufferIterator) {
411
588
  throw new Error("Audio buffer iterator not found");
412
589
  }
590
+ if (sharedAudioContext.state !== "running") {
591
+ throw new Error("Tried to schedule node while audio context is not running");
592
+ }
413
593
  if (muted) {
414
594
  return;
415
595
  }
@@ -417,42 +597,88 @@ var audioIteratorManager = ({
417
597
  node.buffer = buffer;
418
598
  node.playbackRate.value = playbackRate;
419
599
  node.connect(gainNode);
420
- scheduleAudioNode(node, mediaTimestamp, maxDuration);
600
+ const started = scheduleAudioNode(node, mediaTimestamp);
601
+ if (started.type === "not-started") {
602
+ if (debugAudioScheduling) {
603
+ Internals4.Log.info({ logLevel: "trace", tag: "audio-scheduling" }, "not started, disconnected: %s %s", mediaTimestamp.toFixed(3), buffer.duration.toFixed(3));
604
+ }
605
+ node.disconnect();
606
+ return;
607
+ }
421
608
  const iterator = audioBufferIterator;
422
- iterator.addQueuedAudioNode(node, mediaTimestamp, buffer, maxDuration);
609
+ iterator.addQueuedAudioNode({
610
+ node,
611
+ timestamp: mediaTimestamp,
612
+ buffer,
613
+ scheduledTime: started.scheduledTime,
614
+ playbackRate
615
+ });
423
616
  node.onended = () => {
424
617
  setTimeout(() => {
425
618
  iterator.removeQueuedAudioNode(node);
426
619
  }, 30);
427
620
  };
428
621
  };
622
+ const resumeScheduledAudioChunks = ({
623
+ playbackRate,
624
+ scheduleAudioNode,
625
+ debugAudioScheduling
626
+ }) => {
627
+ if (muted) {
628
+ return;
629
+ }
630
+ if (!audioBufferIterator) {
631
+ return;
632
+ }
633
+ for (const chunk of audioBufferIterator.getAndClearAudioChunksForAfterResuming()) {
634
+ scheduleAudioChunk({
635
+ buffer: chunk.buffer,
636
+ mediaTimestamp: chunk.timestamp,
637
+ playbackRate,
638
+ scheduleAudioNode,
639
+ debugAudioScheduling
640
+ });
641
+ }
642
+ };
429
643
  const onAudioChunk = ({
430
644
  getIsPlaying,
431
645
  buffer,
432
646
  playbackRate,
433
- scheduleAudioNode
647
+ scheduleAudioNode,
648
+ debugAudioScheduling
434
649
  }) => {
435
650
  if (muted) {
436
651
  return;
437
652
  }
653
+ const startTime = getStartTime();
438
654
  const endTime = getEndTime();
655
+ if (buffer.timestamp + buffer.duration <= startTime) {
656
+ return;
657
+ }
439
658
  if (buffer.timestamp >= endTime) {
440
659
  return;
441
660
  }
442
- const maxDuration = buffer.timestamp + buffer.duration > endTime ? endTime - buffer.timestamp : null;
443
- if (getIsPlaying()) {
661
+ if (getIsPlaying() && sharedAudioContext.state === "running" && (sharedAudioContext.getOutputTimestamp().contextTime ?? 0) > 0) {
662
+ resumeScheduledAudioChunks({
663
+ playbackRate,
664
+ scheduleAudioNode,
665
+ debugAudioScheduling
666
+ });
444
667
  scheduleAudioChunk({
445
668
  buffer: buffer.buffer,
446
669
  mediaTimestamp: buffer.timestamp,
447
670
  playbackRate,
448
671
  scheduleAudioNode,
449
- maxDuration
672
+ debugAudioScheduling
450
673
  });
451
674
  } else {
452
675
  if (!audioBufferIterator) {
453
676
  throw new Error("Audio buffer iterator not found");
454
677
  }
455
- audioBufferIterator.addChunkForAfterResuming(buffer.buffer, buffer.timestamp, maxDuration);
678
+ if (debugAudioScheduling) {
679
+ Internals4.Log.info({ logLevel: "trace", tag: "audio-scheduling" }, "not ready, added to queue: %s %s", buffer.timestamp.toFixed(3), buffer.duration.toFixed(3));
680
+ }
681
+ audioBufferIterator.addChunkForAfterResuming(buffer.buffer, buffer.timestamp);
456
682
  }
457
683
  drawDebugOverlay();
458
684
  };
@@ -461,17 +687,18 @@ var audioIteratorManager = ({
461
687
  playbackRate,
462
688
  startFromSecond,
463
689
  getIsPlaying,
464
- scheduleAudioNode
690
+ scheduleAudioNode,
691
+ debugAudioScheduling
465
692
  }) => {
466
693
  let __stack = [];
467
694
  try {
468
695
  if (muted) {
469
696
  return;
470
697
  }
471
- audioBufferIterator?.destroy();
698
+ audioBufferIterator?.destroy(sharedAudioContext);
472
699
  const delayHandle = __using(__stack, delayPlaybackHandleIfNotPremounting(), 0);
473
700
  currentDelayHandle = delayHandle;
474
- const iterator = makeAudioIterator(startFromSecond, prewarmedAudioIteratorCache);
701
+ const iterator = makeAudioIterator(startFromSecond, getEndTime(), prewarmedAudioIteratorCache, debugAudioScheduling);
475
702
  audioIteratorsCreated++;
476
703
  audioBufferIterator = iterator;
477
704
  try {
@@ -490,7 +717,8 @@ var audioIteratorManager = ({
490
717
  getIsPlaying,
491
718
  buffer: result.value,
492
719
  playbackRate,
493
- scheduleAudioNode
720
+ scheduleAudioNode,
721
+ debugAudioScheduling
494
722
  });
495
723
  }
496
724
  await iterator.bufferAsFarAsPossible((buffer) => {
@@ -499,7 +727,8 @@ var audioIteratorManager = ({
499
727
  getIsPlaying,
500
728
  buffer,
501
729
  playbackRate,
502
- scheduleAudioNode
730
+ scheduleAudioNode,
731
+ debugAudioScheduling
503
732
  });
504
733
  }
505
734
  }, Math.min(startFromSecond + MAX_BUFFER_AHEAD_SECONDS, getEndTime()));
@@ -526,7 +755,8 @@ var audioIteratorManager = ({
526
755
  nonce,
527
756
  playbackRate,
528
757
  getIsPlaying,
529
- scheduleAudioNode
758
+ scheduleAudioNode,
759
+ debugAudioScheduling
530
760
  }) => {
531
761
  if (muted) {
532
762
  return;
@@ -534,7 +764,8 @@ var audioIteratorManager = ({
534
764
  if (getIsLooping()) {
535
765
  if (getEndTime() - newTime < 1) {
536
766
  prewarmedAudioIteratorCache.prewarmIteratorForLooping({
537
- timeToSeek: getStartTime()
767
+ timeToSeek: getStartTime(),
768
+ maximumTimestamp: getEndTime()
538
769
  });
539
770
  }
540
771
  }
@@ -544,7 +775,8 @@ var audioIteratorManager = ({
544
775
  playbackRate,
545
776
  startFromSecond: newTime,
546
777
  getIsPlaying,
547
- scheduleAudioNode
778
+ scheduleAudioNode,
779
+ debugAudioScheduling
548
780
  });
549
781
  return;
550
782
  }
@@ -557,7 +789,8 @@ var audioIteratorManager = ({
557
789
  getIsPlaying,
558
790
  buffer,
559
791
  playbackRate,
560
- scheduleAudioNode
792
+ scheduleAudioNode,
793
+ debugAudioScheduling
561
794
  });
562
795
  }
563
796
  });
@@ -573,7 +806,8 @@ var audioIteratorManager = ({
573
806
  playbackRate,
574
807
  startFromSecond: newTime,
575
808
  getIsPlaying,
576
- scheduleAudioNode
809
+ scheduleAudioNode,
810
+ debugAudioScheduling
577
811
  });
578
812
  return;
579
813
  }
@@ -585,31 +819,12 @@ var audioIteratorManager = ({
585
819
  getIsPlaying,
586
820
  buffer,
587
821
  playbackRate,
588
- scheduleAudioNode
822
+ scheduleAudioNode,
823
+ debugAudioScheduling
589
824
  });
590
825
  }
591
826
  }, Math.min(newTime + MAX_BUFFER_AHEAD_SECONDS, getEndTime()));
592
827
  };
593
- const resumeScheduledAudioChunks = ({
594
- playbackRate,
595
- scheduleAudioNode
596
- }) => {
597
- if (muted) {
598
- return;
599
- }
600
- if (!audioBufferIterator) {
601
- return;
602
- }
603
- for (const chunk of audioBufferIterator.getAndClearAudioChunksForAfterResuming()) {
604
- scheduleAudioChunk({
605
- buffer: chunk.buffer,
606
- mediaTimestamp: chunk.timestamp,
607
- playbackRate,
608
- scheduleAudioNode,
609
- maxDuration: chunk.maxDuration
610
- });
611
- }
612
- };
613
828
  return {
614
829
  startAudioIterator,
615
830
  resumeScheduledAudioChunks,
@@ -617,7 +832,7 @@ var audioIteratorManager = ({
617
832
  getAudioBufferIterator: () => audioBufferIterator,
618
833
  destroyIterator: () => {
619
834
  prewarmedAudioIteratorCache.destroy();
620
- audioBufferIterator?.destroy();
835
+ audioBufferIterator?.destroy(sharedAudioContext);
621
836
  audioBufferIterator = null;
622
837
  if (currentDelayHandle) {
623
838
  currentDelayHandle.unblock();
@@ -638,16 +853,6 @@ var audioIteratorManager = ({
638
853
  };
639
854
  };
640
855
 
641
- // src/calculate-playbacktime.ts
642
- var calculatePlaybackTime = ({
643
- audioSyncAnchor,
644
- currentTime,
645
- playbackRate
646
- }) => {
647
- const timeSinceAnchor = currentTime - audioSyncAnchor;
648
- return timeSinceAnchor * playbackRate;
649
- };
650
-
651
856
  // src/debug-overlay/preview-overlay.ts
652
857
  var drawPreviewOverlay = ({
653
858
  context,
@@ -659,18 +864,19 @@ var drawPreviewOverlay = ({
659
864
  videoIteratorManager,
660
865
  playbackRate
661
866
  }) => {
867
+ const anchorValue = audioSyncAnchor?.value ?? 0;
662
868
  const lines = [
663
869
  "Debug overlay",
664
870
  `Video iterators created: ${videoIteratorManager?.getVideoIteratorsCreated()}`,
665
871
  `Audio iterators created: ${audioIteratorManager2?.getAudioIteratorsCreated()}`,
666
872
  `Frames rendered: ${videoIteratorManager?.getFramesRendered()}`,
667
873
  `Audio context state: ${audioContextState}`,
668
- audioTime ? `Audio time: ${((audioTime - audioSyncAnchor) * playbackRate).toFixed(3)}s` : null
874
+ audioTime ? `Audio time: ${((audioTime - anchorValue) * playbackRate).toFixed(3)}s` : null
669
875
  ].filter(Boolean);
670
876
  if (audioIteratorManager2) {
671
877
  const queuedPeriod = audioIteratorManager2.getAudioBufferIterator()?.getQueuedPeriod();
672
878
  if (queuedPeriod) {
673
- const aheadText = audioTime ? ` (${(queuedPeriod.until - (audioTime - audioSyncAnchor) * playbackRate).toFixed(3)}s ahead)` : "";
879
+ const aheadText = audioTime ? ` (${(queuedPeriod.until - (audioTime - anchorValue) * playbackRate).toFixed(3)}s ahead)` : "";
674
880
  lines.push(`Audio queued until ${queuedPeriod.until.toFixed(3)}s${aheadText}`);
675
881
  }
676
882
  lines.push(`Playing: ${playing}`);
@@ -720,7 +926,7 @@ var makeNonceManager = () => {
720
926
 
721
927
  // src/video-iterator-manager.ts
722
928
  import { CanvasSink } from "mediabunny";
723
- import { Internals as Internals2 } from "remotion";
929
+ import { Internals as Internals5 } from "remotion";
724
930
 
725
931
  // src/video/video-preview-iterator.ts
726
932
  var createVideoIterator = async (timeToSeek, cache) => {
@@ -890,7 +1096,7 @@ var videoIteratorManager = ({
890
1096
  if (callback) {
891
1097
  callback(frame.canvas);
892
1098
  }
893
- Internals2.Log.trace({ logLevel, tag: "@remotion/media" }, `[MediaPlayer] Drew frame ${frame.timestamp.toFixed(3)}s`);
1099
+ Internals5.Log.trace({ logLevel, tag: "@remotion/media" }, `[MediaPlayer] Drew frame ${frame.timestamp.toFixed(3)}s`);
894
1100
  };
895
1101
  const startVideoIterator = async (timeToSeek, nonce) => {
896
1102
  let __stack = [];
@@ -975,7 +1181,7 @@ class MediaPlayer {
975
1181
  sharedAudioContext;
976
1182
  audioIteratorManager = null;
977
1183
  videoIteratorManager = null;
978
- audioSyncAnchor = 0;
1184
+ sequenceOffset;
979
1185
  playing = false;
980
1186
  loop = false;
981
1187
  fps;
@@ -984,6 +1190,7 @@ class MediaPlayer {
984
1190
  durationInFrames;
985
1191
  totalDuration;
986
1192
  debugOverlay = false;
1193
+ debugAudioScheduling = false;
987
1194
  nonceManager;
988
1195
  onVideoFrameCallback = null;
989
1196
  initializationPromise = null;
@@ -1004,12 +1211,14 @@ class MediaPlayer {
1004
1211
  audioStreamIndex,
1005
1212
  fps,
1006
1213
  debugOverlay,
1214
+ debugAudioScheduling,
1007
1215
  bufferState,
1008
1216
  isPremounting,
1009
1217
  isPostmounting,
1010
1218
  durationInFrames,
1011
1219
  onVideoFrameCallback,
1012
- playing
1220
+ playing,
1221
+ sequenceOffset
1013
1222
  }) {
1014
1223
  this.canvas = canvas ?? null;
1015
1224
  this.src = src;
@@ -1023,6 +1232,7 @@ class MediaPlayer {
1023
1232
  this.audioStreamIndex = audioStreamIndex ?? 0;
1024
1233
  this.fps = fps;
1025
1234
  this.debugOverlay = debugOverlay;
1235
+ this.debugAudioScheduling = debugAudioScheduling;
1026
1236
  this.bufferState = bufferState;
1027
1237
  this.isPremounting = isPremounting;
1028
1238
  this.isPostmounting = isPostmounting;
@@ -1030,6 +1240,7 @@ class MediaPlayer {
1030
1240
  this.nonceManager = makeNonceManager();
1031
1241
  this.onVideoFrameCallback = onVideoFrameCallback;
1032
1242
  this.playing = playing;
1243
+ this.sequenceOffset = sequenceOffset;
1033
1244
  this.input = new Input({
1034
1245
  source: new UrlSource(this.src),
1035
1246
  formats: ALL_FORMATS
@@ -1093,7 +1304,7 @@ class MediaPlayer {
1093
1304
  if (isNetworkError(err)) {
1094
1305
  throw error;
1095
1306
  }
1096
- Internals3.Log.error({ logLevel: this.logLevel, tag: "@remotion/media" }, `[MediaPlayer] Failed to recognize format for ${this.src}`, error);
1307
+ Internals6.Log.error({ logLevel: this.logLevel, tag: "@remotion/media" }, `[MediaPlayer] Failed to recognize format for ${this.src}`, error);
1097
1308
  return { type: "unknown-container-format" };
1098
1309
  }
1099
1310
  const [durationInSeconds, videoTrack, audioTracks] = await Promise.all([
@@ -1134,7 +1345,6 @@ class MediaPlayer {
1134
1345
  if (startTime === null) {
1135
1346
  throw new Error(`should have asserted that the time is not null`);
1136
1347
  }
1137
- this.setAudioPlaybackTime(startTime);
1138
1348
  if (audioTrack && this.sharedAudioContext) {
1139
1349
  const canDecode = await audioTrack.canDecode();
1140
1350
  if (!canDecode) {
@@ -1146,7 +1356,7 @@ class MediaPlayer {
1146
1356
  this.audioIteratorManager = audioIteratorManager({
1147
1357
  audioTrack,
1148
1358
  delayPlaybackHandleIfNotPremounting: this.delayPlaybackHandleIfNotPremounting,
1149
- sharedAudioContext: this.sharedAudioContext,
1359
+ sharedAudioContext: this.sharedAudioContext.audioContext,
1150
1360
  getIsLooping: () => this.loop,
1151
1361
  getEndTime: () => this.getEndTime(),
1152
1362
  getStartTime: () => this.getStartTime(),
@@ -1162,7 +1372,8 @@ class MediaPlayer {
1162
1372
  playbackRate: this.playbackRate * this.globalPlaybackRate,
1163
1373
  startFromSecond: startTime,
1164
1374
  getIsPlaying: () => this.playing,
1165
- scheduleAudioNode: this.scheduleAudioNode
1375
+ scheduleAudioNode: this.scheduleAudioNode,
1376
+ debugAudioScheduling: this.debugAudioScheduling
1166
1377
  }) : Promise.resolve(),
1167
1378
  this.videoIteratorManager ? this.videoIteratorManager.startVideoIterator(startTime, nonce) : Promise.resolve()
1168
1379
  ]);
@@ -1170,16 +1381,16 @@ class MediaPlayer {
1170
1381
  if (this.isDisposalError()) {
1171
1382
  return { type: "disposed" };
1172
1383
  }
1173
- Internals3.Log.error({ logLevel: this.logLevel, tag: "@remotion/media" }, "[MediaPlayer] Failed to start audio and video iterators", error);
1384
+ Internals6.Log.error({ logLevel: this.logLevel, tag: "@remotion/media" }, "[MediaPlayer] Failed to start audio and video iterators", error);
1174
1385
  }
1175
1386
  return { type: "success", durationInSeconds };
1176
1387
  } catch (error) {
1177
1388
  const err = error;
1178
1389
  if (isNetworkError(err)) {
1179
- Internals3.Log.error({ logLevel: this.logLevel, tag: "@remotion/media" }, `[MediaPlayer] Network/CORS error for ${this.src}`, err);
1390
+ Internals6.Log.error({ logLevel: this.logLevel, tag: "@remotion/media" }, `[MediaPlayer] Network/CORS error for ${this.src}`, err);
1180
1391
  return { type: "network-error" };
1181
1392
  }
1182
- Internals3.Log.error({ logLevel: this.logLevel, tag: "@remotion/media" }, "[MediaPlayer] Failed to initialize", error);
1393
+ Internals6.Log.error({ logLevel: this.logLevel, tag: "@remotion/media" }, "[MediaPlayer] Failed to initialize", error);
1183
1394
  throw error;
1184
1395
  }
1185
1396
  } catch (_catch) {
@@ -1205,46 +1416,44 @@ class MediaPlayer {
1205
1416
  if (nonce.isStale()) {
1206
1417
  return;
1207
1418
  }
1208
- const shouldSeekAudio = this.audioIteratorManager && this.sharedAudioContext && this.getAudioPlaybackTime() !== newTime;
1209
- if (shouldSeekAudio) {
1210
- this.setAudioPlaybackTime(newTime);
1211
- }
1212
- await Promise.all([
1213
- this.videoIteratorManager?.seek({
1214
- newTime,
1215
- nonce
1216
- }),
1217
- shouldSeekAudio ? this.audioIteratorManager?.seek({
1218
- newTime,
1219
- nonce,
1220
- playbackRate: this.playbackRate * this.globalPlaybackRate,
1221
- getIsPlaying: () => this.playing,
1222
- scheduleAudioNode: this.scheduleAudioNode
1223
- }) : null
1224
- ]);
1225
- }
1226
- async playAudio(time) {
1227
- const newTime = this.getTrimmedTime(time);
1228
- if (newTime === null) {
1229
- throw new Error(`should have asserted that the time is not null`);
1419
+ const shouldSeekAudio = this.audioIteratorManager && this.getAudioPlaybackTime(this.sharedAudioContext?.audioContext.currentTime ?? 0) !== newTime;
1420
+ try {
1421
+ await Promise.all([
1422
+ this.videoIteratorManager?.seek({
1423
+ newTime,
1424
+ nonce
1425
+ }),
1426
+ shouldSeekAudio ? this.audioIteratorManager?.seek({
1427
+ newTime,
1428
+ nonce,
1429
+ playbackRate: this.playbackRate * this.globalPlaybackRate,
1430
+ getIsPlaying: () => this.playing,
1431
+ scheduleAudioNode: this.scheduleAudioNode,
1432
+ debugAudioScheduling: this.debugAudioScheduling
1433
+ }) : null
1434
+ ]);
1435
+ } catch (error) {
1436
+ if (this.isDisposalError()) {
1437
+ return;
1438
+ }
1439
+ throw error;
1230
1440
  }
1231
- this.setAudioPlaybackTime(newTime);
1232
- if (this.audioIteratorManager) {
1441
+ }
1442
+ playAudio() {
1443
+ if (this.audioIteratorManager && this.sharedAudioContext?.audioContext.state === "running" && (this.sharedAudioContext?.audioContext?.getOutputTimestamp().contextTime ?? 0) > 0) {
1233
1444
  this.audioIteratorManager.resumeScheduledAudioChunks({
1234
1445
  playbackRate: this.playbackRate * this.globalPlaybackRate,
1235
- scheduleAudioNode: this.scheduleAudioNode
1446
+ scheduleAudioNode: this.scheduleAudioNode,
1447
+ debugAudioScheduling: this.debugAudioScheduling
1236
1448
  });
1237
1449
  }
1238
- if (this.sharedAudioContext && this.sharedAudioContext.state === "suspended") {
1239
- await this.sharedAudioContext.resume();
1240
- }
1241
1450
  }
1242
- async play(time) {
1451
+ play() {
1452
+ this.playAudio();
1243
1453
  if (this.playing) {
1244
1454
  return;
1245
1455
  }
1246
1456
  this.playing = true;
1247
- await this.playAudio(time);
1248
1457
  this.drawDebugOverlay();
1249
1458
  }
1250
1459
  delayPlaybackHandleIfNotPremounting = () => {
@@ -1299,7 +1508,6 @@ class MediaPlayer {
1299
1508
  const newMediaTime = this.getTrimmedTime(unloopedTimeInSeconds);
1300
1509
  this.audioIteratorManager?.destroyIterator();
1301
1510
  if (newMediaTime !== null) {
1302
- this.setAudioPlaybackTime(newMediaTime);
1303
1511
  if (!this.playing && this.videoIteratorManager) {
1304
1512
  await this.seekToWithQueue(newMediaTime);
1305
1513
  }
@@ -1320,39 +1528,43 @@ class MediaPlayer {
1320
1528
  setDebugOverlay(debugOverlay) {
1321
1529
  this.debugOverlay = debugOverlay;
1322
1530
  }
1323
- updateAudioTimeAfterPlaybackRateChange(mediaTimeBeforeChange) {
1531
+ setDebugAudioScheduling(debugAudioScheduling) {
1532
+ this.debugAudioScheduling = debugAudioScheduling;
1533
+ }
1534
+ rescheduleAudioChunks() {
1324
1535
  if (!this.audioIteratorManager) {
1325
1536
  return;
1326
1537
  }
1327
1538
  if (!this.sharedAudioContext) {
1328
1539
  return;
1329
1540
  }
1330
- this.setAudioPlaybackTime(mediaTimeBeforeChange);
1331
1541
  const iterator = this.audioIteratorManager.getAudioBufferIterator();
1332
1542
  if (!iterator) {
1333
1543
  return;
1334
1544
  }
1335
1545
  iterator.moveQueuedChunksToPauseQueue();
1336
- if (this.playing) {
1546
+ if (this.playing && this.sharedAudioContext.audioContext.state === "running" && (this.sharedAudioContext.audioContext?.getOutputTimestamp().contextTime ?? 0) > 0) {
1337
1547
  this.audioIteratorManager.resumeScheduledAudioChunks({
1338
1548
  playbackRate: this.playbackRate * this.globalPlaybackRate,
1339
- scheduleAudioNode: this.scheduleAudioNode
1549
+ scheduleAudioNode: this.scheduleAudioNode,
1550
+ debugAudioScheduling: this.debugAudioScheduling
1340
1551
  });
1341
1552
  }
1342
1553
  }
1343
1554
  async setPlaybackRate(rate, unloopedTimeInSeconds) {
1344
1555
  const previousRate = this.playbackRate;
1345
- const mediaTime = this.sharedAudioContext ? this.getAudioPlaybackTime() : 0;
1346
- this.playbackRate = rate;
1347
- this.updateAudioTimeAfterPlaybackRateChange(mediaTime);
1348
1556
  if (previousRate !== rate) {
1557
+ this.playbackRate = rate;
1558
+ this.rescheduleAudioChunks();
1349
1559
  await this.seekTo(unloopedTimeInSeconds);
1350
1560
  }
1351
1561
  }
1352
1562
  setGlobalPlaybackRate(rate) {
1353
- const mediaTime = this.sharedAudioContext ? this.getAudioPlaybackTime() : 0;
1354
- this.globalPlaybackRate = rate;
1355
- this.updateAudioTimeAfterPlaybackRateChange(mediaTime);
1563
+ const previousRate = this.globalPlaybackRate;
1564
+ if (previousRate !== rate) {
1565
+ this.globalPlaybackRate = rate;
1566
+ this.rescheduleAudioChunks();
1567
+ }
1356
1568
  }
1357
1569
  setFps(fps) {
1358
1570
  this.fps = fps;
@@ -1366,6 +1578,9 @@ class MediaPlayer {
1366
1578
  setLoop(loop) {
1367
1579
  this.loop = loop;
1368
1580
  }
1581
+ setSequenceOffset(offset) {
1582
+ this.sequenceOffset = offset;
1583
+ }
1369
1584
  setDurationInFrames(durationInFrames) {
1370
1585
  this.durationInFrames = durationInFrames;
1371
1586
  }
@@ -1380,41 +1595,40 @@ class MediaPlayer {
1380
1595
  this.audioIteratorManager?.destroyIterator();
1381
1596
  this.input.dispose();
1382
1597
  }
1383
- scheduleAudioNode = (node, mediaTimestamp, maxDuration) => {
1384
- const currentTime = this.getAudioPlaybackTime();
1385
- const delayWithoutPlaybackRate = mediaTimestamp - currentTime;
1386
- const delay = delayWithoutPlaybackRate / (this.playbackRate * this.globalPlaybackRate);
1598
+ scheduleAudioNode = (node, mediaTimestamp) => {
1387
1599
  if (!this.sharedAudioContext) {
1388
1600
  throw new Error("Shared audio context not found");
1389
1601
  }
1390
- if (delay >= 0) {
1391
- node.start(this.sharedAudioContext.currentTime + delay, 0, maxDuration ?? undefined);
1392
- } else {
1393
- const offset = -delayWithoutPlaybackRate;
1394
- node.start(this.sharedAudioContext.currentTime, offset, maxDuration !== null ? maxDuration - offset : undefined);
1395
- }
1602
+ const { audioContext } = this.sharedAudioContext;
1603
+ const { currentTime } = audioContext;
1604
+ const globalTime = (currentTime - this.sharedAudioContext.audioSyncAnchor.value) * this.globalPlaybackRate;
1605
+ const timeInSeconds = globalTime - this.sequenceOffset;
1606
+ const localTime = this.getTrimmedTime(timeInSeconds);
1607
+ if (localTime === null) {
1608
+ throw new Error("hmm, should not render!");
1609
+ }
1610
+ const targetTime = (mediaTimestamp - localTime) / (this.playbackRate * this.globalPlaybackRate);
1611
+ return this.sharedAudioContext.scheduleAudioNode({
1612
+ node,
1613
+ mediaTimestamp,
1614
+ targetTime,
1615
+ currentTime,
1616
+ sequenceEndTime: this.getEndTime(),
1617
+ sequenceStartTime: this.getStartTime(),
1618
+ debugAudioScheduling: this.debugAudioScheduling
1619
+ });
1396
1620
  };
1397
- getAudioPlaybackTime() {
1621
+ getAudioPlaybackTime(currentTime) {
1398
1622
  if (!this.sharedAudioContext) {
1399
1623
  throw new Error("Shared audio context not found");
1400
1624
  }
1401
- return calculatePlaybackTime({
1402
- audioSyncAnchor: this.audioSyncAnchor,
1403
- currentTime: this.sharedAudioContext.currentTime,
1404
- playbackRate: this.playbackRate * this.globalPlaybackRate
1405
- });
1406
- }
1407
- setAudioPlaybackTime(time) {
1408
- if (!this.sharedAudioContext) {
1409
- return;
1625
+ const globalTime = (currentTime - this.sharedAudioContext.audioSyncAnchor.value) * this.globalPlaybackRate;
1626
+ const localTime = globalTime - this.sequenceOffset;
1627
+ const trimmedTime = this.getTrimmedTime(localTime);
1628
+ if (trimmedTime !== null) {
1629
+ return trimmedTime;
1410
1630
  }
1411
- const playbackRate = this.playbackRate * this.globalPlaybackRate;
1412
- const newAnchor = this.sharedAudioContext.currentTime - time / playbackRate;
1413
- const shift = Math.abs(newAnchor - this.audioSyncAnchor) * playbackRate;
1414
- if (shift < 0.05) {
1415
- return;
1416
- }
1417
- this.audioSyncAnchor = newAnchor;
1631
+ return localTime * this.playbackRate + (this.trimBefore ?? 0) / this.fps;
1418
1632
  }
1419
1633
  setVideoFrameCallback(callback) {
1420
1634
  this.onVideoFrameCallback = callback;
@@ -1425,9 +1639,9 @@ class MediaPlayer {
1425
1639
  if (this.context && this.canvas) {
1426
1640
  drawPreviewOverlay({
1427
1641
  context: this.context,
1428
- audioTime: this.sharedAudioContext?.currentTime ?? null,
1429
- audioContextState: this.sharedAudioContext?.state ?? null,
1430
- audioSyncAnchor: this.audioSyncAnchor,
1642
+ audioTime: this.sharedAudioContext?.audioContext.currentTime ?? null,
1643
+ audioContextState: this.sharedAudioContext?.audioContext.state ?? null,
1644
+ audioSyncAnchor: this.sharedAudioContext?.audioSyncAnchor ?? null,
1431
1645
  audioIteratorManager: this.audioIteratorManager,
1432
1646
  playing: this.playing,
1433
1647
  videoIteratorManager: this.videoIteratorManager,
@@ -1460,7 +1674,7 @@ var callOnErrorAndResolve = ({
1460
1674
 
1461
1675
  // src/show-in-timeline.ts
1462
1676
  import { useMemo } from "react";
1463
- import { Internals as Internals4, useVideoConfig } from "remotion";
1677
+ import { Internals as Internals7, useVideoConfig } from "remotion";
1464
1678
  var useLoopDisplay = ({
1465
1679
  loop,
1466
1680
  mediaDurationInSeconds,
@@ -1473,7 +1687,7 @@ var useLoopDisplay = ({
1473
1687
  if (!loop || !mediaDurationInSeconds) {
1474
1688
  return;
1475
1689
  }
1476
- const durationInFrames = Internals4.calculateMediaDuration({
1690
+ const durationInFrames = Internals7.calculateMediaDuration({
1477
1691
  mediaDurationInFrames: mediaDurationInSeconds * fps,
1478
1692
  playbackRate,
1479
1693
  trimAfter,
@@ -1497,9 +1711,177 @@ var useLoopDisplay = ({
1497
1711
  return loopDisplay;
1498
1712
  };
1499
1713
 
1714
+ // src/use-common-effects.ts
1715
+ import { useContext, useLayoutEffect } from "react";
1716
+ import { Internals as Internals8 } from "remotion";
1717
+ var useCommonEffects = ({
1718
+ mediaPlayerRef,
1719
+ mediaPlayerReady,
1720
+ currentTimeRef,
1721
+ playing,
1722
+ isPlayerBuffering,
1723
+ frame,
1724
+ trimBefore,
1725
+ trimAfter,
1726
+ effectiveMuted,
1727
+ userPreferredVolume,
1728
+ playbackRate,
1729
+ globalPlaybackRate,
1730
+ fps,
1731
+ sequenceOffset,
1732
+ loop,
1733
+ debugAudioScheduling,
1734
+ durationInFrames,
1735
+ isPremounting,
1736
+ isPostmounting,
1737
+ currentTime,
1738
+ logLevel,
1739
+ sharedAudioContext,
1740
+ label
1741
+ }) => {
1742
+ const absoluteTime = Internals8.useAbsoluteTimelinePosition();
1743
+ const { playing: playingWhilePremounting } = useContext(Internals8.PremountContext);
1744
+ useLayoutEffect(() => {
1745
+ if (sharedAudioContext?.audioContext && sharedAudioContext.audioSyncAnchor) {
1746
+ setGlobalTimeAnchor({
1747
+ audioContext: sharedAudioContext.audioContext,
1748
+ audioSyncAnchor: sharedAudioContext.audioSyncAnchor,
1749
+ absoluteTimeInSeconds: absoluteTime / fps,
1750
+ globalPlaybackRate,
1751
+ debugAudioScheduling,
1752
+ logLevel
1753
+ });
1754
+ }
1755
+ }, [
1756
+ absoluteTime,
1757
+ globalPlaybackRate,
1758
+ sharedAudioContext,
1759
+ fps,
1760
+ debugAudioScheduling,
1761
+ logLevel
1762
+ ]);
1763
+ if (playingWhilePremounting) {
1764
+ mediaPlayerRef.current?.playAudio();
1765
+ }
1766
+ useLayoutEffect(() => {
1767
+ const mediaPlayer = mediaPlayerRef.current;
1768
+ if (!mediaPlayer)
1769
+ return;
1770
+ if (playing && !isPlayerBuffering) {
1771
+ mediaPlayer.play();
1772
+ } else {
1773
+ mediaPlayer.pause();
1774
+ }
1775
+ }, [
1776
+ isPlayerBuffering,
1777
+ playing,
1778
+ logLevel,
1779
+ mediaPlayerReady,
1780
+ frame,
1781
+ mediaPlayerRef
1782
+ ]);
1783
+ useLayoutEffect(() => {
1784
+ const mediaPlayer = mediaPlayerRef.current;
1785
+ if (!mediaPlayer || !mediaPlayerReady) {
1786
+ return;
1787
+ }
1788
+ mediaPlayer.setTrimBefore(trimBefore, currentTimeRef.current);
1789
+ }, [trimBefore, mediaPlayerReady, mediaPlayerRef, currentTimeRef]);
1790
+ useLayoutEffect(() => {
1791
+ const mediaPlayer = mediaPlayerRef.current;
1792
+ if (!mediaPlayer || !mediaPlayerReady) {
1793
+ return;
1794
+ }
1795
+ mediaPlayer.setTrimAfter(trimAfter, currentTimeRef.current);
1796
+ }, [trimAfter, mediaPlayerReady, mediaPlayerRef, currentTimeRef]);
1797
+ useLayoutEffect(() => {
1798
+ const mediaPlayer = mediaPlayerRef.current;
1799
+ if (!mediaPlayer || !mediaPlayerReady)
1800
+ return;
1801
+ mediaPlayer.setMuted(effectiveMuted);
1802
+ }, [effectiveMuted, mediaPlayerReady, mediaPlayerRef]);
1803
+ useLayoutEffect(() => {
1804
+ const mediaPlayer = mediaPlayerRef.current;
1805
+ if (!mediaPlayer || !mediaPlayerReady) {
1806
+ return;
1807
+ }
1808
+ mediaPlayer.setVolume(userPreferredVolume);
1809
+ }, [userPreferredVolume, mediaPlayerReady, mediaPlayerRef]);
1810
+ useLayoutEffect(() => {
1811
+ const mediaPlayer = mediaPlayerRef.current;
1812
+ if (!mediaPlayer || !mediaPlayerReady) {
1813
+ return;
1814
+ }
1815
+ mediaPlayer.setPlaybackRate(playbackRate, currentTimeRef.current);
1816
+ }, [playbackRate, mediaPlayerReady, mediaPlayerRef, currentTimeRef]);
1817
+ useLayoutEffect(() => {
1818
+ const mediaPlayer = mediaPlayerRef.current;
1819
+ if (!mediaPlayer || !mediaPlayerReady) {
1820
+ return;
1821
+ }
1822
+ mediaPlayer.setGlobalPlaybackRate(globalPlaybackRate);
1823
+ }, [globalPlaybackRate, mediaPlayerReady, mediaPlayerRef]);
1824
+ useLayoutEffect(() => {
1825
+ const mediaPlayer = mediaPlayerRef.current;
1826
+ if (!mediaPlayer || !mediaPlayerReady) {
1827
+ return;
1828
+ }
1829
+ mediaPlayer.setLoop(loop);
1830
+ }, [loop, mediaPlayerReady, mediaPlayerRef]);
1831
+ useLayoutEffect(() => {
1832
+ const mediaPlayer = mediaPlayerRef.current;
1833
+ if (!mediaPlayer || !mediaPlayerReady) {
1834
+ return;
1835
+ }
1836
+ mediaPlayer.setDurationInFrames(durationInFrames);
1837
+ }, [durationInFrames, mediaPlayerReady, mediaPlayerRef]);
1838
+ useLayoutEffect(() => {
1839
+ const mediaPlayer = mediaPlayerRef.current;
1840
+ if (!mediaPlayer || !mediaPlayerReady) {
1841
+ return;
1842
+ }
1843
+ mediaPlayer.setIsPremounting(isPremounting);
1844
+ }, [isPremounting, mediaPlayerReady, mediaPlayerRef]);
1845
+ useLayoutEffect(() => {
1846
+ const mediaPlayer = mediaPlayerRef.current;
1847
+ if (!mediaPlayer || !mediaPlayerReady) {
1848
+ return;
1849
+ }
1850
+ mediaPlayer.setIsPostmounting(isPostmounting);
1851
+ }, [isPostmounting, mediaPlayerReady, mediaPlayerRef]);
1852
+ useLayoutEffect(() => {
1853
+ const mediaPlayer = mediaPlayerRef.current;
1854
+ if (!mediaPlayer || !mediaPlayerReady) {
1855
+ return;
1856
+ }
1857
+ mediaPlayer.setFps(fps);
1858
+ }, [fps, mediaPlayerReady, mediaPlayerRef]);
1859
+ useLayoutEffect(() => {
1860
+ const mediaPlayer = mediaPlayerRef.current;
1861
+ if (!mediaPlayer || !mediaPlayerReady) {
1862
+ return;
1863
+ }
1864
+ mediaPlayer.setSequenceOffset(sequenceOffset);
1865
+ }, [sequenceOffset, mediaPlayerReady, mediaPlayerRef]);
1866
+ useLayoutEffect(() => {
1867
+ const mediaPlayer = mediaPlayerRef.current;
1868
+ if (!mediaPlayer || !mediaPlayerReady) {
1869
+ return;
1870
+ }
1871
+ mediaPlayer.setDebugAudioScheduling(debugAudioScheduling);
1872
+ }, [debugAudioScheduling, mediaPlayerReady, mediaPlayerRef]);
1873
+ useLayoutEffect(() => {
1874
+ const mediaPlayer = mediaPlayerRef.current;
1875
+ if (!mediaPlayer || !mediaPlayerReady)
1876
+ return;
1877
+ mediaPlayer.seekTo(currentTime).catch(() => {});
1878
+ Internals8.Log.trace({ logLevel, tag: "@remotion/media" }, `[${label}] Updating target time to ${currentTime.toFixed(3)}s`);
1879
+ }, [currentTime, logLevel, mediaPlayerReady, label, mediaPlayerRef]);
1880
+ };
1881
+
1500
1882
  // src/use-media-in-timeline.ts
1501
- import { useContext, useEffect, useState } from "react";
1502
- import { Internals as Internals5, useCurrentFrame } from "remotion";
1883
+ import { useContext as useContext2, useState, useEffect } from "react";
1884
+ import { Internals as Internals9, useCurrentFrame } from "remotion";
1503
1885
  var useMediaInTimeline = ({
1504
1886
  volume,
1505
1887
  mediaVolume,
@@ -1516,9 +1898,9 @@ var useMediaInTimeline = ({
1516
1898
  trimAfter,
1517
1899
  controls
1518
1900
  }) => {
1519
- const parentSequence = useContext(Internals5.SequenceContext);
1520
- const startsAt = Internals5.useMediaStartsAt();
1521
- const { registerSequence, unregisterSequence } = useContext(Internals5.SequenceManager);
1901
+ const parentSequence = useContext2(Internals9.SequenceContext);
1902
+ const startsAt = Internals9.useMediaStartsAt();
1903
+ const { registerSequence, unregisterSequence } = useContext2(Internals9.SequenceManager);
1522
1904
  const [sequenceId] = useState(() => String(Math.random()));
1523
1905
  const [mediaId] = useState(() => String(Math.random()));
1524
1906
  const frame = useCurrentFrame();
@@ -1530,7 +1912,7 @@ var useMediaInTimeline = ({
1530
1912
  rootId,
1531
1913
  isStudio,
1532
1914
  finalDisplayName
1533
- } = Internals5.useBasicMediaInTimeline({
1915
+ } = Internals9.useBasicMediaInTimeline({
1534
1916
  volume,
1535
1917
  mediaVolume,
1536
1918
  mediaType,
@@ -1560,7 +1942,7 @@ var useMediaInTimeline = ({
1560
1942
  displayName: finalDisplayName,
1561
1943
  rootId,
1562
1944
  showInTimeline: true,
1563
- nonce,
1945
+ nonce: nonce.get(),
1564
1946
  loopDisplay,
1565
1947
  stack,
1566
1948
  from: 0,
@@ -1580,7 +1962,7 @@ var useMediaInTimeline = ({
1580
1962
  rootId,
1581
1963
  volume: volumes,
1582
1964
  showInTimeline: true,
1583
- nonce,
1965
+ nonce: nonce.get(),
1584
1966
  startMediaFrom: 0 - startsAt + (trimBefore ?? 0),
1585
1967
  doesVolumeChange,
1586
1968
  loopDisplay: undefined,
@@ -1640,7 +2022,7 @@ var {
1640
2022
  warnAboutTooHighVolume,
1641
2023
  usePreload,
1642
2024
  SequenceContext
1643
- } = Internals6;
2025
+ } = Internals10;
1644
2026
  var AudioForPreviewAssertedShowing = ({
1645
2027
  src,
1646
2028
  playbackRate,
@@ -1658,6 +2040,7 @@ var AudioForPreviewAssertedShowing = ({
1658
2040
  toneFrequency,
1659
2041
  audioStreamIndex,
1660
2042
  fallbackHtml5AudioProps,
2043
+ debugAudioScheduling,
1661
2044
  onError,
1662
2045
  controls
1663
2046
  }) => {
@@ -1669,9 +2052,9 @@ var AudioForPreviewAssertedShowing = ({
1669
2052
  const [mediaPlayerReady, setMediaPlayerReady] = useState2(false);
1670
2053
  const [shouldFallbackToNativeAudio, setShouldFallbackToNativeAudio] = useState2(false);
1671
2054
  const [playing] = Timeline.usePlayingState();
1672
- const timelineContext = useContext2(Internals6.TimelineContext);
2055
+ const timelineContext = Internals10.useTimelineContext();
1673
2056
  const globalPlaybackRate = timelineContext.playbackRate;
1674
- const sharedAudioContext = useContext2(SharedAudioContext);
2057
+ const sharedAudioContext = useContext3(SharedAudioContext);
1675
2058
  const buffer = useBufferState();
1676
2059
  const [mediaMuted] = useMediaMutedState();
1677
2060
  const [mediaVolume] = useMediaVolumeState();
@@ -1693,9 +2076,10 @@ var AudioForPreviewAssertedShowing = ({
1693
2076
  const currentTimeRef = useRef(currentTime);
1694
2077
  currentTimeRef.current = currentTime;
1695
2078
  const preloadedSrc = usePreload(src);
1696
- const parentSequence = useContext2(SequenceContext);
2079
+ const parentSequence = useContext3(SequenceContext);
1697
2080
  const isPremounting = Boolean(parentSequence?.premounting);
1698
2081
  const isPostmounting = Boolean(parentSequence?.postmounting);
2082
+ const sequenceOffset = ((parentSequence?.cumulatedFrom ?? 0) + (parentSequence?.relativeFrom ?? 0)) / videoConfig.fps;
1699
2083
  const loopDisplay = useLoopDisplay({
1700
2084
  loop,
1701
2085
  mediaDurationInSeconds,
@@ -1719,28 +2103,55 @@ var AudioForPreviewAssertedShowing = ({
1719
2103
  trimBefore,
1720
2104
  controls
1721
2105
  });
1722
- const bufferingContext = useContext2(Internals6.BufferingContextReact);
2106
+ const bufferingContext = useContext3(Internals10.BufferingContextReact);
1723
2107
  if (!bufferingContext) {
1724
2108
  throw new Error("useMediaPlayback must be used inside a <BufferingContext>");
1725
2109
  }
1726
2110
  const effectiveMuted = muted || mediaMuted || userPreferredVolume <= 0;
1727
- const isPlayerBuffering = Internals6.useIsPlayerBuffering(bufferingContext);
2111
+ const isPlayerBuffering = Internals10.useIsPlayerBuffering(bufferingContext);
1728
2112
  const initialPlaying = useRef(playing && !isPlayerBuffering);
1729
2113
  const initialIsPremounting = useRef(isPremounting);
1730
2114
  const initialIsPostmounting = useRef(isPostmounting);
1731
2115
  const initialGlobalPlaybackRate = useRef(globalPlaybackRate);
1732
2116
  const initialPlaybackRate = useRef(playbackRate);
1733
2117
  const initialMuted = useRef(effectiveMuted);
2118
+ const initialSequenceOffset = useRef(sequenceOffset);
2119
+ useCommonEffects({
2120
+ mediaPlayerRef,
2121
+ mediaPlayerReady,
2122
+ currentTimeRef,
2123
+ playing,
2124
+ isPlayerBuffering,
2125
+ frame,
2126
+ trimBefore,
2127
+ trimAfter,
2128
+ effectiveMuted,
2129
+ userPreferredVolume,
2130
+ playbackRate,
2131
+ globalPlaybackRate,
2132
+ fps: videoConfig.fps,
2133
+ sequenceOffset,
2134
+ loop,
2135
+ debugAudioScheduling,
2136
+ durationInFrames: videoConfig.durationInFrames,
2137
+ isPremounting,
2138
+ isPostmounting,
2139
+ currentTime,
2140
+ logLevel,
2141
+ sharedAudioContext,
2142
+ label: "AudioForPreview"
2143
+ });
1734
2144
  useEffect2(() => {
1735
2145
  if (!sharedAudioContext)
1736
2146
  return;
1737
2147
  if (!sharedAudioContext.audioContext)
1738
2148
  return;
2149
+ const { audioContext, audioSyncAnchor, scheduleAudioNode } = sharedAudioContext;
1739
2150
  try {
1740
2151
  const player = new MediaPlayer({
1741
2152
  src: preloadedSrc,
1742
2153
  logLevel,
1743
- sharedAudioContext: sharedAudioContext.audioContext,
2154
+ sharedAudioContext: { audioContext, audioSyncAnchor, scheduleAudioNode },
1744
2155
  loop,
1745
2156
  trimAfter: initialTrimAfterRef.current,
1746
2157
  trimBefore: initialTrimBeforeRef.current,
@@ -1749,13 +2160,15 @@ var AudioForPreviewAssertedShowing = ({
1749
2160
  playbackRate: initialPlaybackRate.current,
1750
2161
  audioStreamIndex: audioStreamIndex ?? 0,
1751
2162
  debugOverlay: false,
2163
+ debugAudioScheduling,
1752
2164
  bufferState: buffer,
1753
2165
  isPostmounting: initialIsPostmounting.current,
1754
2166
  isPremounting: initialIsPremounting.current,
1755
2167
  globalPlaybackRate: initialGlobalPlaybackRate.current,
1756
2168
  durationInFrames: videoConfig.durationInFrames,
1757
2169
  onVideoFrameCallback: null,
1758
- playing: initialPlaying.current
2170
+ playing: initialPlaying.current,
2171
+ sequenceOffset: initialSequenceOffset.current
1759
2172
  });
1760
2173
  mediaPlayerRef.current = player;
1761
2174
  player.initialize(currentTimeRef.current, initialMuted.current).then((result) => {
@@ -1773,7 +2186,7 @@ var AudioForPreviewAssertedShowing = ({
1773
2186
  if (action === "fail") {
1774
2187
  throw errorToUse;
1775
2188
  } else {
1776
- Internals6.Log.warn({ logLevel, tag: "@remotion/media" }, fallbackMessage);
2189
+ Internals10.Log.warn({ logLevel, tag: "@remotion/media" }, fallbackMessage);
1777
2190
  setShouldFallbackToNativeAudio(true);
1778
2191
  }
1779
2192
  };
@@ -1796,7 +2209,7 @@ var AudioForPreviewAssertedShowing = ({
1796
2209
  if (result.type === "success") {
1797
2210
  setMediaPlayerReady(true);
1798
2211
  setMediaDurationInSeconds(result.durationInSeconds);
1799
- Internals6.Log.trace({ logLevel, tag: "@remotion/media" }, `[AudioForPreview] MediaPlayer initialized successfully`);
2212
+ Internals10.Log.trace({ logLevel, tag: "@remotion/media" }, `[AudioForPreview] MediaPlayer initialized successfully`);
1800
2213
  }
1801
2214
  }).catch((error) => {
1802
2215
  const [action, errorToUse] = callOnErrorAndResolve({
@@ -1809,7 +2222,7 @@ var AudioForPreviewAssertedShowing = ({
1809
2222
  if (action === "fail") {
1810
2223
  throw errorToUse;
1811
2224
  } else {
1812
- Internals6.Log.error({ logLevel, tag: "@remotion/media" }, "[AudioForPreview] Failed to initialize MediaPlayer", error);
2225
+ Internals10.Log.error({ logLevel, tag: "@remotion/media" }, "[AudioForPreview] Failed to initialize MediaPlayer", error);
1813
2226
  setShouldFallbackToNativeAudio(true);
1814
2227
  }
1815
2228
  });
@@ -1824,12 +2237,12 @@ var AudioForPreviewAssertedShowing = ({
1824
2237
  if (action === "fail") {
1825
2238
  throw errorToUse;
1826
2239
  }
1827
- Internals6.Log.error({ logLevel, tag: "@remotion/media" }, "[AudioForPreview] MediaPlayer initialization failed", errorToUse);
2240
+ Internals10.Log.error({ logLevel, tag: "@remotion/media" }, "[AudioForPreview] MediaPlayer initialization failed", errorToUse);
1828
2241
  setShouldFallbackToNativeAudio(true);
1829
2242
  }
1830
2243
  return () => {
1831
2244
  if (mediaPlayerRef.current) {
1832
- Internals6.Log.trace({ logLevel, tag: "@remotion/media" }, `[AudioForPreview] Disposing MediaPlayer`);
2245
+ Internals10.Log.trace({ logLevel, tag: "@remotion/media" }, `[AudioForPreview] Disposing MediaPlayer`);
1833
2246
  mediaPlayerRef.current.dispose();
1834
2247
  mediaPlayerRef.current = null;
1835
2248
  }
@@ -1840,108 +2253,15 @@ var AudioForPreviewAssertedShowing = ({
1840
2253
  preloadedSrc,
1841
2254
  logLevel,
1842
2255
  sharedAudioContext,
1843
- currentTimeRef,
1844
2256
  loop,
1845
2257
  videoConfig.fps,
1846
2258
  audioStreamIndex,
1847
2259
  disallowFallbackToHtml5Audio,
2260
+ debugAudioScheduling,
1848
2261
  buffer,
1849
2262
  onError,
1850
2263
  videoConfig.durationInFrames
1851
- ]);
1852
- useLayoutEffect(() => {
1853
- const audioPlayer = mediaPlayerRef.current;
1854
- if (!audioPlayer)
1855
- return;
1856
- if (playing && !isPlayerBuffering) {
1857
- audioPlayer.play(currentTimeRef.current);
1858
- } else {
1859
- audioPlayer.pause();
1860
- }
1861
- }, [isPlayerBuffering, logLevel, playing]);
1862
- useLayoutEffect(() => {
1863
- const mediaPlayer = mediaPlayerRef.current;
1864
- if (!mediaPlayer || !mediaPlayerReady) {
1865
- return;
1866
- }
1867
- mediaPlayer.setTrimBefore(trimBefore, currentTimeRef.current);
1868
- }, [trimBefore, mediaPlayerReady]);
1869
- useLayoutEffect(() => {
1870
- const mediaPlayer = mediaPlayerRef.current;
1871
- if (!mediaPlayer || !mediaPlayerReady) {
1872
- return;
1873
- }
1874
- mediaPlayer.setTrimAfter(trimAfter, currentTimeRef.current);
1875
- }, [trimAfter, mediaPlayerReady]);
1876
- useLayoutEffect(() => {
1877
- const audioPlayer = mediaPlayerRef.current;
1878
- if (!audioPlayer || !mediaPlayerReady)
1879
- return;
1880
- audioPlayer.setMuted(effectiveMuted);
1881
- }, [effectiveMuted, mediaPlayerReady]);
1882
- useEffect2(() => {
1883
- const audioPlayer = mediaPlayerRef.current;
1884
- if (!audioPlayer || !mediaPlayerReady) {
1885
- return;
1886
- }
1887
- audioPlayer.setVolume(userPreferredVolume);
1888
- }, [userPreferredVolume, mediaPlayerReady]);
1889
- useEffect2(() => {
1890
- const audioPlayer = mediaPlayerRef.current;
1891
- if (!audioPlayer || !mediaPlayerReady) {
1892
- return;
1893
- }
1894
- audioPlayer.setPlaybackRate(playbackRate, currentTimeRef.current);
1895
- }, [playbackRate, mediaPlayerReady]);
1896
- useLayoutEffect(() => {
1897
- const audioPlayer = mediaPlayerRef.current;
1898
- if (!audioPlayer || !mediaPlayerReady) {
1899
- return;
1900
- }
1901
- audioPlayer.setGlobalPlaybackRate(globalPlaybackRate);
1902
- }, [globalPlaybackRate, mediaPlayerReady]);
1903
- useLayoutEffect(() => {
1904
- const audioPlayer = mediaPlayerRef.current;
1905
- if (!audioPlayer || !mediaPlayerReady) {
1906
- return;
1907
- }
1908
- audioPlayer.setFps(videoConfig.fps);
1909
- }, [videoConfig.fps, mediaPlayerReady]);
1910
- useLayoutEffect(() => {
1911
- const mediaPlayer = mediaPlayerRef.current;
1912
- if (!mediaPlayer || !mediaPlayerReady) {
1913
- return;
1914
- }
1915
- mediaPlayer.setLoop(loop);
1916
- }, [loop, mediaPlayerReady]);
1917
- useLayoutEffect(() => {
1918
- const mediaPlayer = mediaPlayerRef.current;
1919
- if (!mediaPlayer || !mediaPlayerReady) {
1920
- return;
1921
- }
1922
- mediaPlayer.setDurationInFrames(videoConfig.durationInFrames);
1923
- }, [videoConfig.durationInFrames, mediaPlayerReady]);
1924
- useLayoutEffect(() => {
1925
- const mediaPlayer = mediaPlayerRef.current;
1926
- if (!mediaPlayer || !mediaPlayerReady) {
1927
- return;
1928
- }
1929
- mediaPlayer.setIsPremounting(isPremounting);
1930
- }, [isPremounting, mediaPlayerReady]);
1931
- useLayoutEffect(() => {
1932
- const mediaPlayer = mediaPlayerRef.current;
1933
- if (!mediaPlayer || !mediaPlayerReady) {
1934
- return;
1935
- }
1936
- mediaPlayer.setIsPostmounting(isPostmounting);
1937
- }, [isPostmounting, mediaPlayerReady]);
1938
- useLayoutEffect(() => {
1939
- const audioPlayer = mediaPlayerRef.current;
1940
- if (!audioPlayer || !mediaPlayerReady)
1941
- return;
1942
- audioPlayer.seekTo(currentTime).catch(() => {});
1943
- Internals6.Log.trace({ logLevel, tag: "@remotion/media" }, `[AudioForPreview] Updating target time to ${currentTime.toFixed(3)}s`);
1944
- }, [currentTime, logLevel, mediaPlayerReady]);
2264
+ ]);
1945
2265
  if (shouldFallbackToNativeAudio && !disallowFallbackToHtml5Audio) {
1946
2266
  return /* @__PURE__ */ jsx(RemotionAudio, {
1947
2267
  src,
@@ -1964,72 +2284,37 @@ var AudioForPreviewAssertedShowing = ({
1964
2284
  }
1965
2285
  return null;
1966
2286
  };
1967
- var audioSchema = {
1968
- volume: {
1969
- type: "number",
1970
- min: 0,
1971
- max: 20,
1972
- step: 0.01,
1973
- default: 1,
1974
- description: "Volume"
1975
- },
1976
- playbackRate: {
1977
- type: "number",
1978
- min: 0,
1979
- step: 0.01,
1980
- default: 1,
1981
- description: "Playback Rate"
1982
- },
1983
- trimBefore: { type: "number", min: 0, default: 0 },
1984
- trimAfter: { type: "number", min: 0, default: 0 }
1985
- };
1986
2287
  var AudioForPreview = ({
1987
- loop,
2288
+ loop = false,
1988
2289
  src,
1989
2290
  logLevel,
1990
2291
  muted,
1991
2292
  name,
1992
- volume: volumeProp,
2293
+ volume,
1993
2294
  loopVolumeCurveBehavior,
1994
- playbackRate: playbackRateProp,
1995
- trimAfter: trimAfterProp,
1996
- trimBefore: trimBeforeProp,
2295
+ playbackRate = 1,
2296
+ trimAfter,
2297
+ trimBefore,
1997
2298
  showInTimeline,
1998
2299
  stack,
1999
2300
  disallowFallbackToHtml5Audio,
2000
2301
  toneFrequency,
2001
2302
  audioStreamIndex,
2002
2303
  fallbackHtml5AudioProps,
2003
- onError
2304
+ debugAudioScheduling,
2305
+ onError,
2306
+ controls
2004
2307
  }) => {
2005
- const schemaInput = useMemo2(() => {
2006
- if (typeof volumeProp !== "number") {
2007
- return null;
2008
- }
2009
- return {
2010
- volume: volumeProp,
2011
- playbackRate: playbackRateProp,
2012
- trimBefore: trimBeforeProp,
2013
- trimAfter: trimAfterProp,
2014
- loop: loop ?? false
2015
- };
2016
- }, [volumeProp, playbackRateProp, trimBeforeProp, trimAfterProp, loop]);
2017
- const { controls, values } = Internals6.useSchema(schemaInput ? audioSchema : null, schemaInput);
2018
- const volume = schemaInput !== null ? values.volume : volumeProp;
2019
- const playbackRate = schemaInput !== null ? values.playbackRate : playbackRateProp;
2020
- const trimBefore = schemaInput !== null ? values.trimBefore : trimBeforeProp;
2021
- const trimAfter = schemaInput !== null ? values.trimAfter : trimAfterProp;
2022
- const effectiveLoop = schemaInput !== null ? values.loop : loop ?? false;
2023
2308
  const preloadedSrc = usePreload(src);
2024
- const defaultLogLevel = Internals6.useLogLevel();
2309
+ const defaultLogLevel = Internals10.useLogLevel();
2025
2310
  const frame = useCurrentFrame2();
2026
2311
  const videoConfig = useVideoConfig2();
2027
2312
  const currentTime = frame / videoConfig.fps;
2028
2313
  const showShow = useMemo2(() => {
2029
2314
  return getTimeInSeconds({
2030
2315
  unloopedTimeInSeconds: currentTime,
2031
- playbackRate: playbackRate ?? 1,
2032
- loop: effectiveLoop,
2316
+ playbackRate,
2317
+ loop,
2033
2318
  trimBefore,
2034
2319
  trimAfter,
2035
2320
  mediaDurationInSeconds: Infinity,
@@ -2039,12 +2324,12 @@ var AudioForPreview = ({
2039
2324
  }) !== null;
2040
2325
  }, [
2041
2326
  currentTime,
2042
- effectiveLoop,
2043
2327
  playbackRate,
2044
2328
  src,
2045
2329
  trimAfter,
2046
2330
  trimBefore,
2047
- videoConfig.fps
2331
+ videoConfig.fps,
2332
+ loop
2048
2333
  ]);
2049
2334
  if (!showShow) {
2050
2335
  return null;
@@ -2052,12 +2337,12 @@ var AudioForPreview = ({
2052
2337
  return /* @__PURE__ */ jsx(AudioForPreviewAssertedShowing, {
2053
2338
  audioStreamIndex: audioStreamIndex ?? 0,
2054
2339
  src: preloadedSrc,
2055
- playbackRate: playbackRate ?? 1,
2340
+ playbackRate,
2056
2341
  logLevel: logLevel ?? defaultLogLevel,
2057
2342
  muted: muted ?? false,
2058
2343
  volume: volume ?? 1,
2059
2344
  loopVolumeCurveBehavior: loopVolumeCurveBehavior ?? "repeat",
2060
- loop: effectiveLoop,
2345
+ loop,
2061
2346
  trimAfter,
2062
2347
  trimBefore,
2063
2348
  name,
@@ -2065,6 +2350,7 @@ var AudioForPreview = ({
2065
2350
  stack,
2066
2351
  disallowFallbackToHtml5Audio: disallowFallbackToHtml5Audio ?? false,
2067
2352
  toneFrequency,
2353
+ debugAudioScheduling: debugAudioScheduling ?? false,
2068
2354
  onError,
2069
2355
  fallbackHtml5AudioProps,
2070
2356
  controls
@@ -2072,11 +2358,11 @@ var AudioForPreview = ({
2072
2358
  };
2073
2359
 
2074
2360
  // src/audio/audio-for-rendering.tsx
2075
- import { useContext as useContext3, useLayoutEffect as useLayoutEffect2, useMemo as useMemo3, useState as useState3 } from "react";
2361
+ import { useContext as useContext4, useLayoutEffect as useLayoutEffect2, useMemo as useMemo3, useState as useState3 } from "react";
2076
2362
  import {
2077
2363
  cancelRender as cancelRender2,
2078
2364
  Html5Audio,
2079
- Internals as Internals14,
2365
+ Internals as Internals18,
2080
2366
  random,
2081
2367
  useCurrentFrame as useCurrentFrame3,
2082
2368
  useDelayRender,
@@ -2085,13 +2371,13 @@ import {
2085
2371
 
2086
2372
  // src/caches.ts
2087
2373
  import React2 from "react";
2088
- import { cancelRender, Internals as Internals11 } from "remotion";
2374
+ import { cancelRender, Internals as Internals15 } from "remotion";
2089
2375
 
2090
2376
  // src/audio-extraction/audio-manager.ts
2091
- import { Internals as Internals8 } from "remotion";
2377
+ import { Internals as Internals12 } from "remotion";
2092
2378
 
2093
2379
  // src/audio-extraction/audio-iterator.ts
2094
- import { Internals as Internals7 } from "remotion";
2380
+ import { Internals as Internals11 } from "remotion";
2095
2381
 
2096
2382
  // src/audio-extraction/audio-cache.ts
2097
2383
  var makeAudioCache = () => {
@@ -2162,7 +2448,7 @@ var makeAudioCache = () => {
2162
2448
  };
2163
2449
 
2164
2450
  // src/audio-extraction/audio-iterator.ts
2165
- var extraThreshold = 1.5;
2451
+ var EXTRA_THRESHOLD_IN_SECONDS = 1.5;
2166
2452
  var safetyOutOfOrderThreshold = 0.2;
2167
2453
  var warned = {};
2168
2454
  var warnAboutMatroskaOnce = (src, logLevel) => {
@@ -2170,7 +2456,7 @@ var warnAboutMatroskaOnce = (src, logLevel) => {
2170
2456
  return;
2171
2457
  }
2172
2458
  warned[src] = true;
2173
- Internals7.Log.warn({ logLevel, tag: "@remotion/media" }, `Audio from ${src} will need to be read from the beginning. https://www.remotion.dev/docs/media/support#matroska-limitation`);
2459
+ Internals11.Log.warn({ logLevel, tag: "@remotion/media" }, `Audio from ${src} will need to be read from the beginning. https://www.remotion.dev/docs/media/support#matroska-limitation`);
2174
2460
  };
2175
2461
  var makeAudioIterator2 = ({
2176
2462
  audioSampleSink,
@@ -2180,7 +2466,7 @@ var makeAudioIterator2 = ({
2180
2466
  actualMatroskaTimestamps,
2181
2467
  logLevel
2182
2468
  }) => {
2183
- const sampleIterator = audioSampleSink.samples(isMatroska ? 0 : Math.max(0, startTimestamp - extraThreshold));
2469
+ const sampleIterator = audioSampleSink.samples(isMatroska ? 0 : Math.max(0, startTimestamp - EXTRA_THRESHOLD_IN_SECONDS));
2184
2470
  if (isMatroska) {
2185
2471
  warnAboutMatroskaOnce(src, logLevel);
2186
2472
  }
@@ -2238,7 +2524,7 @@ var makeAudioIterator2 = ({
2238
2524
  if (openTimestamps.length > 0) {
2239
2525
  const first = openTimestamps[0];
2240
2526
  const last = openTimestamps[openTimestamps.length - 1];
2241
- Internals7.Log.verbose({ logLevel, tag: "@remotion/media" }, "Open audio samples for src", src, `${first.toFixed(3)}...${last.toFixed(3)}`);
2527
+ Internals11.Log.verbose({ logLevel, tag: "@remotion/media" }, "Open audio samples for src", src, `${first.toFixed(3)}...${last.toFixed(3)}`);
2242
2528
  }
2243
2529
  };
2244
2530
  const getCacheStats = () => {
@@ -2335,7 +2621,7 @@ var makeAudioManager = () => {
2335
2621
  if (seenKeys.has(key)) {
2336
2622
  iterator.prepareForDeletion();
2337
2623
  iterators.splice(iterators.indexOf(iterator), 1);
2338
- Internals8.Log.verbose({ logLevel, tag: "@remotion/media" }, `Deleted duplicate iterator for ${iterator.src}`);
2624
+ Internals12.Log.verbose({ logLevel, tag: "@remotion/media" }, `Deleted duplicate iterator for ${iterator.src}`);
2339
2625
  }
2340
2626
  seenKeys.add(key);
2341
2627
  }
@@ -2356,7 +2642,7 @@ var makeAudioManager = () => {
2356
2642
  attempts++;
2357
2643
  }
2358
2644
  if ((await getTotalCacheStats()).totalSize > maxCacheSize && attempts >= maxAttempts) {
2359
- Internals8.Log.warn({ logLevel, tag: "@remotion/media" }, `Audio cache: Exceeded max cache size after ${maxAttempts} attempts. Still ${(await getTotalCacheStats()).totalSize} bytes used, target was ${maxCacheSize} bytes.`);
2645
+ Internals12.Log.warn({ logLevel, tag: "@remotion/media" }, `Audio cache: Exceeded max cache size after ${maxAttempts} attempts. Still ${(await getTotalCacheStats()).totalSize} bytes used, target was ${maxCacheSize} bytes.`);
2360
2646
  }
2361
2647
  for (const iterator of iterators) {
2362
2648
  if (iterator.src === src && await iterator.waitForCompletion() && iterator.canSatisfyRequestedTime(timeInSeconds)) {
@@ -2425,7 +2711,7 @@ var makeAudioManager = () => {
2425
2711
  };
2426
2712
 
2427
2713
  // src/video-extraction/keyframe-manager.ts
2428
- import { Internals as Internals10 } from "remotion";
2714
+ import { Internals as Internals14 } from "remotion";
2429
2715
 
2430
2716
  // src/render-timestamp-range.ts
2431
2717
  var renderTimestampRange = (timestamps) => {
@@ -2439,7 +2725,7 @@ var renderTimestampRange = (timestamps) => {
2439
2725
  };
2440
2726
 
2441
2727
  // src/video-extraction/keyframe-bank.ts
2442
- import { Internals as Internals9 } from "remotion";
2728
+ import { Internals as Internals13 } from "remotion";
2443
2729
 
2444
2730
  // src/video-extraction/get-allocation-size.ts
2445
2731
  var getAllocationSize = (sample) => {
@@ -2502,7 +2788,7 @@ var makeKeyframeBank = async ({
2502
2788
  }
2503
2789
  }
2504
2790
  if (deletedTimestamps.length > 0) {
2505
- Internals9.Log.verbose({ logLevel, tag: "@remotion/media" }, `Deleted ${deletedTimestamps.length} frame${deletedTimestamps.length === 1 ? "" : "s"} ${renderTimestampRange(deletedTimestamps)} for src ${src} because it is lower than ${timestampInSeconds}. Remaining: ${renderTimestampRange(frameTimestamps)}`);
2791
+ Internals13.Log.verbose({ logLevel, tag: "@remotion/media" }, `Deleted ${deletedTimestamps.length} frame${deletedTimestamps.length === 1 ? "" : "s"} ${renderTimestampRange(deletedTimestamps)} for src ${src} because it is lower than ${timestampInSeconds}. Remaining: ${renderTimestampRange(frameTimestamps)}`);
2506
2792
  }
2507
2793
  };
2508
2794
  const hasDecodedEnoughForTimestamp = (timestamp) => {
@@ -2525,7 +2811,7 @@ var makeKeyframeBank = async ({
2525
2811
  frameTimestamps.push(frame.timestamp);
2526
2812
  allocationSize += getAllocationSize(frame);
2527
2813
  lastUsed = Date.now();
2528
- Internals9.Log.trace({ logLevel, tag: "@remotion/media" }, `Added frame at ${frame.timestamp}sec to bank`);
2814
+ Internals13.Log.trace({ logLevel, tag: "@remotion/media" }, `Added frame at ${frame.timestamp}sec to bank`);
2529
2815
  };
2530
2816
  const ensureEnoughFramesForTimestamp = async (timestampInSeconds, logLevel, fps) => {
2531
2817
  while (!hasDecodedEnoughForTimestamp(timestampInSeconds)) {
@@ -2580,7 +2866,7 @@ var makeKeyframeBank = async ({
2580
2866
  throw new Error("No first frame found");
2581
2867
  }
2582
2868
  const startTimestampInSeconds = firstFrame.value.timestamp;
2583
- Internals9.Log.verbose({ logLevel: parentLogLevel, tag: "@remotion/media" }, `Creating keyframe bank from ${startTimestampInSeconds}sec`);
2869
+ Internals13.Log.verbose({ logLevel: parentLogLevel, tag: "@remotion/media" }, `Creating keyframe bank from ${startTimestampInSeconds}sec`);
2584
2870
  addFrame(firstFrame.value, parentLogLevel);
2585
2871
  const getRangeOfTimestamps = () => {
2586
2872
  if (frameTimestamps.length === 0) {
@@ -2598,7 +2884,7 @@ var makeKeyframeBank = async ({
2598
2884
  const prepareForDeletion = (logLevel, reason) => {
2599
2885
  const range = getRangeOfTimestamps();
2600
2886
  if (range) {
2601
- Internals9.Log.verbose({ logLevel, tag: "@remotion/media" }, `Preparing for deletion (${reason}) of keyframe bank from ${range?.firstTimestamp}sec to ${range?.lastTimestamp}sec`);
2887
+ Internals13.Log.verbose({ logLevel, tag: "@remotion/media" }, `Preparing for deletion (${reason}) of keyframe bank from ${range?.firstTimestamp}sec to ${range?.lastTimestamp}sec`);
2602
2888
  }
2603
2889
  let framesDeleted = 0;
2604
2890
  for (const frameTimestamp of frameTimestamps.slice()) {
@@ -2671,10 +2957,10 @@ var makeKeyframeManager = () => {
2671
2957
  if (size === 0) {
2672
2958
  continue;
2673
2959
  }
2674
- Internals10.Log.verbose({ logLevel, tag: "@remotion/media" }, `Open frames for src ${src}: ${renderTimestampRange(timestamps)}`);
2960
+ Internals14.Log.verbose({ logLevel, tag: "@remotion/media" }, `Open frames for src ${src}: ${renderTimestampRange(timestamps)}`);
2675
2961
  }
2676
2962
  }
2677
- Internals10.Log.verbose({ logLevel, tag: "@remotion/media" }, `Video cache stats: ${count} open frames, ${totalSize} bytes`);
2963
+ Internals14.Log.verbose({ logLevel, tag: "@remotion/media" }, `Video cache stats: ${count} open frames, ${totalSize} bytes`);
2678
2964
  };
2679
2965
  const getCacheStats = () => {
2680
2966
  let count = 0;
@@ -2728,7 +3014,7 @@ var makeKeyframeManager = () => {
2728
3014
  const { framesDeleted } = mostInThePastBank.prepareForDeletion(logLevel, "deleted oldest keyframe bank to stay under max cache size");
2729
3015
  sources[mostInThePastSrc].splice(mostInThePastIndex, 1);
2730
3016
  if (range) {
2731
- Internals10.Log.verbose({ logLevel, tag: "@remotion/media" }, `Deleted ${framesDeleted} frames for src ${mostInThePastSrc} from ${range?.firstTimestamp}sec to ${range?.lastTimestamp}sec to free up memory.`);
3017
+ Internals14.Log.verbose({ logLevel, tag: "@remotion/media" }, `Deleted ${framesDeleted} frames for src ${mostInThePastSrc} from ${range?.firstTimestamp}sec to ${range?.lastTimestamp}sec to free up memory.`);
2732
3018
  }
2733
3019
  }
2734
3020
  return { finish: false };
@@ -2742,12 +3028,12 @@ var makeKeyframeManager = () => {
2742
3028
  if (finish) {
2743
3029
  break;
2744
3030
  }
2745
- Internals10.Log.verbose({ logLevel, tag: "@remotion/media" }, "Deleted oldest keyframe bank to stay under max cache size", (cacheStats.totalSize / 1024 / 1024).toFixed(1), "out of", (maxCacheSize / 1024 / 1024).toFixed(1));
3031
+ Internals14.Log.verbose({ logLevel, tag: "@remotion/media" }, "Deleted oldest keyframe bank to stay under max cache size", (cacheStats.totalSize / 1024 / 1024).toFixed(1), "out of", (maxCacheSize / 1024 / 1024).toFixed(1));
2746
3032
  cacheStats = getTotalCacheStats();
2747
3033
  attempts++;
2748
3034
  }
2749
3035
  if (cacheStats.totalSize > maxCacheSize && attempts >= maxAttempts) {
2750
- Internals10.Log.warn({ logLevel, tag: "@remotion/media" }, `Exceeded max cache size after ${maxAttempts} attempts. Remaining cache size: ${(cacheStats.totalSize / 1024 / 1024).toFixed(1)} MB, target was ${(maxCacheSize / 1024 / 1024).toFixed(1)} MB.`);
3036
+ Internals14.Log.warn({ logLevel, tag: "@remotion/media" }, `Exceeded max cache size after ${maxAttempts} attempts. Remaining cache size: ${(cacheStats.totalSize / 1024 / 1024).toFixed(1)} MB, target was ${(maxCacheSize / 1024 / 1024).toFixed(1)} MB.`);
2751
3037
  }
2752
3038
  };
2753
3039
  const clearKeyframeBanksBeforeTime = ({
@@ -2768,7 +3054,7 @@ var makeKeyframeManager = () => {
2768
3054
  }
2769
3055
  if (range.lastTimestamp < threshold) {
2770
3056
  bank.prepareForDeletion(logLevel, "cleared before threshold " + threshold);
2771
- Internals10.Log.verbose({ logLevel, tag: "@remotion/media" }, `[Video] Cleared frames for src ${src} from ${range.firstTimestamp}sec to ${range.lastTimestamp}sec`);
3057
+ Internals14.Log.verbose({ logLevel, tag: "@remotion/media" }, `[Video] Cleared frames for src ${src} from ${range.firstTimestamp}sec to ${range.lastTimestamp}sec`);
2772
3058
  const bankIndex = banks.indexOf(bank);
2773
3059
  delete sources[src][bankIndex];
2774
3060
  } else {
@@ -2790,7 +3076,7 @@ var makeKeyframeManager = () => {
2790
3076
  const existingBanks = sources[src] ?? [];
2791
3077
  const existingBank = existingBanks?.find((bank) => bank.canSatisfyTimestamp(timestamp));
2792
3078
  if (!existingBank) {
2793
- Internals10.Log.trace({ logLevel, tag: "@remotion/media" }, `Creating new keyframe bank for src ${src} at timestamp ${timestamp}`);
3079
+ Internals14.Log.trace({ logLevel, tag: "@remotion/media" }, `Creating new keyframe bank for src ${src} at timestamp ${timestamp}`);
2794
3080
  const newKeyframeBank = await makeKeyframeBank({
2795
3081
  videoSampleSink,
2796
3082
  logLevel,
@@ -2801,10 +3087,10 @@ var makeKeyframeManager = () => {
2801
3087
  return newKeyframeBank;
2802
3088
  }
2803
3089
  if (existingBank.canSatisfyTimestamp(timestamp)) {
2804
- Internals10.Log.trace({ logLevel, tag: "@remotion/media" }, `Keyframe bank exists and satisfies timestamp ${timestamp}`);
3090
+ Internals14.Log.trace({ logLevel, tag: "@remotion/media" }, `Keyframe bank exists and satisfies timestamp ${timestamp}`);
2805
3091
  return existingBank;
2806
3092
  }
2807
- Internals10.Log.verbose({ logLevel, tag: "@remotion/media" }, `Keyframe bank exists but frame at time ${timestamp} does not exist anymore.`);
3093
+ Internals14.Log.verbose({ logLevel, tag: "@remotion/media" }, `Keyframe bank exists but frame at time ${timestamp} does not exist anymore.`);
2808
3094
  existingBank.prepareForDeletion(logLevel, "already existed but evicted");
2809
3095
  sources[src] = sources[src].filter((bank) => bank !== existingBank);
2810
3096
  const replacementKeybank = await makeKeyframeBank({
@@ -2895,20 +3181,20 @@ var getUncachedMaxCacheSize = (logLevel) => {
2895
3181
  if (window.remotion_mediaCacheSizeInBytes > 20000 * 1024 * 1024) {
2896
3182
  cancelRender(new Error(`The maximum value for the "mediaCacheSizeInBytes" prop is 20GB (${20000 * 1024 * 1024}), got: ${window.remotion_mediaCacheSizeInBytes}`));
2897
3183
  }
2898
- Internals11.Log.verbose({ logLevel, tag: "@remotion/media" }, `Using cache size set using "mediaCacheSizeInBytes": ${(window.remotion_mediaCacheSizeInBytes / 1024 / 1024).toFixed(1)} MB`);
3184
+ Internals15.Log.verbose({ logLevel, tag: "@remotion/media" }, `Using cache size set using "mediaCacheSizeInBytes": ${(window.remotion_mediaCacheSizeInBytes / 1024 / 1024).toFixed(1)} MB`);
2899
3185
  return window.remotion_mediaCacheSizeInBytes;
2900
3186
  }
2901
3187
  if (typeof window !== "undefined" && window.remotion_initialMemoryAvailable !== undefined && window.remotion_initialMemoryAvailable !== null) {
2902
3188
  const value = window.remotion_initialMemoryAvailable / 2;
2903
3189
  if (value < 500 * 1024 * 1024) {
2904
- Internals11.Log.verbose({ logLevel, tag: "@remotion/media" }, `Using cache size set based on minimum value of 500MB (which is more than half of the available system memory!)`);
3190
+ Internals15.Log.verbose({ logLevel, tag: "@remotion/media" }, `Using cache size set based on minimum value of 500MB (which is more than half of the available system memory!)`);
2905
3191
  return 500 * 1024 * 1024;
2906
3192
  }
2907
3193
  if (value > 20000 * 1024 * 1024) {
2908
- Internals11.Log.verbose({ logLevel, tag: "@remotion/media" }, `Using cache size set based on maximum value of 20GB (which is less than half of the available system memory)`);
3194
+ Internals15.Log.verbose({ logLevel, tag: "@remotion/media" }, `Using cache size set based on maximum value of 20GB (which is less than half of the available system memory)`);
2909
3195
  return 20000 * 1024 * 1024;
2910
3196
  }
2911
- Internals11.Log.verbose({ logLevel, tag: "@remotion/media" }, `Using cache size set based on available memory (50% of available memory): ${(value / 1024 / 1024).toFixed(1)} MB`);
3197
+ Internals15.Log.verbose({ logLevel, tag: "@remotion/media" }, `Using cache size set based on available memory (50% of available memory): ${(value / 1024 / 1024).toFixed(1)} MB`);
2912
3198
  return value;
2913
3199
  }
2914
3200
  return 1000 * 1000 * 1000;
@@ -2922,7 +3208,7 @@ var getMaxVideoCacheSize = (logLevel) => {
2922
3208
  return cachedMaxCacheSize;
2923
3209
  };
2924
3210
  var useMaxMediaCacheSize = (logLevel) => {
2925
- const context = React2.useContext(Internals11.MaxMediaCacheSizeContext);
3211
+ const context = React2.useContext(Internals15.MaxMediaCacheSizeContext);
2926
3212
  if (context === null) {
2927
3213
  return getMaxVideoCacheSize(logLevel);
2928
3214
  }
@@ -3171,7 +3457,7 @@ var combineAudioDataAndClosePrevious = (audioDataArray) => {
3171
3457
  };
3172
3458
 
3173
3459
  // src/get-sink.ts
3174
- import { Internals as Internals12 } from "remotion";
3460
+ import { Internals as Internals16 } from "remotion";
3175
3461
 
3176
3462
  // src/video-extraction/get-frames-since-keyframe.ts
3177
3463
  import {
@@ -3324,7 +3610,7 @@ var sinkPromises = {};
3324
3610
  var getSink = (src, logLevel) => {
3325
3611
  let promise = sinkPromises[src];
3326
3612
  if (!promise) {
3327
- Internals12.Log.verbose({
3613
+ Internals16.Log.verbose({
3328
3614
  logLevel,
3329
3615
  tag: "@remotion/media"
3330
3616
  }, `Sink for ${src} was not found, creating new sink`);
@@ -3464,7 +3750,7 @@ var extractAudio = (params) => {
3464
3750
  };
3465
3751
 
3466
3752
  // src/video-extraction/extract-frame.ts
3467
- import { Internals as Internals13 } from "remotion";
3753
+ import { Internals as Internals17 } from "remotion";
3468
3754
  var extractFrameInternal = async ({
3469
3755
  src,
3470
3756
  timeInSeconds: unloopedTimeInSeconds,
@@ -3545,7 +3831,7 @@ var extractFrameInternal = async ({
3545
3831
  durationInSeconds: await sink.getDuration()
3546
3832
  };
3547
3833
  } catch (err) {
3548
- Internals13.Log.info({ logLevel, tag: "@remotion/media" }, `Error decoding ${src} at time ${timeInSeconds}: ${err}`, err);
3834
+ Internals17.Log.info({ logLevel, tag: "@remotion/media" }, `Error decoding ${src} at time ${timeInSeconds}: ${err}`, err);
3549
3835
  return { type: "cannot-decode", durationInSeconds: mediaDurationInSeconds };
3550
3836
  }
3551
3837
  };
@@ -3941,13 +4227,13 @@ var AudioForRendering = ({
3941
4227
  trimBefore,
3942
4228
  onError
3943
4229
  }) => {
3944
- const defaultLogLevel = Internals14.useLogLevel();
4230
+ const defaultLogLevel = Internals18.useLogLevel();
3945
4231
  const logLevel = overriddenLogLevel ?? defaultLogLevel;
3946
4232
  const frame = useCurrentFrame3();
3947
- const absoluteFrame = Internals14.useTimelinePosition();
3948
- const videoConfig = Internals14.useUnsafeVideoConfig();
3949
- const { registerRenderAsset, unregisterRenderAsset } = useContext3(Internals14.RenderAssetManager);
3950
- const startsAt = Internals14.useMediaStartsAt();
4233
+ const absoluteFrame = Internals18.useTimelinePosition();
4234
+ const videoConfig = Internals18.useUnsafeVideoConfig();
4235
+ const { registerRenderAsset, unregisterRenderAsset } = useContext4(Internals18.RenderAssetManager);
4236
+ const startsAt = Internals18.useMediaStartsAt();
3951
4237
  const environment = useRemotionEnvironment();
3952
4238
  if (!videoConfig) {
3953
4239
  throw new Error("No video config found");
@@ -3958,7 +4244,7 @@ var AudioForRendering = ({
3958
4244
  const { fps } = videoConfig;
3959
4245
  const { delayRender, continueRender } = useDelayRender();
3960
4246
  const [replaceWithHtml5Audio, setReplaceWithHtml5Audio] = useState3(false);
3961
- const sequenceContext = useContext3(Internals14.SequenceContext);
4247
+ const sequenceContext = useContext4(Internals18.SequenceContext);
3962
4248
  const id = useMemo3(() => `media-audio-${random(src)}-${sequenceContext?.cumulatedFrom}-${sequenceContext?.relativeFrom}-${sequenceContext?.durationInFrames}`, [
3963
4249
  src,
3964
4250
  sequenceContext?.cumulatedFrom,
@@ -3966,7 +4252,7 @@ var AudioForRendering = ({
3966
4252
  sequenceContext?.durationInFrames
3967
4253
  ]);
3968
4254
  const maxCacheSize = useMaxMediaCacheSize(logLevel);
3969
- const audioEnabled = Internals14.useAudioEnabled();
4255
+ const audioEnabled = Internals18.useAudioEnabled();
3970
4256
  useLayoutEffect2(() => {
3971
4257
  const timestamp = frame / fps;
3972
4258
  const durationInSeconds = 1 / fps;
@@ -4016,7 +4302,7 @@ var AudioForRendering = ({
4016
4302
  if (action === "fail") {
4017
4303
  cancelRender2(errorToUse);
4018
4304
  }
4019
- Internals14.Log.warn({ logLevel, tag: "@remotion/media" }, fallbackMessage);
4305
+ Internals18.Log.warn({ logLevel, tag: "@remotion/media" }, fallbackMessage);
4020
4306
  setReplaceWithHtml5Audio(true);
4021
4307
  };
4022
4308
  if (result.type === "unknown-container-format") {
@@ -4043,12 +4329,12 @@ var AudioForRendering = ({
4043
4329
  frame,
4044
4330
  startsAt
4045
4331
  });
4046
- const volume = Internals14.evaluateVolume({
4332
+ const volume = Internals18.evaluateVolume({
4047
4333
  volume: volumeProp,
4048
4334
  frame: volumePropsFrame,
4049
4335
  mediaVolume: 1
4050
4336
  });
4051
- Internals14.warnAboutTooHighVolume(volume);
4337
+ Internals18.warnAboutTooHighVolume(volume);
4052
4338
  if (audio && volume > 0) {
4053
4339
  applyVolume(audio.data, volume);
4054
4340
  registerRenderAsset({
@@ -4124,9 +4410,27 @@ var AudioForRendering = ({
4124
4410
 
4125
4411
  // src/audio/audio.tsx
4126
4412
  import { jsx as jsx3 } from "react/jsx-runtime";
4127
- var { validateMediaProps } = Internals15;
4128
- var Audio = (props) => {
4129
- const { name, stack, showInTimeline, ...otherProps } = props;
4413
+ var { validateMediaProps } = Internals19;
4414
+ var audioSchema = {
4415
+ volume: {
4416
+ type: "number",
4417
+ min: 0,
4418
+ max: 20,
4419
+ step: 0.01,
4420
+ default: 1,
4421
+ description: "Volume"
4422
+ },
4423
+ playbackRate: {
4424
+ type: "number",
4425
+ min: 0.1,
4426
+ step: 0.01,
4427
+ default: 1,
4428
+ description: "Playback Rate"
4429
+ },
4430
+ loop: { type: "boolean", default: false, description: "Loop" }
4431
+ };
4432
+ var AudioInner = (props) => {
4433
+ const { name, stack, showInTimeline, controls, ...otherProps } = props;
4130
4434
  const environment = useRemotionEnvironment2();
4131
4435
  if (typeof props.src !== "string") {
4132
4436
  throw new TypeError(`The \`<Audio>\` tag requires a string for \`src\`, but got ${JSON.stringify(props.src)} instead.`);
@@ -4140,17 +4444,19 @@ var Audio = (props) => {
4140
4444
  return /* @__PURE__ */ jsx3(AudioForPreview, {
4141
4445
  name,
4142
4446
  ...otherProps,
4143
- stack: stack ?? null
4447
+ stack: stack ?? null,
4448
+ controls
4144
4449
  });
4145
4450
  };
4146
- Internals15.addSequenceStackTraces(Audio);
4451
+ var Audio = Internals19.wrapInSchema(AudioInner, audioSchema);
4452
+ Internals19.addSequenceStackTraces(Audio);
4147
4453
 
4148
4454
  // src/video/video.tsx
4149
- import { Internals as Internals18, useRemotionEnvironment as useRemotionEnvironment4 } from "remotion";
4455
+ import { Internals as Internals22, useRemotionEnvironment as useRemotionEnvironment4 } from "remotion";
4150
4456
 
4151
4457
  // src/video/video-for-preview.tsx
4152
4458
  import {
4153
- useContext as useContext4,
4459
+ useContext as useContext5,
4154
4460
  useEffect as useEffect3,
4155
4461
  useLayoutEffect as useLayoutEffect3,
4156
4462
  useMemo as useMemo4,
@@ -4159,7 +4465,7 @@ import {
4159
4465
  } from "react";
4160
4466
  import {
4161
4467
  Html5Video,
4162
- Internals as Internals16,
4468
+ Internals as Internals20,
4163
4469
  useBufferState as useBufferState2,
4164
4470
  useCurrentFrame as useCurrentFrame4,
4165
4471
  useVideoConfig as useVideoConfig3
@@ -4177,7 +4483,7 @@ var {
4177
4483
  usePreload: usePreload2,
4178
4484
  SequenceContext: SequenceContext2,
4179
4485
  SequenceVisibilityToggleContext
4180
- } = Internals16;
4486
+ } = Internals20;
4181
4487
  var VideoForPreviewAssertedShowing = ({
4182
4488
  src: unpreloadedSrc,
4183
4489
  style,
@@ -4198,6 +4504,7 @@ var VideoForPreviewAssertedShowing = ({
4198
4504
  fallbackOffthreadVideoProps,
4199
4505
  audioStreamIndex,
4200
4506
  debugOverlay,
4507
+ debugAudioScheduling,
4201
4508
  headless,
4202
4509
  onError,
4203
4510
  controls
@@ -4213,26 +4520,28 @@ var VideoForPreviewAssertedShowing = ({
4213
4520
  const [mediaPlayerReady, setMediaPlayerReady] = useState4(false);
4214
4521
  const [shouldFallbackToNativeVideo, setShouldFallbackToNativeVideo] = useState4(false);
4215
4522
  const [playing] = Timeline2.usePlayingState();
4216
- const timelineContext = useContext4(Internals16.TimelineContext);
4523
+ const timelineContext = Internals20.useTimelineContext();
4217
4524
  const globalPlaybackRate = timelineContext.playbackRate;
4218
- const sharedAudioContext = useContext4(SharedAudioContext2);
4525
+ const sharedAudioContext = useContext5(SharedAudioContext2);
4219
4526
  const buffer = useBufferState2();
4220
4527
  const [mediaMuted] = useMediaMutedState2();
4221
4528
  const [mediaVolume] = useMediaVolumeState2();
4222
4529
  const [mediaDurationInSeconds, setMediaDurationInSeconds] = useState4(null);
4223
- const { hidden } = useContext4(SequenceVisibilityToggleContext);
4530
+ const { hidden } = useContext5(SequenceVisibilityToggleContext);
4224
4531
  const volumePropFrame = useFrameForVolumeProp2(loopVolumeCurveBehavior);
4225
4532
  const userPreferredVolume = evaluateVolume2({
4226
4533
  frame: volumePropFrame,
4227
4534
  volume,
4228
4535
  mediaVolume
4229
4536
  });
4537
+ if (!videoConfig) {
4538
+ throw new Error("No video config found");
4539
+ }
4230
4540
  warnAboutTooHighVolume2(userPreferredVolume);
4231
- const parentSequence = useContext4(SequenceContext2);
4541
+ const parentSequence = useContext5(SequenceContext2);
4232
4542
  const isPremounting = Boolean(parentSequence?.premounting);
4233
4543
  const isPostmounting = Boolean(parentSequence?.postmounting);
4234
- const { premountFramesRemaining, playing: playingWhilePremounting } = useContext4(Internals16.PremountContext);
4235
- const isNextFrameGoingToPlay = playingWhilePremounting && premountFramesRemaining > 0 && premountFramesRemaining <= 1.000000001;
4544
+ const sequenceOffset = ((parentSequence?.cumulatedFrom ?? 0) + (parentSequence?.relativeFrom ?? 0)) / videoConfig.fps;
4236
4545
  const loopDisplay = useLoopDisplay({
4237
4546
  loop,
4238
4547
  mediaDurationInSeconds,
@@ -4257,34 +4566,35 @@ var VideoForPreviewAssertedShowing = ({
4257
4566
  controls
4258
4567
  });
4259
4568
  const isSequenceHidden = hidden[timelineId] ?? false;
4260
- if (!videoConfig) {
4261
- throw new Error("No video config found");
4262
- }
4263
4569
  const currentTime = frame / videoConfig.fps;
4264
4570
  const currentTimeRef = useRef2(currentTime);
4265
4571
  currentTimeRef.current = currentTime;
4266
4572
  const preloadedSrc = usePreload2(src);
4267
- const buffering = useContext4(Internals16.BufferingContextReact);
4573
+ const buffering = useContext5(Internals20.BufferingContextReact);
4268
4574
  if (!buffering) {
4269
4575
  throw new Error("useMediaPlayback must be used inside a <BufferingContext>");
4270
4576
  }
4271
4577
  const effectiveMuted = isSequenceHidden || muted || mediaMuted || userPreferredVolume <= 0;
4272
- const isPlayerBuffering = Internals16.useIsPlayerBuffering(buffering);
4578
+ const isPlayerBuffering = Internals20.useIsPlayerBuffering(buffering);
4273
4579
  const initialPlaying = useRef2(playing && !isPlayerBuffering);
4274
4580
  const initialIsPremounting = useRef2(isPremounting);
4275
4581
  const initialIsPostmounting = useRef2(isPostmounting);
4276
4582
  const initialGlobalPlaybackRate = useRef2(globalPlaybackRate);
4277
4583
  const initialPlaybackRate = useRef2(playbackRate);
4278
4584
  const initialMuted = useRef2(effectiveMuted);
4585
+ const initialSequenceOffset = useRef2(sequenceOffset);
4279
4586
  useEffect3(() => {
4280
4587
  if (!sharedAudioContext)
4281
4588
  return;
4589
+ if (!sharedAudioContext.audioContext)
4590
+ return;
4591
+ const { audioContext, audioSyncAnchor, scheduleAudioNode } = sharedAudioContext;
4282
4592
  try {
4283
4593
  const player = new MediaPlayer({
4284
4594
  canvas: canvasRef.current,
4285
4595
  src: preloadedSrc,
4286
4596
  logLevel,
4287
- sharedAudioContext: sharedAudioContext.audioContext,
4597
+ sharedAudioContext: { audioContext, audioSyncAnchor, scheduleAudioNode },
4288
4598
  loop,
4289
4599
  trimAfter: initialTrimAfterRef.current,
4290
4600
  trimBefore: initialTrimBeforeRef.current,
@@ -4292,13 +4602,15 @@ var VideoForPreviewAssertedShowing = ({
4292
4602
  playbackRate: initialPlaybackRate.current,
4293
4603
  audioStreamIndex,
4294
4604
  debugOverlay,
4605
+ debugAudioScheduling,
4295
4606
  bufferState: buffer,
4296
4607
  isPremounting: initialIsPremounting.current,
4297
4608
  isPostmounting: initialIsPostmounting.current,
4298
4609
  globalPlaybackRate: initialGlobalPlaybackRate.current,
4299
4610
  durationInFrames: videoConfig.durationInFrames,
4300
4611
  onVideoFrameCallback: initialOnVideoFrameRef.current ?? null,
4301
- playing: initialPlaying.current
4612
+ playing: initialPlaying.current,
4613
+ sequenceOffset: initialSequenceOffset.current
4302
4614
  });
4303
4615
  mediaPlayerRef.current = player;
4304
4616
  player.initialize(currentTimeRef.current, initialMuted.current).then((result) => {
@@ -4316,7 +4628,7 @@ var VideoForPreviewAssertedShowing = ({
4316
4628
  if (action === "fail") {
4317
4629
  throw errorToUse;
4318
4630
  }
4319
- Internals16.Log.warn({ logLevel, tag: "@remotion/media" }, fallbackMessage);
4631
+ Internals20.Log.warn({ logLevel, tag: "@remotion/media" }, fallbackMessage);
4320
4632
  setShouldFallbackToNativeVideo(true);
4321
4633
  };
4322
4634
  if (result.type === "unknown-container-format") {
@@ -4350,7 +4662,7 @@ var VideoForPreviewAssertedShowing = ({
4350
4662
  if (action === "fail") {
4351
4663
  throw errorToUse;
4352
4664
  }
4353
- Internals16.Log.error({ logLevel, tag: "@remotion/media" }, "[VideoForPreview] Failed to initialize MediaPlayer", errorToUse);
4665
+ Internals20.Log.error({ logLevel, tag: "@remotion/media" }, "[VideoForPreview] Failed to initialize MediaPlayer", errorToUse);
4354
4666
  setShouldFallbackToNativeVideo(true);
4355
4667
  });
4356
4668
  } catch (error) {
@@ -4364,12 +4676,12 @@ var VideoForPreviewAssertedShowing = ({
4364
4676
  if (action === "fail") {
4365
4677
  throw errorToUse;
4366
4678
  }
4367
- Internals16.Log.error({ logLevel, tag: "@remotion/media" }, "[VideoForPreview] MediaPlayer initialization failed", errorToUse);
4679
+ Internals20.Log.error({ logLevel, tag: "@remotion/media" }, "[VideoForPreview] MediaPlayer initialization failed", errorToUse);
4368
4680
  setShouldFallbackToNativeVideo(true);
4369
4681
  }
4370
4682
  return () => {
4371
4683
  if (mediaPlayerRef.current) {
4372
- Internals16.Log.trace({ logLevel, tag: "@remotion/media" }, `[VideoForPreview] Disposing MediaPlayer`);
4684
+ Internals20.Log.trace({ logLevel, tag: "@remotion/media" }, `[VideoForPreview] Disposing MediaPlayer`);
4373
4685
  mediaPlayerRef.current.dispose();
4374
4686
  mediaPlayerRef.current = null;
4375
4687
  }
@@ -4380,6 +4692,7 @@ var VideoForPreviewAssertedShowing = ({
4380
4692
  audioStreamIndex,
4381
4693
  buffer,
4382
4694
  debugOverlay,
4695
+ debugAudioScheduling,
4383
4696
  disallowFallbackToOffthreadVideo,
4384
4697
  logLevel,
4385
4698
  loop,
@@ -4390,65 +4703,33 @@ var VideoForPreviewAssertedShowing = ({
4390
4703
  videoConfig.durationInFrames
4391
4704
  ]);
4392
4705
  const classNameValue = useMemo4(() => {
4393
- return [Internals16.OBJECTFIT_CONTAIN_CLASS_NAME, className].filter(Internals16.truthy).join(" ");
4706
+ return [Internals20.OBJECTFIT_CONTAIN_CLASS_NAME, className].filter(Internals20.truthy).join(" ");
4394
4707
  }, [className]);
4395
- useEffect3(() => {
4396
- const mediaPlayer = mediaPlayerRef.current;
4397
- if (!mediaPlayer)
4398
- return;
4399
- if (isNextFrameGoingToPlay) {
4400
- const currentTimeUntilZero = premountFramesRemaining / videoConfig.fps / globalPlaybackRate;
4401
- mediaPlayer.playAudio(currentTimeRef.current - currentTimeUntilZero);
4402
- }
4403
- }, [
4404
- isNextFrameGoingToPlay,
4405
- premountFramesRemaining,
4406
- videoConfig.fps,
4407
- globalPlaybackRate
4408
- ]);
4409
- useEffect3(() => {
4410
- const mediaPlayer = mediaPlayerRef.current;
4411
- if (!mediaPlayer)
4412
- return;
4413
- if (playing && !isPlayerBuffering && !isNextFrameGoingToPlay) {
4414
- mediaPlayer.play(currentTimeRef.current);
4415
- } else {
4416
- mediaPlayer.pause();
4417
- }
4418
- }, [
4419
- isPlayerBuffering,
4708
+ useCommonEffects({
4709
+ mediaPlayerRef,
4710
+ mediaPlayerReady,
4711
+ currentTimeRef,
4420
4712
  playing,
4713
+ isPlayerBuffering,
4714
+ frame,
4715
+ trimBefore,
4716
+ trimAfter,
4717
+ effectiveMuted,
4718
+ userPreferredVolume,
4719
+ playbackRate,
4720
+ globalPlaybackRate,
4721
+ fps: videoConfig.fps,
4722
+ sequenceOffset,
4723
+ loop,
4724
+ debugAudioScheduling,
4725
+ durationInFrames: videoConfig.durationInFrames,
4726
+ isPremounting,
4727
+ isPostmounting,
4728
+ currentTime,
4421
4729
  logLevel,
4422
- mediaPlayerReady,
4423
- isNextFrameGoingToPlay
4424
- ]);
4425
- useEffect3(() => {
4426
- const mediaPlayer = mediaPlayerRef.current;
4427
- if (!mediaPlayer || !mediaPlayerReady) {
4428
- return;
4429
- }
4430
- mediaPlayer.setTrimBefore(trimBefore, currentTimeRef.current);
4431
- }, [trimBefore, mediaPlayerReady]);
4432
- useEffect3(() => {
4433
- const mediaPlayer = mediaPlayerRef.current;
4434
- if (!mediaPlayer || !mediaPlayerReady) {
4435
- return;
4436
- }
4437
- mediaPlayer.setTrimAfter(trimAfter, currentTimeRef.current);
4438
- }, [trimAfter, mediaPlayerReady]);
4439
- useLayoutEffect3(() => {
4440
- const mediaPlayer = mediaPlayerRef.current;
4441
- if (!mediaPlayer || !mediaPlayerReady)
4442
- return;
4443
- mediaPlayer.setMuted(effectiveMuted);
4444
- }, [effectiveMuted, mediaPlayerReady]);
4445
- useLayoutEffect3(() => {
4446
- const mediaPlayer = mediaPlayerRef.current;
4447
- if (!mediaPlayer || !mediaPlayerReady) {
4448
- return;
4449
- }
4450
- mediaPlayer.setVolume(userPreferredVolume);
4451
- }, [userPreferredVolume, mediaPlayerReady]);
4730
+ sharedAudioContext,
4731
+ label: "VideoForPreview"
4732
+ });
4452
4733
  useLayoutEffect3(() => {
4453
4734
  const mediaPlayer = mediaPlayerRef.current;
4454
4735
  if (!mediaPlayer || !mediaPlayerReady) {
@@ -4456,55 +4737,6 @@ var VideoForPreviewAssertedShowing = ({
4456
4737
  }
4457
4738
  mediaPlayer.setDebugOverlay(debugOverlay);
4458
4739
  }, [debugOverlay, mediaPlayerReady]);
4459
- useLayoutEffect3(() => {
4460
- const mediaPlayer = mediaPlayerRef.current;
4461
- if (!mediaPlayer || !mediaPlayerReady) {
4462
- return;
4463
- }
4464
- mediaPlayer.setPlaybackRate(playbackRate, currentTimeRef.current);
4465
- }, [playbackRate, mediaPlayerReady]);
4466
- useLayoutEffect3(() => {
4467
- const mediaPlayer = mediaPlayerRef.current;
4468
- if (!mediaPlayer || !mediaPlayerReady) {
4469
- return;
4470
- }
4471
- mediaPlayer.setGlobalPlaybackRate(globalPlaybackRate);
4472
- }, [globalPlaybackRate, mediaPlayerReady]);
4473
- useLayoutEffect3(() => {
4474
- const mediaPlayer = mediaPlayerRef.current;
4475
- if (!mediaPlayer || !mediaPlayerReady) {
4476
- return;
4477
- }
4478
- mediaPlayer.setLoop(loop);
4479
- }, [loop, mediaPlayerReady]);
4480
- useLayoutEffect3(() => {
4481
- const mediaPlayer = mediaPlayerRef.current;
4482
- if (!mediaPlayer || !mediaPlayerReady) {
4483
- return;
4484
- }
4485
- mediaPlayer.setDurationInFrames(videoConfig.durationInFrames);
4486
- }, [videoConfig.durationInFrames, mediaPlayerReady]);
4487
- useLayoutEffect3(() => {
4488
- const mediaPlayer = mediaPlayerRef.current;
4489
- if (!mediaPlayer || !mediaPlayerReady) {
4490
- return;
4491
- }
4492
- mediaPlayer.setIsPremounting(isPremounting);
4493
- }, [isPremounting, mediaPlayerReady]);
4494
- useLayoutEffect3(() => {
4495
- const mediaPlayer = mediaPlayerRef.current;
4496
- if (!mediaPlayer || !mediaPlayerReady) {
4497
- return;
4498
- }
4499
- mediaPlayer.setIsPostmounting(isPostmounting);
4500
- }, [isPostmounting, mediaPlayerReady]);
4501
- useLayoutEffect3(() => {
4502
- const mediaPlayer = mediaPlayerRef.current;
4503
- if (!mediaPlayer || !mediaPlayerReady) {
4504
- return;
4505
- }
4506
- mediaPlayer.setFps(videoConfig.fps);
4507
- }, [videoConfig.fps, mediaPlayerReady]);
4508
4740
  useLayoutEffect3(() => {
4509
4741
  const mediaPlayer = mediaPlayerRef.current;
4510
4742
  if (!mediaPlayer || !mediaPlayerReady) {
@@ -4512,13 +4744,6 @@ var VideoForPreviewAssertedShowing = ({
4512
4744
  }
4513
4745
  mediaPlayer.setVideoFrameCallback(onVideoFrame ?? null);
4514
4746
  }, [onVideoFrame, mediaPlayerReady]);
4515
- useLayoutEffect3(() => {
4516
- const mediaPlayer = mediaPlayerRef.current;
4517
- if (!mediaPlayer || !mediaPlayerReady)
4518
- return;
4519
- mediaPlayer.seekTo(currentTime).catch(() => {});
4520
- Internals16.Log.trace({ logLevel, tag: "@remotion/media" }, `[VideoForPreview] Updating target time to ${currentTime.toFixed(3)}s`);
4521
- }, [currentTime, logLevel, mediaPlayerReady]);
4522
4747
  const actualStyle = useMemo4(() => {
4523
4748
  return {
4524
4749
  ...style,
@@ -4548,66 +4773,21 @@ var VideoForPreviewAssertedShowing = ({
4548
4773
  }
4549
4774
  return /* @__PURE__ */ jsx4("canvas", {
4550
4775
  ref: canvasRef,
4551
- width: videoConfig.width,
4552
- height: videoConfig.height,
4553
4776
  style: actualStyle,
4554
4777
  className: classNameValue
4555
4778
  });
4556
4779
  };
4557
- var videoSchema = {
4558
- volume: {
4559
- type: "number",
4560
- min: 0,
4561
- max: 20,
4562
- step: 0.01,
4563
- default: 1,
4564
- description: "Volume"
4565
- },
4566
- playbackRate: {
4567
- type: "number",
4568
- min: 0,
4569
- step: 0.01,
4570
- default: 1,
4571
- description: "Playback Rate"
4572
- },
4573
- trimBefore: { type: "number", min: 0, default: 0 },
4574
- trimAfter: { type: "number", min: 0, default: 0 }
4575
- };
4576
4780
  var VideoForPreview = (props) => {
4577
- const schemaInput = useMemo4(() => {
4578
- if (typeof props.volume !== "number") {
4579
- return null;
4580
- }
4581
- return {
4582
- volume: props.volume,
4583
- playbackRate: props.playbackRate,
4584
- trimBefore: props.trimBefore,
4585
- trimAfter: props.trimAfter,
4586
- loop: props.loop
4587
- };
4588
- }, [
4589
- props.volume,
4590
- props.playbackRate,
4591
- props.trimBefore,
4592
- props.trimAfter,
4593
- props.loop
4594
- ]);
4595
- const { controls, values } = Internals16.useSchema(schemaInput ? videoSchema : null, schemaInput);
4596
- const volume = schemaInput !== null ? values.volume : props.volume;
4597
- const playbackRate = schemaInput !== null ? values.playbackRate : props.playbackRate;
4598
- const trimBefore = schemaInput !== null ? values.trimBefore : props.trimBefore;
4599
- const trimAfter = schemaInput !== null ? values.trimAfter : props.trimAfter;
4600
- const effectiveLoop = schemaInput !== null ? values.loop : props.loop;
4601
4781
  const frame = useCurrentFrame4();
4602
4782
  const videoConfig = useVideoConfig3();
4603
4783
  const currentTime = frame / videoConfig.fps;
4604
4784
  const showShow = useMemo4(() => {
4605
4785
  return getTimeInSeconds({
4606
4786
  unloopedTimeInSeconds: currentTime,
4607
- playbackRate,
4608
- loop: effectiveLoop,
4609
- trimBefore,
4610
- trimAfter,
4787
+ playbackRate: props.playbackRate,
4788
+ loop: props.loop,
4789
+ trimBefore: props.trimBefore,
4790
+ trimAfter: props.trimAfter,
4611
4791
  mediaDurationInSeconds: Infinity,
4612
4792
  fps: videoConfig.fps,
4613
4793
  ifNoMediaDuration: "infinity",
@@ -4615,37 +4795,32 @@ var VideoForPreview = (props) => {
4615
4795
  }) !== null;
4616
4796
  }, [
4617
4797
  currentTime,
4618
- effectiveLoop,
4619
- playbackRate,
4798
+ props.loop,
4799
+ props.playbackRate,
4620
4800
  props.src,
4621
- trimAfter,
4622
- trimBefore,
4623
- videoConfig.fps
4801
+ videoConfig.fps,
4802
+ props.trimBefore,
4803
+ props.trimAfter
4624
4804
  ]);
4625
4805
  if (!showShow) {
4626
4806
  return null;
4627
4807
  }
4628
4808
  return /* @__PURE__ */ jsx4(VideoForPreviewAssertedShowing, {
4629
4809
  ...props,
4630
- volume,
4631
- playbackRate,
4632
- loop: effectiveLoop,
4633
- trimBefore,
4634
- trimAfter,
4635
- controls
4810
+ controls: props.controls
4636
4811
  });
4637
4812
  };
4638
4813
 
4639
4814
  // src/video/video-for-rendering.tsx
4640
4815
  import {
4641
- useContext as useContext5,
4816
+ useContext as useContext6,
4642
4817
  useLayoutEffect as useLayoutEffect4,
4643
4818
  useMemo as useMemo5,
4644
4819
  useRef as useRef3,
4645
4820
  useState as useState5
4646
4821
  } from "react";
4647
4822
  import {
4648
- Internals as Internals17,
4823
+ Internals as Internals21,
4649
4824
  Loop,
4650
4825
  random as random2,
4651
4826
  useCurrentFrame as useCurrentFrame5,
@@ -4682,11 +4857,11 @@ var VideoForRendering = ({
4682
4857
  throw new TypeError("No `src` was passed to <Video>.");
4683
4858
  }
4684
4859
  const frame = useCurrentFrame5();
4685
- const absoluteFrame = Internals17.useTimelinePosition();
4860
+ const absoluteFrame = Internals21.useTimelinePosition();
4686
4861
  const { fps } = useVideoConfig4();
4687
- const { registerRenderAsset, unregisterRenderAsset } = useContext5(Internals17.RenderAssetManager);
4688
- const startsAt = Internals17.useMediaStartsAt();
4689
- const sequenceContext = useContext5(Internals17.SequenceContext);
4862
+ const { registerRenderAsset, unregisterRenderAsset } = useContext6(Internals21.RenderAssetManager);
4863
+ const startsAt = Internals21.useMediaStartsAt();
4864
+ const sequenceContext = useContext6(Internals21.SequenceContext);
4690
4865
  const id = useMemo5(() => `media-video-${random2(src)}-${sequenceContext?.cumulatedFrom}-${sequenceContext?.relativeFrom}-${sequenceContext?.durationInFrames}`, [
4691
4866
  src,
4692
4867
  sequenceContext?.cumulatedFrom,
@@ -4697,8 +4872,8 @@ var VideoForRendering = ({
4697
4872
  const { delayRender, continueRender, cancelRender: cancelRender3 } = useDelayRender2();
4698
4873
  const canvasRef = useRef3(null);
4699
4874
  const [replaceWithOffthreadVideo, setReplaceWithOffthreadVideo] = useState5(false);
4700
- const audioEnabled = Internals17.useAudioEnabled();
4701
- const videoEnabled = Internals17.useVideoEnabled();
4875
+ const audioEnabled = Internals21.useAudioEnabled();
4876
+ const videoEnabled = Internals21.useVideoEnabled();
4702
4877
  const maxCacheSize = useMaxMediaCacheSize(logLevel);
4703
4878
  const [error, setError] = useState5(null);
4704
4879
  if (error) {
@@ -4762,7 +4937,7 @@ var VideoForRendering = ({
4762
4937
  return;
4763
4938
  }
4764
4939
  if (window.remotion_isMainTab) {
4765
- Internals17.Log.warn({ logLevel, tag: "@remotion/media" }, fallbackMessage);
4940
+ Internals21.Log.warn({ logLevel, tag: "@remotion/media" }, fallbackMessage);
4766
4941
  }
4767
4942
  setReplaceWithOffthreadVideo({
4768
4943
  durationInSeconds: mediaDurationInSeconds
@@ -4817,12 +4992,12 @@ var VideoForRendering = ({
4817
4992
  frame,
4818
4993
  startsAt
4819
4994
  });
4820
- const volume = Internals17.evaluateVolume({
4995
+ const volume = Internals21.evaluateVolume({
4821
4996
  volume: volumeProp,
4822
4997
  frame: volumePropsFrame,
4823
4998
  mediaVolume: 1
4824
4999
  });
4825
- Internals17.warnAboutTooHighVolume(volume);
5000
+ Internals21.warnAboutTooHighVolume(volume);
4826
5001
  if (audio && volume > 0) {
4827
5002
  applyVolume(audio.data, volume);
4828
5003
  registerRenderAsset({
@@ -4878,10 +5053,10 @@ var VideoForRendering = ({
4878
5053
  onError
4879
5054
  ]);
4880
5055
  const classNameValue = useMemo5(() => {
4881
- return [Internals17.OBJECTFIT_CONTAIN_CLASS_NAME, className].filter(Internals17.truthy).join(" ");
5056
+ return [Internals21.OBJECTFIT_CONTAIN_CLASS_NAME, className].filter(Internals21.truthy).join(" ");
4882
5057
  }, [className]);
4883
5058
  if (replaceWithOffthreadVideo) {
4884
- const fallback = /* @__PURE__ */ jsx5(Internals17.InnerOffthreadVideo, {
5059
+ const fallback = /* @__PURE__ */ jsx5(Internals21.InnerOffthreadVideo, {
4885
5060
  src,
4886
5061
  playbackRate: playbackRate ?? 1,
4887
5062
  muted: muted ?? false,
@@ -4921,7 +5096,7 @@ var VideoForRendering = ({
4921
5096
  }
4922
5097
  return /* @__PURE__ */ jsx5(Loop, {
4923
5098
  layout: "none",
4924
- durationInFrames: Internals17.calculateMediaDuration({
5099
+ durationInFrames: Internals21.calculateMediaDuration({
4925
5100
  trimAfter: trimAfterValue,
4926
5101
  mediaDurationInFrames: replaceWithOffthreadVideo.durationInSeconds * fps,
4927
5102
  playbackRate,
@@ -4944,7 +5119,53 @@ var VideoForRendering = ({
4944
5119
 
4945
5120
  // src/video/video.tsx
4946
5121
  import { jsx as jsx6 } from "react/jsx-runtime";
4947
- var { validateMediaTrimProps, resolveTrimProps, validateMediaProps: validateMediaProps2 } = Internals18;
5122
+ var { validateMediaTrimProps, resolveTrimProps, validateMediaProps: validateMediaProps2 } = Internals22;
5123
+ var videoSchema = {
5124
+ volume: {
5125
+ type: "number",
5126
+ min: 0,
5127
+ max: 20,
5128
+ step: 0.01,
5129
+ default: 1,
5130
+ description: "Volume"
5131
+ },
5132
+ playbackRate: {
5133
+ type: "number",
5134
+ min: 0.1,
5135
+ step: 0.01,
5136
+ default: 1,
5137
+ description: "Playback Rate"
5138
+ },
5139
+ loop: { type: "boolean", default: false, description: "Loop" },
5140
+ "style.translate": {
5141
+ type: "translate",
5142
+ step: 1,
5143
+ default: "0px 0px",
5144
+ description: "Position"
5145
+ },
5146
+ "style.scale": {
5147
+ type: "number",
5148
+ min: 0.05,
5149
+ max: 100,
5150
+ step: 0.01,
5151
+ default: 1,
5152
+ description: "Scale"
5153
+ },
5154
+ "style.rotate": {
5155
+ type: "rotation",
5156
+ step: 1,
5157
+ default: "0deg",
5158
+ description: "Rotation"
5159
+ },
5160
+ "style.opacity": {
5161
+ type: "number",
5162
+ min: 0,
5163
+ max: 1,
5164
+ step: 0.01,
5165
+ default: 1,
5166
+ description: "Opacity"
5167
+ }
5168
+ };
4948
5169
  var InnerVideo = ({
4949
5170
  src,
4950
5171
  audioStreamIndex,
@@ -4968,8 +5189,10 @@ var InnerVideo = ({
4968
5189
  toneFrequency,
4969
5190
  showInTimeline,
4970
5191
  debugOverlay,
5192
+ debugAudioScheduling,
4971
5193
  headless,
4972
- onError
5194
+ onError,
5195
+ controls
4973
5196
  }) => {
4974
5197
  const environment = useRemotionEnvironment4();
4975
5198
  if (typeof src !== "string") {
@@ -5034,11 +5257,13 @@ var InnerVideo = ({
5034
5257
  disallowFallbackToOffthreadVideo,
5035
5258
  fallbackOffthreadVideoProps,
5036
5259
  debugOverlay: debugOverlay ?? false,
5260
+ debugAudioScheduling: debugAudioScheduling ?? false,
5037
5261
  headless: headless ?? false,
5038
- onError
5262
+ onError,
5263
+ controls
5039
5264
  });
5040
5265
  };
5041
- var Video = ({
5266
+ var VideoInner = ({
5042
5267
  src,
5043
5268
  audioStreamIndex,
5044
5269
  className,
@@ -5061,10 +5286,12 @@ var Video = ({
5061
5286
  stack,
5062
5287
  toneFrequency,
5063
5288
  debugOverlay,
5289
+ debugAudioScheduling,
5064
5290
  headless,
5065
- onError
5291
+ onError,
5292
+ controls
5066
5293
  }) => {
5067
- const fallbackLogLevel = Internals18.useLogLevel();
5294
+ const fallbackLogLevel = Internals22.useLogLevel();
5068
5295
  return /* @__PURE__ */ jsx6(InnerVideo, {
5069
5296
  audioStreamIndex: audioStreamIndex ?? 0,
5070
5297
  className,
@@ -5088,11 +5315,14 @@ var Video = ({
5088
5315
  toneFrequency: toneFrequency ?? 1,
5089
5316
  stack,
5090
5317
  debugOverlay: debugOverlay ?? false,
5318
+ debugAudioScheduling: debugAudioScheduling ?? false,
5091
5319
  headless: headless ?? false,
5092
- onError
5320
+ onError,
5321
+ controls
5093
5322
  });
5094
5323
  };
5095
- Internals18.addSequenceStackTraces(Video);
5324
+ var Video = Internals22.wrapInSchema(VideoInner, videoSchema);
5325
+ Internals22.addSequenceStackTraces(Video);
5096
5326
 
5097
5327
  // src/index.ts
5098
5328
  var experimental_Audio = Audio;