@remotion/media 4.0.428 → 4.0.430

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 (56) hide show
  1. package/README.md +7 -7
  2. package/dist/audio/allow-wait.js +15 -0
  3. package/dist/audio/audio-for-preview.d.ts +0 -1
  4. package/dist/audio/audio-for-preview.js +304 -0
  5. package/dist/audio/audio-for-rendering.js +194 -0
  6. package/dist/audio/audio-preview-iterator.d.ts +4 -2
  7. package/dist/audio/audio-preview-iterator.js +176 -0
  8. package/dist/audio/audio.js +20 -0
  9. package/dist/audio/props.js +1 -0
  10. package/dist/audio-extraction/audio-cache.js +66 -0
  11. package/dist/audio-extraction/audio-iterator.js +132 -0
  12. package/dist/audio-extraction/audio-manager.js +113 -0
  13. package/dist/audio-extraction/extract-audio.js +132 -0
  14. package/dist/audio-iterator-manager.d.ts +10 -9
  15. package/dist/audio-iterator-manager.js +228 -0
  16. package/dist/browser-can-use-webgl2.js +13 -0
  17. package/dist/caches.js +61 -0
  18. package/dist/calculate-playbacktime.js +4 -0
  19. package/dist/convert-audiodata/apply-volume.js +17 -0
  20. package/dist/convert-audiodata/combine-audiodata.js +23 -0
  21. package/dist/convert-audiodata/convert-audiodata.js +73 -0
  22. package/dist/convert-audiodata/resample-audiodata.js +94 -0
  23. package/dist/debug-overlay/preview-overlay.d.ts +9 -7
  24. package/dist/debug-overlay/preview-overlay.js +42 -0
  25. package/dist/esm/index.mjs +246 -103
  26. package/dist/extract-frame-and-audio.js +101 -0
  27. package/dist/get-sink.js +15 -0
  28. package/dist/get-time-in-seconds.js +40 -0
  29. package/dist/helpers/round-to-4-digits.js +4 -0
  30. package/dist/index.js +12 -0
  31. package/dist/is-type-of-error.js +20 -0
  32. package/dist/looped-frame.js +10 -0
  33. package/dist/media-player.d.ts +9 -5
  34. package/dist/media-player.js +431 -0
  35. package/dist/nonce-manager.js +13 -0
  36. package/dist/prewarm-iterator-for-looping.js +56 -0
  37. package/dist/render-timestamp-range.js +9 -0
  38. package/dist/show-in-timeline.js +31 -0
  39. package/dist/use-media-in-timeline.d.ts +3 -2
  40. package/dist/use-media-in-timeline.js +103 -0
  41. package/dist/video/props.js +1 -0
  42. package/dist/video/video-for-preview.js +331 -0
  43. package/dist/video/video-for-rendering.js +263 -0
  44. package/dist/video/video-preview-iterator.js +122 -0
  45. package/dist/video/video.js +35 -0
  46. package/dist/video-extraction/add-broadcast-channel-listener.js +125 -0
  47. package/dist/video-extraction/extract-frame-via-broadcast-channel.js +113 -0
  48. package/dist/video-extraction/extract-frame.js +85 -0
  49. package/dist/video-extraction/get-allocation-size.js +6 -0
  50. package/dist/video-extraction/get-frames-since-keyframe.js +108 -0
  51. package/dist/video-extraction/keyframe-bank.js +159 -0
  52. package/dist/video-extraction/keyframe-manager.js +206 -0
  53. package/dist/video-extraction/remember-actual-matroska-timestamps.js +19 -0
  54. package/dist/video-extraction/rotate-frame.js +34 -0
  55. package/dist/video-iterator-manager.js +109 -0
  56. package/package.json +7 -5
@@ -243,13 +243,13 @@ var makeAudioIterator = (startFromSecond, cache) => {
243
243
  queuedAudioNodes.length = 0;
244
244
  return nodes;
245
245
  };
