@remotion/studio 4.0.333 → 4.0.335

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.
@@ -29882,7 +29882,8 @@ var performSeek = async ({
29882
29882
  src,
29883
29883
  discardReadBytes,
29884
29884
  fields,
29885
- prefetchCache
29885
+ prefetchCache,
29886
+ isoState
29886
29887
  }) => {
29887
29888
  const byteInMediaSection = isByteInMediaSection({
29888
29889
  position: seekTo,
@@ -29946,6 +29947,9 @@ var performSeek = async ({
29946
29947
  prefetchCache
29947
29948
  });
29948
29949
  }
29950
+ if (userInitiated) {
29951
+ isoState.flatSamples.updateAfterSeek(seekTo);
29952
+ }
29949
29953
  await controller._internals.checkForAbortAndPause();
29950
29954
  };
29951
29955
  var turnSeekIntoByte = async ({
@@ -30122,7 +30126,8 @@ var workOnSeekRequest = async (options) => {
30122
30126
  src,
30123
30127
  discardReadBytes,
30124
30128
  fields,
30125
- prefetchCache
30129
+ prefetchCache,
30130
+ isoState
30126
30131
  });
30127
30132
  return;
30128
30133
  }
@@ -30142,7 +30147,8 @@ var workOnSeekRequest = async (options) => {
30142
30147
  src,
30143
30148
  discardReadBytes,
30144
30149
  fields,
30145
- prefetchCache
30150
+ prefetchCache,
30151
+ isoState
30146
30152
  });
30147
30153
  const { hasChanged } = controller._internals.seekSignal.clearSeekIfStillSame(seek2);
30148
30154
  if (hasChanged) {
@@ -31206,9 +31212,10 @@ var parseFlac = ({
31206
31212
  state
31207
31213
  });
31208
31214
  };