246
- const addChunkForAfterResuming = (buffer, timestamp) => {
247
- audioChunksForAfterResuming.push({ buffer, timestamp });
246
+ const addChunkForAfterResuming = (buffer, timestamp, maxDuration) => {
247
+ audioChunksForAfterResuming.push({ buffer, timestamp, maxDuration });
248
248
  };
249
249
  const moveQueuedChunksToPauseQueue = () => {
250
250
  const toQueue = removeAndReturnAllQueuedAudioNodes();
251
251
  for (const chunk of toQueue) {
252
- addChunkForAfterResuming(chunk.buffer, chunk.timestamp);
252
+ addChunkForAfterResuming(chunk.buffer, chunk.timestamp, chunk.maxDuration);
253
253
  }
254
254
  };
255
255
  const getNumberOfChunksAfterResuming = () => {
@@ -274,8 +274,8 @@ var makeAudioIterator = (startFromSecond, cache) => {
274
274
  isDestroyed: () => {
275
275
  return destroyed;
276
276
  },
277
- addQueuedAudioNode: (node, timestamp, buffer) => {
278
- queuedAudioNodes.push({ node, timestamp, buffer });
277
+ addQueuedAudioNode: (node, timestamp, buffer, maxDuration) => {
278
+ queuedAudioNodes.push({ node, timestamp, buffer, maxDuration });
279
279
  },
280
280
  removeQueuedAudioNode: (node) => {
281
281
  const index = queuedAudioNodes.findIndex((n) => n.node === node);
@@ -388,7 +388,6 @@ var audioIteratorManager = ({
388
388
  getIsLooping,
389
389
  getEndTime,
390
390
  getStartTime,
391
- updatePlaybackTime,
392
391
  initialMuted,
393
392
  drawDebugOverlay
394
393
  }) => {
@@ -405,7 +404,8 @@ var audioIteratorManager = ({
405
404
  buffer,
406
405
  mediaTimestamp,
407
406
  playbackRate,
408
- scheduleAudioNode
407
+ scheduleAudioNode,
408
+ maxDuration
409
409
  }) => {
410
410
  if (!audioBufferIterator) {
411
411
  throw new Error("Audio buffer iterator not found");
@@ -417,9 +417,9 @@ var audioIteratorManager = ({
417
417
  node.buffer = buffer;
418
418
  node.playbackRate.value = playbackRate;
419
419
  node.connect(gainNode);
420
- scheduleAudioNode(node, mediaTimestamp);
420
+ scheduleAudioNode(node, mediaTimestamp, maxDuration);
421
421
  const iterator = audioBufferIterator;
422
- iterator.addQueuedAudioNode(node, mediaTimestamp, buffer);
422
+ iterator.addQueuedAudioNode(node, mediaTimestamp, buffer, maxDuration);
423
423
  node.onended = () => {
424
424
  setTimeout(() => {
425
425
  iterator.removeQueuedAudioNode(node);
@@ -435,18 +435,24 @@ var audioIteratorManager = ({
435
435
  if (muted) {
436
436
  return;
437
437
  }
438
+ const endTime = getEndTime();
439
+ if (buffer.timestamp >= endTime) {
440
+ return;
441
+ }
442
+ const maxDuration = buffer.timestamp + buffer.duration > endTime ? endTime - buffer.timestamp : null;
438
443
  if (getIsPlaying()) {
439
444
  scheduleAudioChunk({
440
445
  buffer: buffer.buffer,
441
446
  mediaTimestamp: buffer.timestamp,
442
447
  playbackRate,
443
- scheduleAudioNode
448
+ scheduleAudioNode,
449
+ maxDuration
444
450
  });
445
451
  } else {
446
452
  if (!audioBufferIterator) {
447
453
  throw new Error("Audio buffer iterator not found");
448
454
  }
449
- audioBufferIterator.addChunkForAfterResuming(buffer.buffer, buffer.timestamp);
455
+ audioBufferIterator.addChunkForAfterResuming(buffer.buffer, buffer.timestamp, maxDuration);
450
456
  }
451
457
  drawDebugOverlay();
452
458
  };
@@ -462,7 +468,6 @@ var audioIteratorManager = ({
462
468
  if (muted) {
463
469
  return;
464
470
  }
465
- updatePlaybackTime(startFromSecond);
466
471
  audioBufferIterator?.destroy();
467
472
  const delayHandle = __using(__stack, delayPlaybackHandleIfNotPremounting(), 0);
468
473
  currentDelayHandle = delayHandle;
@@ -497,7 +502,7 @@ var audioIteratorManager = ({
497
502
  scheduleAudioNode
498
503
  });
499
504
  }
500
- }, startFromSecond + MAX_BUFFER_AHEAD_SECONDS);
505
+ }, Math.min(startFromSecond + MAX_BUFFER_AHEAD_SECONDS, getEndTime()));
501
506
  } catch (e) {
502
507
  if (e instanceof InputDisposedError) {
503
508
  return;
@@ -583,7 +588,7 @@ var audioIteratorManager = ({
583
588
  scheduleAudioNode
584
589
  });
585
590
  }
586
- }, newTime + MAX_BUFFER_AHEAD_SECONDS);
591
+ }, Math.min(newTime + MAX_BUFFER_AHEAD_SECONDS, getEndTime()));
587
592
  };
588
593
  const resumeScheduledAudioChunks = ({
589
594
  playbackRate,
@@ -600,7 +605,8 @@ var audioIteratorManager = ({
600
605
  buffer: chunk.buffer,
601
606
  mediaTimestamp: chunk.timestamp,
602
607
  playbackRate,
603
- scheduleAudioNode
608
+ scheduleAudioNode,
609
+ maxDuration: chunk.maxDuration
604
610
  });
605
611
  }
606
612
  };
@@ -975,6 +981,7 @@ class MediaPlayer {
975
981
  fps;
976
982
  trimBefore;
977
983
  trimAfter;
984
+ durationInFrames;
978
985
  totalDuration;
979
986
  debugOverlay = false;
980
987
  nonceManager;
@@ -1000,6 +1007,7 @@ class MediaPlayer {
1000
1007
  bufferState,
1001
1008
  isPremounting,
1002
1009
  isPostmounting,
1010
+ durationInFrames,
1003
1011
  onVideoFrameCallback,
1004
1012
  playing
1005
1013
  }) {
@@ -1018,6 +1026,7 @@ class MediaPlayer {
1018
1026
  this.bufferState = bufferState;
1019
1027
  this.isPremounting = isPremounting;
1020
1028
  this.isPostmounting = isPostmounting;
1029
+ this.durationInFrames = durationInFrames;
1021
1030
  this.nonceManager = makeNonceManager();
1022
1031
  this.onVideoFrameCallback = onVideoFrameCallback;
1023
1032
  this.playing = playing;
@@ -1052,7 +1061,7 @@ class MediaPlayer {
1052
1061
  return (this.trimBefore ?? 0) / this.fps;
1053
1062
  }
1054
1063
  getEndTime() {
1055
- return calculateEndTime({
1064
+ const mediaEndTime = calculateEndTime({
1056
1065
  mediaDurationInSeconds: this.totalDuration,
1057
1066
  ifNoMediaDuration: "fail",
1058
1067
  src: this.src,
@@ -1060,6 +1069,11 @@ class MediaPlayer {
1060
1069
  trimBefore: this.trimBefore,
1061
1070
  fps: this.fps
1062
1071
  });
1072
+ if (this.loop) {
1073
+ return mediaEndTime;
1074
+ }
1075
+ const sequenceEndMediaTime = this.durationInFrames / this.fps * this.playbackRate + (this.trimBefore ?? 0) / this.fps;
1076
+ return Math.min(mediaEndTime, sequenceEndMediaTime);
1063
1077
  }
1064
1078
  async _initialize(startTimeUnresolved, initialMuted) {
1065
1079
  let __stack = [];
@@ -1116,21 +1130,11 @@ class MediaPlayer {
1116
1130
  getIsLooping: () => this.loop
1117
1131
  });
1118
1132
  }
1119
- const startTime = getTimeInSeconds({
1120
- unloopedTimeInSeconds: startTimeUnresolved,
1121
- playbackRate: this.playbackRate,
1122
- loop: this.loop,
1123
- trimBefore: this.trimBefore,
1124
- trimAfter: this.trimAfter,
1125
- mediaDurationInSeconds: this.totalDuration,
1126
- fps: this.fps,
1127
- ifNoMediaDuration: "infinity",
1128
- src: this.src
1129
- });
1133
+ const startTime = this.getTrimmedTime(startTimeUnresolved);
1130
1134
  if (startTime === null) {
1131
1135
  throw new Error(`should have asserted that the time is not null`);
1132
1136
  }
1133
- this.setPlaybackTime(startTime, this.playbackRate * this.globalPlaybackRate);
1137
+ this.setAudioPlaybackTime(startTime);
1134
1138
  if (audioTrack && this.sharedAudioContext) {
1135
1139
  const canDecode = await audioTrack.canDecode();
1136
1140
  if (!canDecode) {
@@ -1146,7 +1150,6 @@ class MediaPlayer {
1146
1150
  getIsLooping: () => this.loop,
1147
1151
  getEndTime: () => this.getEndTime(),
1148
1152
  getStartTime: () => this.getStartTime(),
1149
- updatePlaybackTime: (time) => this.setPlaybackTime(time, this.playbackRate * this.globalPlaybackRate),
1150
1153
  initialMuted,
1151
1154
  drawDebugOverlay: this.drawDebugOverlay
1152
1155
  });
@@ -1192,17 +1195,7 @@ class MediaPlayer {
1192
1195
  await this.seekPromiseChain;
1193
1196
  };
1194
1197
  async seekTo(time) {
1195
- const newTime = getTimeInSeconds({
1196
- unloopedTimeInSeconds: time,
1197
- playbackRate: this.playbackRate,
1198
- loop: this.loop,
1199
- trimBefore: this.trimBefore,
1200
- trimAfter: this.trimAfter,
1201
- mediaDurationInSeconds: this.totalDuration ?? null,
1202
- fps: this.fps,
1203
- ifNoMediaDuration: "infinity",
1204
- src: this.src
1205
- });
1198
+ const newTime = this.getTrimmedTime(time);
1206
1199
  if (newTime === null) {
1207
1200
  throw new Error(`should have asserted that the time is not null`);
1208
1201
  }
@@ -1213,6 +1206,9 @@ class MediaPlayer {
1213
1206
  return;
1214
1207
  }
1215
1208
  const shouldSeekAudio = this.audioIteratorManager && this.sharedAudioContext && this.getAudioPlaybackTime() !== newTime;
1209
+ if (shouldSeekAudio) {
1210
+ this.setAudioPlaybackTime(newTime);
1211
+ }
1216
1212
  await Promise.all([
1217
1213
  this.videoIteratorManager?.seek({
1218
1214
  newTime,
@@ -1227,26 +1223,12 @@ class MediaPlayer {
1227
1223
  }) : null
1228
1224
  ]);
1229
1225
  }
1230
- async play(time) {
1231
- if (this.playing) {
1232
- return;
1233
- }
1234
- const newTime = getTimeInSeconds({
1235
- unloopedTimeInSeconds: time,
1236
- playbackRate: this.playbackRate,
1237
- loop: this.loop,
1238
- trimBefore: this.trimBefore,
1239
- trimAfter: this.trimAfter,
1240
- mediaDurationInSeconds: this.totalDuration ?? null,
1241
- fps: this.fps,
1242
- ifNoMediaDuration: "infinity",
1243
- src: this.src
1244
- });
1226
+ async playAudio(time) {
1227
+ const newTime = this.getTrimmedTime(time);
1245
1228
  if (newTime === null) {
1246
1229
  throw new Error(`should have asserted that the time is not null`);
1247
1230
  }
1248
- this.setPlaybackTime(newTime, this.playbackRate * this.globalPlaybackRate);
1249
- this.playing = true;
1231
+ this.setAudioPlaybackTime(newTime);
1250
1232
  if (this.audioIteratorManager) {
1251
1233
  this.audioIteratorManager.resumeScheduledAudioChunks({
1252
1234
  playbackRate: this.playbackRate * this.globalPlaybackRate,
@@ -1256,6 +1238,13 @@ class MediaPlayer {
1256
1238
  if (this.sharedAudioContext && this.sharedAudioContext.state === "suspended") {
1257
1239
  await this.sharedAudioContext.resume();
1258
1240
  }
1241
+ }
1242
+ async play(time) {
1243
+ if (this.playing) {
1244
+ return;
1245
+ }
1246
+ this.playing = true;
1247
+ await this.playAudio(time);
1259
1248
  this.drawDebugOverlay();
1260
1249
  }
1261
1250
  delayPlaybackHandleIfNotPremounting = () => {
@@ -1290,11 +1279,8 @@ class MediaPlayer {
1290
1279
  }
1291
1280
  this.audioIteratorManager.setVolume(volume);
1292
1281
  }
1293
- async updateAfterTrimChange(unloopedTimeInSeconds) {
1294
- if (!this.audioIteratorManager && !this.videoIteratorManager) {
1295
- return;
1296
- }
1297
- const newMediaTime = getTimeInSeconds({
1282
+ getTrimmedTime(unloopedTimeInSeconds) {
1283
+ return getTimeInSeconds({
1298
1284
  unloopedTimeInSeconds,
1299
1285
  playbackRate: this.playbackRate,
1300
1286
  loop: this.loop,
@@ -1305,9 +1291,15 @@ class MediaPlayer {
1305
1291
  ifNoMediaDuration: "infinity",
1306
1292
  src: this.src
1307
1293
  });
1294
+ }
1295
+ async updateAfterTrimChange(unloopedTimeInSeconds) {
1296
+ if (!this.audioIteratorManager && !this.videoIteratorManager) {
1297
+ return;
1298
+ }
1299
+ const newMediaTime = this.getTrimmedTime(unloopedTimeInSeconds);
1308
1300
  this.audioIteratorManager?.destroyIterator();
1309
1301
  if (newMediaTime !== null) {
1310
- this.setPlaybackTime(newMediaTime, this.playbackRate * this.globalPlaybackRate);
1302
+ this.setAudioPlaybackTime(newMediaTime);
1311
1303
  if (!this.playing && this.videoIteratorManager) {
1312
1304
  await this.seekToWithQueue(newMediaTime);
1313
1305
  }
@@ -1328,14 +1320,14 @@ class MediaPlayer {
1328
1320
  setDebugOverlay(debugOverlay) {
1329
1321
  this.debugOverlay = debugOverlay;
1330
1322
  }
1331
- updateAudioTimeAfterPlaybackRateChange() {
1323
+ updateAudioTimeAfterPlaybackRateChange(mediaTimeBeforeChange) {
1332
1324
  if (!this.audioIteratorManager) {
1333
1325
  return;
1334
1326
  }
1335
1327
  if (!this.sharedAudioContext) {
1336
1328
  return;
1337
1329
  }
1338
- this.setPlaybackTime(this.getAudioPlaybackTime(), this.playbackRate * this.globalPlaybackRate);
1330
+ this.setAudioPlaybackTime(mediaTimeBeforeChange);
1339
1331
  const iterator = this.audioIteratorManager.getAudioBufferIterator();
1340
1332
  if (!iterator) {
1341
1333
  return;
@@ -1348,13 +1340,19 @@ class MediaPlayer {
1348
1340
  });
1349
1341
  }
1350
1342
  }
1351
- setPlaybackRate(rate) {
1343
+ async setPlaybackRate(rate, unloopedTimeInSeconds) {
1344
+ const previousRate = this.playbackRate;
1345
+ const mediaTime = this.sharedAudioContext ? this.getAudioPlaybackTime() : 0;
1352
1346
  this.playbackRate = rate;
1353
- this.updateAudioTimeAfterPlaybackRateChange();
1347
+ this.updateAudioTimeAfterPlaybackRateChange(mediaTime);
1348
+ if (previousRate !== rate) {
1349
+ await this.seekTo(unloopedTimeInSeconds);
1350
+ }
1354
1351
  }
1355
1352
  setGlobalPlaybackRate(rate) {
1353
+ const mediaTime = this.sharedAudioContext ? this.getAudioPlaybackTime() : 0;
1356
1354
  this.globalPlaybackRate = rate;
1357
- this.updateAudioTimeAfterPlaybackRateChange();
1355
+ this.updateAudioTimeAfterPlaybackRateChange(mediaTime);
1358
1356
  }
1359
1357
  setFps(fps) {
1360
1358
  this.fps = fps;
@@ -1368,6 +1366,9 @@ class MediaPlayer {
1368
1366
  setLoop(loop) {
1369
1367
  this.loop = loop;
1370
1368
  }
1369
+ setDurationInFrames(durationInFrames) {
1370
+ this.durationInFrames = durationInFrames;
1371
+ }
1371
1372
  async dispose() {
1372
1373
  if (this.initializationPromise) {
1373
1374
  try {
@@ -1379,7 +1380,7 @@ class MediaPlayer {
1379
1380
  this.audioIteratorManager?.destroyIterator();
1380
1381
  this.input.dispose();
1381
1382
  }
1382
- scheduleAudioNode = (node, mediaTimestamp) => {
1383
+ scheduleAudioNode = (node, mediaTimestamp, maxDuration) => {
1383
1384
  const currentTime = this.getAudioPlaybackTime();
1384
1385
  const delayWithoutPlaybackRate = mediaTimestamp - currentTime;
1385
1386
  const delay = delayWithoutPlaybackRate / (this.playbackRate * this.globalPlaybackRate);
@@ -1387,9 +1388,10 @@ class MediaPlayer {
1387
1388
  throw new Error("Shared audio context not found");
1388
1389
  }
1389
1390
  if (delay >= 0) {
1390
- node.start(this.sharedAudioContext.currentTime + delay);
1391
+ node.start(this.sharedAudioContext.currentTime + delay, 0, maxDuration ?? undefined);
1391
1392
  } else {
1392
- node.start(this.sharedAudioContext.currentTime, -delayWithoutPlaybackRate);
1393
+ const offset = -delayWithoutPlaybackRate;
1394
+ node.start(this.sharedAudioContext.currentTime, offset, maxDuration !== null ? maxDuration - offset : undefined);
1393
1395
  }
1394
1396
  };
1395
1397
  getAudioPlaybackTime() {
@@ -1402,11 +1404,17 @@ class MediaPlayer {
1402
1404
  playbackRate: this.playbackRate * this.globalPlaybackRate
1403
1405
  });
1404
1406
  }
1405
- setPlaybackTime(time, playbackRate) {
1407
+ setAudioPlaybackTime(time) {
1406
1408
  if (!this.sharedAudioContext) {
1407
1409
  return;
1408
1410
  }
1409
- this.audioSyncAnchor = this.sharedAudioContext.currentTime - time / playbackRate;
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;
1410
1418
  }
1411
1419
  setVideoFrameCallback(callback) {
1412
1420
  this.onVideoFrameCallback = callback;
@@ -1505,7 +1513,8 @@ var useMediaInTimeline = ({
1505
1513
  postmountDisplay,
1506
1514
  loopDisplay,
1507
1515
  trimBefore,
1508
- trimAfter
1516
+ trimAfter,
1517
+ controls
1509
1518
  }) => {
1510
1519
  const parentSequence = useContext(Internals5.SequenceContext);
1511
1520
  const startsAt = Internals5.useMediaStartsAt();
@@ -1556,7 +1565,8 @@ var useMediaInTimeline = ({
1556
1565
  stack,
1557
1566
  from: 0,
1558
1567
  duration,
1559
- id: sequenceId
1568
+ id: sequenceId,
1569
+ controls: null
1560
1570
  });
1561
1571
  }
1562
1572
  registerSequence({
@@ -1577,7 +1587,8 @@ var useMediaInTimeline = ({
1577
1587
  playbackRate,
1578
1588
  stack,
1579
1589
  premountDisplay: null,
1580
- postmountDisplay: null
1590
+ postmountDisplay: null,
1591
+ controls: controls ?? null
1581
1592
  });
1582
1593
  return () => {
1583
1594
  if (loopDisplay) {
@@ -1586,6 +1597,7 @@ var useMediaInTimeline = ({
1586
1597
  unregisterSequence(mediaId);
1587
1598
  };
1588
1599
  }, [
1600
+ controls,
1589
1601
  doesVolumeChange,
1590
1602
  duration,
1591
1603
  finalDisplayName,
@@ -1646,7 +1658,8 @@ var AudioForPreviewAssertedShowing = ({
1646
1658
  toneFrequency,
1647
1659
  audioStreamIndex,
1648
1660
  fallbackHtml5AudioProps,
1649
- onError
1661
+ onError,
1662
+ controls
1650
1663
  }) => {
1651
1664
  const videoConfig = useUnsafeVideoConfig();
1652
1665
  const frame = useCurrentFrame2();
@@ -1703,7 +1716,8 @@ var AudioForPreviewAssertedShowing = ({
1703
1716
  postmountDisplay: parentSequence?.postmountDisplay ?? null,
1704
1717
  loopDisplay,
1705
1718
  trimAfter,
1706
- trimBefore
1719
+ trimBefore,
1720
+ controls
1707
1721
  });
1708
1722
  const bufferingContext = useContext2(Internals6.BufferingContextReact);
1709
1723
  if (!bufferingContext) {
@@ -1739,6 +1753,7 @@ var AudioForPreviewAssertedShowing = ({
1739
1753
  isPostmounting: initialIsPostmounting.current,
1740
1754
  isPremounting: initialIsPremounting.current,
1741
1755
  globalPlaybackRate: initialGlobalPlaybackRate.current,
1756
+ durationInFrames: videoConfig.durationInFrames,
1742
1757
  onVideoFrameCallback: null,
1743
1758
  playing: initialPlaying.current
1744
1759
  });
@@ -1831,7 +1846,8 @@ var AudioForPreviewAssertedShowing = ({
1831
1846
  audioStreamIndex,
1832
1847
  disallowFallbackToHtml5Audio,
1833
1848
  buffer,
1834
- onError
1849
+ onError,
1850
+ videoConfig.durationInFrames
1835
1851
  ]);
1836
1852
  useLayoutEffect(() => {
1837
1853
  const audioPlayer = mediaPlayerRef.current;
@@ -1875,7 +1891,7 @@ var AudioForPreviewAssertedShowing = ({
1875
1891
  if (!audioPlayer || !mediaPlayerReady) {
1876
1892
  return;
1877
1893
  }
1878
- audioPlayer.setPlaybackRate(playbackRate);
1894
+ audioPlayer.setPlaybackRate(playbackRate, currentTimeRef.current);
1879
1895
  }, [playbackRate, mediaPlayerReady]);
1880
1896
  useLayoutEffect(() => {
1881
1897
  const audioPlayer = mediaPlayerRef.current;
@@ -1898,6 +1914,13 @@ var AudioForPreviewAssertedShowing = ({
1898
1914
  }
1899
1915
  mediaPlayer.setLoop(loop);
1900
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]);
1901
1924
  useLayoutEffect(() => {
1902
1925
  const mediaPlayer = mediaPlayerRef.current;
1903
1926
  if (!mediaPlayer || !mediaPlayerReady) {
@@ -1941,17 +1964,36 @@ var AudioForPreviewAssertedShowing = ({
1941
1964
  }
1942
1965
  return null;
1943
1966
  };
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
+ };
1944
1986
  var AudioForPreview = ({
1945
1987
  loop,
1946
1988
  src,
1947
1989
  logLevel,
1948
1990
  muted,
1949
1991
  name,
1950
- volume,
1992
+ volume: volumeProp,
1951
1993
  loopVolumeCurveBehavior,
1952
- playbackRate,
1953
- trimAfter,
1954
- trimBefore,
1994
+ playbackRate: playbackRateProp,
1995
+ trimAfter: trimAfterProp,
1996
+ trimBefore: trimBeforeProp,
1955
1997
  showInTimeline,
1956
1998
  stack,
1957
1999
  disallowFallbackToHtml5Audio,
@@ -1960,6 +2002,24 @@ var AudioForPreview = ({
1960
2002
  fallbackHtml5AudioProps,
1961
2003
  onError
1962
2004
  }) => {
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;
1963
2023
  const preloadedSrc = usePreload(src);
1964
2024
  const defaultLogLevel = Internals6.useLogLevel();
1965
2025
  const frame = useCurrentFrame2();
@@ -1969,7 +2029,7 @@ var AudioForPreview = ({
1969
2029
  return getTimeInSeconds({
1970
2030
  unloopedTimeInSeconds: currentTime,
1971
2031
  playbackRate: playbackRate ?? 1,
1972
- loop: loop ?? false,
2032
+ loop: effectiveLoop,
1973
2033
  trimBefore,
1974
2034
  trimAfter,
1975
2035
  mediaDurationInSeconds: Infinity,
@@ -1979,7 +2039,7 @@ var AudioForPreview = ({
1979
2039
  }) !== null;
1980
2040
  }, [
1981
2041
  currentTime,
1982
- loop,
2042
+ effectiveLoop,
1983
2043
  playbackRate,
1984
2044
  src,
1985
2045
  trimAfter,
@@ -1997,7 +2057,7 @@ var AudioForPreview = ({
1997
2057
  muted: muted ?? false,
1998
2058
  volume: volume ?? 1,
1999
2059
  loopVolumeCurveBehavior: loopVolumeCurveBehavior ?? "repeat",
2000
- loop: loop ?? false,
2060
+ loop: effectiveLoop,
2001
2061
  trimAfter,
2002
2062
  trimBefore,
2003
2063
  name,
@@ -2006,7 +2066,8 @@ var AudioForPreview = ({
2006
2066
  disallowFallbackToHtml5Audio: disallowFallbackToHtml5Audio ?? false,
2007
2067
  toneFrequency,
2008
2068
  onError,
2009
- fallbackHtml5AudioProps
2069
+ fallbackHtml5AudioProps,
2070
+ controls
2010
2071
  });
2011
2072
  };
2012
2073
 
@@ -4138,7 +4199,8 @@ var VideoForPreviewAssertedShowing = ({
4138
4199
  audioStreamIndex,
4139
4200
  debugOverlay,
4140
4201
  headless,
4141
- onError
4202
+ onError,
4203
+ controls
4142
4204
  }) => {
4143
4205
  const src = usePreload2(unpreloadedSrc);
4144
4206
  const canvasRef = useRef2(null);
@@ -4169,6 +4231,8 @@ var VideoForPreviewAssertedShowing = ({
4169
4231
  const parentSequence = useContext4(SequenceContext2);
4170
4232
  const isPremounting = Boolean(parentSequence?.premounting);
4171
4233
  const isPostmounting = Boolean(parentSequence?.postmounting);
4234
+ const { premountFramesRemaining, playing: playingWhilePremounting } = useContext4(Internals16.PremountContext);
4235
+ const isNextFrameGoingToPlay = playingWhilePremounting && premountFramesRemaining > 0 && premountFramesRemaining <= 1.000000001;
4172
4236
  const loopDisplay = useLoopDisplay({
4173
4237
  loop,
4174
4238
  mediaDurationInSeconds,
@@ -4189,7 +4253,8 @@ var VideoForPreviewAssertedShowing = ({
4189
4253
  loopDisplay,
4190
4254
  mediaVolume,
4191
4255
  trimAfter,
4192
- trimBefore
4256
+ trimBefore,
4257
+ controls
4193
4258
  });
4194
4259
  const isSequenceHidden = hidden[timelineId] ?? false;
4195
4260
  if (!videoConfig) {
@@ -4231,6 +4296,7 @@ var VideoForPreviewAssertedShowing = ({
4231
4296
  isPremounting: initialIsPremounting.current,
4232
4297
  isPostmounting: initialIsPostmounting.current,
4233
4298
  globalPlaybackRate: initialGlobalPlaybackRate.current,
4299
+ durationInFrames: videoConfig.durationInFrames,
4234
4300
  onVideoFrameCallback: initialOnVideoFrameRef.current ?? null,
4235
4301
  playing: initialPlaying.current
4236
4302
  });
@@ -4320,7 +4386,8 @@ var VideoForPreviewAssertedShowing = ({
4320
4386
  preloadedSrc,
4321
4387
  sharedAudioContext,
4322
4388
  videoConfig.fps,
4323
- onError
4389
+ onError,
4390
+ videoConfig.durationInFrames
4324
4391
  ]);
4325
4392
  const classNameValue = useMemo4(() => {
4326
4393
  return [Internals16.OBJECTFIT_CONTAIN_CLASS_NAME, className].filter(Internals16.truthy).join(" ");
@@ -4329,12 +4396,32 @@ var VideoForPreviewAssertedShowing = ({
4329
4396
  const mediaPlayer = mediaPlayerRef.current;
4330
4397
  if (!mediaPlayer)
4331
4398
  return;
4332
- if (playing && !isPlayerBuffering) {
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) {
4333
4414
  mediaPlayer.play(currentTimeRef.current);
4334
4415
  } else {
4335
4416
  mediaPlayer.pause();
4336
4417
  }
4337
- }, [isPlayerBuffering, playing, logLevel, mediaPlayerReady]);
4418
+ }, [
4419
+ isPlayerBuffering,
4420
+ playing,
4421
+ logLevel,
4422
+ mediaPlayerReady,
4423
+ isNextFrameGoingToPlay
4424
+ ]);
4338
4425
  useEffect3(() => {
4339
4426
  const mediaPlayer = mediaPlayerRef.current;
4340
4427
  if (!mediaPlayer || !mediaPlayerReady) {
@@ -4374,7 +4461,7 @@ var VideoForPreviewAssertedShowing = ({
4374
4461
  if (!mediaPlayer || !mediaPlayerReady) {
4375
4462
  return;
4376
4463
  }
4377
- mediaPlayer.setPlaybackRate(playbackRate);
4464
+ mediaPlayer.setPlaybackRate(playbackRate, currentTimeRef.current);
4378
4465
  }, [playbackRate, mediaPlayerReady]);
4379
4466
  useLayoutEffect3(() => {
4380
4467
  const mediaPlayer = mediaPlayerRef.current;
@@ -4390,6 +4477,13 @@ var VideoForPreviewAssertedShowing = ({
4390
4477
  }
4391
4478
  mediaPlayer.setLoop(loop);
4392
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]);
4393
4487
  useLayoutEffect3(() => {
4394
4488
  const mediaPlayer = mediaPlayerRef.current;
4395
4489
  if (!mediaPlayer || !mediaPlayerReady) {
@@ -4460,17 +4554,60 @@ var VideoForPreviewAssertedShowing = ({
4460
4554
  className: classNameValue
4461
4555
  });
4462
4556
  };
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
+ };
4463
4576
  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;
4464
4601
  const frame = useCurrentFrame4();
4465
4602
  const videoConfig = useVideoConfig3();
4466
4603
  const currentTime = frame / videoConfig.fps;
4467
4604
  const showShow = useMemo4(() => {
4468
4605
  return getTimeInSeconds({
4469
4606
  unloopedTimeInSeconds: currentTime,
4470
- playbackRate: props.playbackRate,
4471
- loop: props.loop,
4472
- trimBefore: props.trimBefore,
4473
- trimAfter: props.trimAfter,
4607
+ playbackRate,
4608
+ loop: effectiveLoop,
4609
+ trimBefore,
4610
+ trimAfter,
4474
4611
  mediaDurationInSeconds: Infinity,
4475
4612
  fps: videoConfig.fps,
4476
4613
  ifNoMediaDuration: "infinity",
@@ -4478,18 +4615,24 @@ var VideoForPreview = (props) => {
4478
4615
  }) !== null;
4479
4616
  }, [
4480
4617
  currentTime,
4481
- props.loop,
4482
- props.playbackRate,
4618
+ effectiveLoop,
4619
+ playbackRate,
4483
4620
  props.src,
4484
- props.trimAfter,
4485
- props.trimBefore,
4621
+ trimAfter,
4622
+ trimBefore,
4486
4623
  videoConfig.fps
4487
4624
  ]);
4488
4625
  if (!showShow) {
4489
4626
  return null;
4490
4627
  }
4491
4628
  return /* @__PURE__ */ jsx4(VideoForPreviewAssertedShowing, {
4492
- ...props
4629
+ ...props,
4630
+ volume,
4631
+ playbackRate,
4632
+ loop: effectiveLoop,
4633
+ trimBefore,
4634
+ trimAfter,
4635
+ controls
4493
4636
  });
4494
4637
  };
4495
4638