31209
- var calculateFlatSamples = ({
31215
+ var calculateSamplePositions = ({
31210
31216
  state,
31211
- mediaSectionStart
31217
+ mediaSectionStart,
31218
+ trackIds
31212
31219
  }) => {
31213
31220
  const tracks2 = getTracks(state, true);
31214
31221
  const moofBoxes = getMoofBoxes(state.structure.getIsoStructure().boxes);
@@ -31230,11 +31237,13 @@ var calculateFlatSamples = ({
31230
31237
  if (!moov) {
31231
31238
  throw new Error("No moov box found");
31232
31239
  }
31233
- const offsets = [];
31234
- const trackIds = [];
31235
- const map = new Map;
31240
+ const trackIdAndSamplePositions = [];
31236
31241
  for (const track of tracks2) {
31237
31242
  const trakBox = getTrakBoxByTrackId(moov, track.trackId);
31243
+ if (!trackIds.includes(track.trackId)) {
31244
+ Log.verbose(state.logLevel, "Skipping calculating sample positions for track", track.trackId);
31245
+ continue;
31246
+ }
31238
31247
  if (!trakBox) {
31239
31248
  throw new Error("No trak box found");
31240
31249
  }
@@ -31244,36 +31253,88 @@ var calculateFlatSamples = ({
31244
31253
  moofComplete,
31245
31254
  trexBoxes: getTrexBoxes(moov)
31246
31255
  });
31247
- trackIds.push(track.trackId);
31248
- for (const samplePosition of samplePositions) {
31249
- offsets.push(samplePosition.offset);
31250
- map.set(samplePosition.offset, {
31251
- track,
31252
- samplePosition
31253
- });
31256
+ trackIdAndSamplePositions.push({
31257
+ trackId: track.trackId,
31258
+ samplePositions
31259
+ });
31260
+ }
31261
+ return trackIdAndSamplePositions;
31262
+ };
31263
+ var updateSampleIndicesAfterSeek = ({
31264
+ samplePositionsForMdatStart,
31265
+ seekedByte
31266
+ }) => {
31267
+ const currentSampleIndices = {};
31268
+ const keys = Object.keys(samplePositionsForMdatStart).map(Number).sort();
31269
+ const mdat = keys.find((key4) => seekedByte >= key4);
31270
+ if (!mdat) {
31271
+ return currentSampleIndices;
31272
+ }
31273
+ const samplePositions = samplePositionsForMdatStart[mdat];
31274
+ if (!samplePositions) {
31275
+ return currentSampleIndices;
31276
+ }
31277
+ for (const track of samplePositions) {
31278
+ const currentSampleIndex = track.samplePositions.findIndex((sample) => sample.offset >= seekedByte);
31279
+ if (!currentSampleIndices[mdat]) {
31280
+ currentSampleIndices[mdat] = {};
31281
+ }
31282
+ if (!currentSampleIndices[mdat][track.trackId]) {
31283
+ currentSampleIndices[mdat][track.trackId] = 0;
31284
+ }
31285
+ if (currentSampleIndex === -1) {
31286
+ currentSampleIndices[mdat][track.trackId] = track.samplePositions.length;
31287
+ } else {
31288
+ currentSampleIndices[mdat][track.trackId] = currentSampleIndex;
31254
31289
  }
31255
31290
  }
31256
- offsets.sort((a, b) => a - b);
31257
- return { flatSamples: map, offsets, trackIds };
31291
+ return currentSampleIndices;
31258
31292
  };
31259
31293
  var cachedSamplePositionsState = () => {
31260
- const cachedForMdatStart = {};
31261
- const jumpMarksForMdatStart = {};
31294
+ const samplePositionsForMdatStart = {};
31295
+ let currentSampleIndex = {};
31262
31296
  return {
31263
31297
  getSamples: (mdatStart) => {
31264
- return cachedForMdatStart[mdatStart] ?? null;
31298
+ return samplePositionsForMdatStart[mdatStart] ?? null;
31265
31299
  },
31266
31300
  setSamples: (mdatStart, samples) => {
31267
- cachedForMdatStart[mdatStart] = samples;
31301
+ samplePositionsForMdatStart[mdatStart] = samples;
31268
31302
  },
31269
- setJumpMarks: (mdatStart, marks) => {
31270
- jumpMarksForMdatStart[mdatStart] = marks;
31303
+ setCurrentSampleIndex: (mdatStart, trackId, index) => {
31304
+ if (!currentSampleIndex[mdatStart]) {
31305
+ currentSampleIndex[mdatStart] = {};
31306
+ }
31307
+ if (!currentSampleIndex[mdatStart][trackId]) {
31308
+ currentSampleIndex[mdatStart][trackId] = 0;
31309
+ }
31310
+ currentSampleIndex[mdatStart][trackId] = index;
31271
31311
  },
31272
- getJumpMarks: (mdatStart) => {
31273
- return jumpMarksForMdatStart[mdatStart];
31312
+ getCurrentSampleIndices: (mdatStart) => {
31313
+ return currentSampleIndex[mdatStart] ?? {};
31314
+ },
31315
+ updateAfterSeek: (seekedByte) => {
31316
+ currentSampleIndex = updateSampleIndicesAfterSeek({
31317
+ samplePositionsForMdatStart,
31318
+ seekedByte
31319
+ });
31274
31320
  }
31275
31321
  };
31276
31322
  };
31323
+ var getSampleWithLowestDts = (samplePositions, currentSampleIndexMap) => {
31324
+ const lowestDts = [];
31325
+ for (const track of samplePositions) {
31326
+ const currentSampleIndex = currentSampleIndexMap[track.trackId] ?? 0;
31327
+ const currentSample = track.samplePositions[currentSampleIndex];
31328
+ if (currentSample && (lowestDts.length === 0 || currentSample.decodingTimestamp <= lowestDts[0].samplePosition.decodingTimestamp)) {
31329
+ lowestDts.push({
31330
+ samplePosition: currentSample,
31331
+ trackId: track.trackId,
31332
+ index: currentSampleIndex
31333
+ });
31334
+ }
31335
+ }
31336
+ return lowestDts;
31337
+ };
31277
31338
  var getLastMoofBox = (boxes) => {
31278
31339
  if (boxes) {
31279
31340
  const tfras = boxes.filter((b) => b.type === "tfra-box");
@@ -31543,116 +31604,6 @@ var getMoovAtom = async ({
31543
31604
  Log.verbose(state.logLevel, `Finished fetching moov atom in ${Date.now() - start}ms`);
31544
31605
  return moov;
31545
31606
  };
31546
- var MAX_SPREAD_IN_SECONDS = 8;
31547
- var getKey = (samplePositionTrack) => {
31548
- return `${samplePositionTrack.track.trackId}-${samplePositionTrack.samplePosition.decodingTimestamp}.${samplePositionTrack.samplePosition.offset}`;
31549
- };
31550
- var findBestJump = ({
31551
- sampleMap,
31552
- offsetsSorted,
31553
- visited,
31554
- progresses
31555
- }) => {
31556
- const minProgress = Math.min(...Object.values(progresses));
31557
- const trackNumberWithLowestProgress = Object.entries(progresses).find(([, progress]) => progress === minProgress)?.[0];
31558
- const firstSampleAboveMinProgress = offsetsSorted.findIndex((offset) => sampleMap.get(offset).track.trackId === Number(trackNumberWithLowestProgress) && !visited.has(getKey(sampleMap.get(offset))));
31559
- if (firstSampleAboveMinProgress === -1) {
31560
- const backup = offsetsSorted.findIndex((offset) => !visited.has(getKey(sampleMap.get(offset))));
31561
- if (backup === -1) {
31562
- throw new Error("this should not happen");
31563
- }
31564
- return backup;
31565
- }
31566
- return firstSampleAboveMinProgress;
31567
- };
31568
- var calculateJumpMarks = ({
31569
- sampleMap,
31570
- offsetsSorted,
31571
- trackIds,
31572
- endOfMdat
31573
- }) => {
31574
- const progresses = {};
31575
- for (const trackId of trackIds) {
31576
- progresses[trackId] = 0;
31577
- }
31578
- const jumpMarks = [];
31579
- let indexToVisit = 0;
31580
- const visited = new Set;
31581
- const increaseIndex = () => {
31582
- indexToVisit++;
31583
- if (indexToVisit >= offsetsSorted.length) {
31584
- throw new Error("should not roll over, should jump");
31585
- }
31586
- };
31587
- let lastVisitedSample = null;
31588
- const addJumpMark = ({
31589
- firstSampleAboveMinProgress
31590
- }) => {
31591
- if (!lastVisitedSample) {
31592
- throw new Error("no last visited sample");
31593
- }
31594
- const jumpMark = {
31595
- afterSampleWithOffset: lastVisitedSample.samplePosition.offset,
31596
- jumpToOffset: offsetsSorted[firstSampleAboveMinProgress]
31597
- };
31598
- if (firstSampleAboveMinProgress === offsetsSorted.indexOf(lastVisitedSample.samplePosition.offset) + 1) {
31599
- indexToVisit = firstSampleAboveMinProgress;
31600
- return;
31601
- }
31602
- indexToVisit = firstSampleAboveMinProgress;
31603
- jumpMarks.push(jumpMark);
31604
- };
31605
- const addFinalJumpIfNecessary = () => {
31606
- if (indexToVisit === offsetsSorted.length - 1) {
31607
- return;
31608
- }
31609
- jumpMarks.push({
31610
- afterSampleWithOffset: offsetsSorted[indexToVisit],
31611
- jumpToOffset: endOfMdat
31612
- });
31613
- };
31614
- const considerJump = () => {
31615
- const firstSampleAboveMinProgress = findBestJump({
31616
- sampleMap,
31617
- offsetsSorted,
31618
- visited,
31619
- progresses
31620
- });
31621
- addJumpMark({ firstSampleAboveMinProgress });
31622
- };
31623
- while (true) {
31624
- const currentSamplePosition = sampleMap.get(offsetsSorted[indexToVisit]);
31625
- const sampleKey = getKey(currentSamplePosition);
31626
- if (visited.has(sampleKey)) {
31627
- considerJump();
31628
- continue;
31629
- }
31630
- visited.add(sampleKey);
31631
- lastVisitedSample = currentSamplePosition;
31632
- if (visited.size === offsetsSorted.length) {
31633
- addFinalJumpIfNecessary();
31634
- break;
31635
- }
31636
- const timestamp = currentSamplePosition.samplePosition.decodingTimestamp / currentSamplePosition.track.originalTimescale;
31637
- progresses[currentSamplePosition.track.trackId] = timestamp;
31638
- const progressValues = Object.values(progresses);
31639
- const maxProgress = Math.max(...progressValues);
31640
- const minProgress = Math.min(...progressValues);
31641
- const spread = maxProgress - minProgress;
31642
- if (visited.size === offsetsSorted.length) {
31643
- addFinalJumpIfNecessary();
31644
- break;
31645
- }
31646
- if (spread > MAX_SPREAD_IN_SECONDS) {
31647
- considerJump();
31648
- } else if (indexToVisit === offsetsSorted.length - 1) {
31649
- considerJump();
31650
- } else {
31651
- increaseIndex();
31652
- }
31653
- }
31654
- return jumpMarks;
31655
- };
31656
31607
  var postprocessBytes = ({
31657
31608
  bytes,
31658
31609
  bigEndian,
@@ -31710,52 +31661,53 @@ var parseMdatSection = async (state) => {
31710
31661
  endOfMdat,
31711
31662
  state
31712
31663
  });
31664
+ const tracksFromMoov = getTracksFromMoovBox(moov);
31713
31665
  state.iso.moov.setMoovBox({
31714
31666
  moovBox: moov,
31715
31667
  precomputed: false
31716
31668
  });
31669
+ const existingTracks = state.callbacks.tracks.getTracks();
31670
+ for (const trackFromMoov of tracksFromMoov) {
31671
+ if (existingTracks.find((t) => t.trackId === trackFromMoov.trackId)) {
31672
+ continue;
31673
+ }
31674
+ if (trackFromMoov.type === "other") {
31675
+ continue;
31676
+ }
31677
+ state.callbacks.tracks.addTrack(trackFromMoov);
31678
+ }
31717
31679
  state.callbacks.tracks.setIsDone(state.logLevel);
31718
31680
  state.structure.getIsoStructure().boxes.push(moov);
31719
31681
  return parseMdatSection(state);
31720
31682
  }
31683
+ const tracks2 = state.callbacks.tracks.getTracks();
31721
31684
  if (!state.iso.flatSamples.getSamples(mediaSection.start)) {
31722
- const {
31723
- flatSamples: flatSamplesMap,
31724
- offsets,
31725
- trackIds
31726
- } = calculateFlatSamples({
31685
+ const samplePosition = calculateSamplePositions({
31727
31686
  state,
31728
- mediaSectionStart: mediaSection.start
31729
- });
31730
- const calcedJumpMarks = calculateJumpMarks({
31731
- sampleMap: flatSamplesMap,
31732
- offsetsSorted: offsets,
31733
- trackIds,
31734
- endOfMdat
31687
+ mediaSectionStart: mediaSection.start,
31688
+ trackIds: tracks2.map((t) => t.trackId)
31735
31689
  });
31736
- state.iso.flatSamples.setJumpMarks(mediaSection.start, calcedJumpMarks);
31737
- state.iso.flatSamples.setSamples(mediaSection.start, flatSamplesMap);
31690
+ state.iso.flatSamples.setSamples(mediaSection.start, samplePosition);
31738
31691
  }
31739
- const flatSamples = state.iso.flatSamples.getSamples(mediaSection.start);
31740
- const jumpMarks = state.iso.flatSamples.getJumpMarks(mediaSection.start);
31741
- const { iterator } = state;
31742
- const samplesWithIndex = flatSamples.get(iterator.counter.getOffset());
31743
- if (!samplesWithIndex) {
31744
- const offsets = Array.from(flatSamples.keys());
31745
- const nextSample_ = offsets.filter((s) => s > iterator.counter.getOffset()).sort((a, b) => a - b)[0];
31746
- if (nextSample_) {
31747
- iterator.discard(nextSample_ - iterator.counter.getOffset());
31748
- return null;
31749
- }
31750
- Log.verbose(state.logLevel, "Could not find sample at offset", iterator.counter.getOffset(), "skipping to end of mdat");
31692
+ const samplePositions = state.iso.flatSamples.getSamples(mediaSection.start);
31693
+ const sampleIndices = state.iso.flatSamples.getCurrentSampleIndices(mediaSection.start);
31694
+ const nextSampleArray = getSampleWithLowestDts(samplePositions, sampleIndices);
31695
+ if (nextSampleArray.length === 0) {
31696
+ Log.verbose(state.logLevel, "Iterated over all samples.", endOfMdat);
31751
31697
  return makeSkip(endOfMdat);
31752
31698
  }
31753
- if (samplesWithIndex.samplePosition.offset + samplesWithIndex.samplePosition.size > state.contentLength) {
31754
- Log.verbose(state.logLevel, "Sample is beyond the end of the file. Don't process it.", samplesWithIndex.samplePosition.offset + samplesWithIndex.samplePosition.size, endOfMdat);
31699
+ const exactMatch = nextSampleArray.find((s) => s.samplePosition.offset === state.iterator.counter.getOffset());
31700
+ const nextSample = exactMatch ?? nextSampleArray[0];
31701
+ if (nextSample.samplePosition.offset !== state.iterator.counter.getOffset()) {
31702
+ return makeSkip(nextSample.samplePosition.offset);
31703
+ }
31704
+ if (nextSample.samplePosition.offset + nextSample.samplePosition.size > state.contentLength) {
31705
+ Log.verbose(state.logLevel, "Sample is beyond the end of the file. Don't process it.", nextSample.samplePosition.offset + nextSample.samplePosition.size, endOfMdat);
31755
31706
  return makeSkip(endOfMdat);
31756
31707
  }
31757
- if (iterator.bytesRemaining() < samplesWithIndex.samplePosition.size) {
31758
- return makeFetchMoreData(samplesWithIndex.samplePosition.size - iterator.bytesRemaining());
31708
+ const { iterator } = state;
31709
+ if (iterator.bytesRemaining() < nextSample.samplePosition.size) {
31710
+ return makeFetchMoreData(nextSample.samplePosition.size - iterator.bytesRemaining());
31759
31711
  }
31760
31712
  const {
31761
31713
  timestamp: rawCts,
@@ -31765,21 +31717,22 @@ var parseMdatSection = async (state) => {
31765
31717
  offset,
31766
31718
  bigEndian,
31767
31719
  chunkSize
31768
- } = samplesWithIndex.samplePosition;
31720
+ } = nextSample.samplePosition;
31721
+ const track = tracks2.find((t) => t.trackId === nextSample.trackId);
31769
31722
  const {
31770
31723
  originalTimescale,
31771
31724
  startInSeconds,
31772
31725
  trackMediaTimeOffsetInTrackTimescale,
31773
31726
  timescale: trackTimescale
31774
- } = samplesWithIndex.track;
31727
+ } = track;
31775
31728
  const cts = rawCts + startInSeconds * originalTimescale - trackMediaTimeOffsetInTrackTimescale / trackTimescale * WEBCODECS_TIMESCALE;
31776
31729
  const dts = rawDts + startInSeconds * originalTimescale - trackMediaTimeOffsetInTrackTimescale / trackTimescale * WEBCODECS_TIMESCALE;
31777
31730
  const bytes = postprocessBytes({
31778
- bytes: iterator.getSlice(samplesWithIndex.samplePosition.size),
31731
+ bytes: iterator.getSlice(nextSample.samplePosition.size),
31779
31732
  bigEndian,
31780
31733
  chunkSize
31781
31734
  });
31782
- if (samplesWithIndex.track.type === "audio") {
31735
+ if (track.type === "audio") {
31783
31736
  const audioSample = convertAudioOrVideoSampleToWebCodecsTimestamps({
31784
31737
  sample: {
31785
31738
  data: bytes,
@@ -31793,10 +31746,10 @@ var parseMdatSection = async (state) => {
31793
31746
  });
31794
31747
  await state.callbacks.onAudioSample({
31795
31748
  audioSample,
31796
- trackId: samplesWithIndex.track.trackId
31749
+ trackId: track.trackId
31797
31750
  });
31798
31751
  }
31799
- if (samplesWithIndex.track.type === "video") {
31752
+ if (track.type === "video") {
31800
31753
  const nalUnitType = bytes[4] & 31;
31801
31754
  let isRecoveryPoint = false;
31802
31755
  if (nalUnitType === 6) {
@@ -31816,14 +31769,10 @@ var parseMdatSection = async (state) => {
31816
31769
  });
31817
31770
  await state.callbacks.onVideoSample({
31818
31771
  videoSample,
31819
- trackId: samplesWithIndex.track.trackId
31772
+ trackId: track.trackId
31820
31773
  });
31821
31774
  }
31822
- const jump = jumpMarks.find((j) => j.afterSampleWithOffset === offset);
31823
- if (jump) {
31824
- Log.verbose(state.logLevel, "Found jump mark", jump.jumpToOffset, "skipping to jump mark");
31825
- return makeSkip(jump.jumpToOffset);
31826
- }
31775
+ state.iso.flatSamples.setCurrentSampleIndex(mediaSection.start, nextSample.trackId, nextSample.index + 1);
31827
31776
  return null;
31828
31777
  };
31829
31778
  var parseIsoBaseMedia = async (state) => {
@@ -35715,7 +35664,8 @@ var parseLoop = async ({
35715
35664
  fields: state.fields,
35716
35665
  src: state.src,
35717
35666
  discardReadBytes: state.discardReadBytes,
35718
- prefetchCache: state.prefetchCache
35667
+ prefetchCache: state.prefetchCache,
35668
+ isoState: state.iso
35719
35669
  });
35720
35670
  state.timings.timeSeeking += Date.now() - seekStart;
35721
35671
  }
@@ -38036,7 +37986,8 @@ var TimelineSequenceFrame = ({ roundedFrame, premounted }) => {
38036
37986
  };
38037
37987
 
38038
37988
  // src/components/Timeline/TimelineVideoInfo.tsx
38039
- import { extractFrames, rotateAndResizeVideoFrame } from "@remotion/webcodecs";
37989
+ import { rotateAndResizeVideoFrame } from "@remotion/webcodecs";
37990
+ import { extractFramesOnWebWorker } from "@remotion/webcodecs/worker";
38040
37991
  import { useEffect as useEffect66, useRef as useRef36, useState as useState66 } from "react";
38041
37992
  import { useVideoConfig as useVideoConfig5 } from "remotion";
38042
37993
 
@@ -38278,7 +38229,7 @@ var TimelineVideoInfo = ({ src, visualizationWidth, startFrom, durationInFrames
38278
38229
  }
38279
38230
  }
38280
38231
  clearOldFrames();
38281
- extractFrames({
38232
+ extractFramesOnWebWorker({
38282
38233
  acknowledgeRemotionLicense: true,
38283
38234
  timestampsInSeconds: ({ track }) => {
38284
38235
  aspectRatio.current = track.width / track.height;