@remotion/studio 4.0.333 → 4.0.334

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.
@@ -30162,7 +30162,8 @@ var performSeek = async ({
30162
30162
  src,
30163
30163
  discardReadBytes,
30164
30164
  fields,
30165
- prefetchCache
30165
+ prefetchCache,
30166
+ isoState
30166
30167
  }) => {
30167
30168
  const byteInMediaSection = isByteInMediaSection({
30168
30169
  position: seekTo,
@@ -30226,6 +30227,9 @@ var performSeek = async ({
30226
30227
  prefetchCache
30227
30228
  });
30228
30229
  }
30230
+ if (userInitiated) {
30231
+ isoState.flatSamples.updateAfterSeek(seekTo);
30232
+ }
30229
30233
  await controller._internals.checkForAbortAndPause();
30230
30234
  };
30231
30235
  var turnSeekIntoByte = async ({
@@ -30402,7 +30406,8 @@ var workOnSeekRequest = async (options) => {
30402
30406
  src,
30403
30407
  discardReadBytes,
30404
30408
  fields,
30405
- prefetchCache
30409
+ prefetchCache,
30410
+ isoState
30406
30411
  });
30407
30412
  return;
30408
30413
  }
@@ -30422,7 +30427,8 @@ var workOnSeekRequest = async (options) => {
30422
30427
  src,
30423
30428
  discardReadBytes,
30424
30429
  fields,
30425
- prefetchCache
30430
+ prefetchCache,
30431
+ isoState
30426
30432
  });
30427
30433
  const { hasChanged } = controller._internals.seekSignal.clearSeekIfStillSame(seek2);
30428
30434
  if (hasChanged) {
@@ -31486,9 +31492,10 @@ var parseFlac = ({
31486
31492
  state
31487
31493
  });
31488
31494
  };
31489
- var calculateFlatSamples = ({
31495
+ var calculateSamplePositions = ({
31490
31496
  state,
31491
- mediaSectionStart
31497
+ mediaSectionStart,
31498
+ trackIds
31492
31499
  }) => {
31493
31500
  const tracks2 = getTracks(state, true);
31494
31501
  const moofBoxes = getMoofBoxes(state.structure.getIsoStructure().boxes);
@@ -31510,11 +31517,13 @@ var calculateFlatSamples = ({
31510
31517
  if (!moov) {
31511
31518
  throw new Error("No moov box found");
31512
31519
  }
31513
- const offsets = [];
31514
- const trackIds = [];
31515
- const map = new Map;
31520
+ const trackIdAndSamplePositions = [];
31516
31521
  for (const track of tracks2) {
31517
31522
  const trakBox = getTrakBoxByTrackId(moov, track.trackId);
31523
+ if (!trackIds.includes(track.trackId)) {
31524
+ Log.verbose(state.logLevel, "Skipping calculating sample positions for track", track.trackId);
31525
+ continue;
31526
+ }
31518
31527
  if (!trakBox) {
31519
31528
  throw new Error("No trak box found");
31520
31529
  }
@@ -31524,36 +31533,88 @@ var calculateFlatSamples = ({
31524
31533
  moofComplete,
31525
31534
  trexBoxes: getTrexBoxes(moov)
31526
31535
  });
31527
- trackIds.push(track.trackId);
31528
- for (const samplePosition of samplePositions) {
31529
- offsets.push(samplePosition.offset);
31530
- map.set(samplePosition.offset, {
31531
- track,
31532
- samplePosition
31533
- });
31536
+ trackIdAndSamplePositions.push({
31537
+ trackId: track.trackId,
31538
+ samplePositions
31539
+ });
31540
+ }
31541
+ return trackIdAndSamplePositions;
31542
+ };
31543
+ var updateSampleIndicesAfterSeek = ({
31544
+ samplePositionsForMdatStart,
31545
+ seekedByte
31546
+ }) => {
31547
+ const currentSampleIndices = {};
31548
+ const keys = Object.keys(samplePositionsForMdatStart).map(Number).sort();
31549
+ const mdat = keys.find((key4) => seekedByte >= key4);
31550
+ if (!mdat) {
31551
+ return currentSampleIndices;
31552
+ }
31553
+ const samplePositions = samplePositionsForMdatStart[mdat];
31554
+ if (!samplePositions) {
31555
+ return currentSampleIndices;
31556
+ }
31557
+ for (const track of samplePositions) {
31558
+ const currentSampleIndex = track.samplePositions.findIndex((sample) => sample.offset >= seekedByte);
31559
+ if (!currentSampleIndices[mdat]) {
31560
+ currentSampleIndices[mdat] = {};
31561
+ }
31562
+ if (!currentSampleIndices[mdat][track.trackId]) {
31563
+ currentSampleIndices[mdat][track.trackId] = 0;
31564
+ }
31565
+ if (currentSampleIndex === -1) {
31566
+ currentSampleIndices[mdat][track.trackId] = track.samplePositions.length;
31567
+ } else {
31568
+ currentSampleIndices[mdat][track.trackId] = currentSampleIndex;
31534
31569
  }
31535
31570
  }
31536
- offsets.sort((a, b) => a - b);
31537
- return { flatSamples: map, offsets, trackIds };
31571
+ return currentSampleIndices;
31538
31572
  };
31539
31573
  var cachedSamplePositionsState = () => {
31540
- const cachedForMdatStart = {};
31541
- const jumpMarksForMdatStart = {};
31574
+ const samplePositionsForMdatStart = {};
31575
+ let currentSampleIndex = {};
31542
31576
  return {
31543
31577
  getSamples: (mdatStart) => {
31544
- return cachedForMdatStart[mdatStart] ?? null;
31578
+ return samplePositionsForMdatStart[mdatStart] ?? null;
31545
31579
  },
31546
31580
  setSamples: (mdatStart, samples) => {
31547
- cachedForMdatStart[mdatStart] = samples;
31581
+ samplePositionsForMdatStart[mdatStart] = samples;
31548
31582
  },
31549
- setJumpMarks: (mdatStart, marks) => {
31550
- jumpMarksForMdatStart[mdatStart] = marks;
31583
+ setCurrentSampleIndex: (mdatStart, trackId, index) => {
31584
+ if (!currentSampleIndex[mdatStart]) {
31585
+ currentSampleIndex[mdatStart] = {};
31586
+ }
31587
+ if (!currentSampleIndex[mdatStart][trackId]) {
31588
+ currentSampleIndex[mdatStart][trackId] = 0;
31589
+ }
31590
+ currentSampleIndex[mdatStart][trackId] = index;
31551
31591
  },
31552
- getJumpMarks: (mdatStart) => {
31553
- return jumpMarksForMdatStart[mdatStart];
31592
+ getCurrentSampleIndices: (mdatStart) => {
31593
+ return currentSampleIndex[mdatStart] ?? {};
31594
+ },
31595
+ updateAfterSeek: (seekedByte) => {
31596
+ currentSampleIndex = updateSampleIndicesAfterSeek({
31597
+ samplePositionsForMdatStart,
31598
+ seekedByte
31599
+ });
31554
31600
  }
31555
31601
  };
31556
31602
  };
31603
+ var getSampleWithLowestDts = (samplePositions, currentSampleIndexMap) => {
31604
+ const lowestDts = [];
31605
+ for (const track of samplePositions) {
31606
+ const currentSampleIndex = currentSampleIndexMap[track.trackId] ?? 0;
31607
+ const currentSample = track.samplePositions[currentSampleIndex];
31608
+ if (currentSample && (lowestDts.length === 0 || currentSample.decodingTimestamp <= lowestDts[0].samplePosition.decodingTimestamp)) {
31609
+ lowestDts.push({
31610
+ samplePosition: currentSample,
31611
+ trackId: track.trackId,
31612
+ index: currentSampleIndex
31613
+ });
31614
+ }
31615
+ }
31616
+ return lowestDts;
31617
+ };
31557
31618
  var getLastMoofBox = (boxes) => {
31558
31619
  if (boxes) {
31559
31620
  const tfras = boxes.filter((b) => b.type === "tfra-box");
@@ -31823,116 +31884,6 @@ var getMoovAtom = async ({
31823
31884
  Log.verbose(state.logLevel, `Finished fetching moov atom in ${Date.now() - start}ms`);
31824
31885
  return moov;
31825
31886
  };
31826
- var MAX_SPREAD_IN_SECONDS = 8;
31827
- var getKey = (samplePositionTrack) => {
31828
- return `${samplePositionTrack.track.trackId}-${samplePositionTrack.samplePosition.decodingTimestamp}.${samplePositionTrack.samplePosition.offset}`;
31829
- };
31830
- var findBestJump = ({
31831
- sampleMap,
31832
- offsetsSorted,
31833
- visited,
31834
- progresses
31835
- }) => {
31836
- const minProgress = Math.min(...Object.values(progresses));
31837
- const trackNumberWithLowestProgress = Object.entries(progresses).find(([, progress]) => progress === minProgress)?.[0];
31838
- const firstSampleAboveMinProgress = offsetsSorted.findIndex((offset) => sampleMap.get(offset).track.trackId === Number(trackNumberWithLowestProgress) && !visited.has(getKey(sampleMap.get(offset))));
31839
- if (firstSampleAboveMinProgress === -1) {
31840
- const backup = offsetsSorted.findIndex((offset) => !visited.has(getKey(sampleMap.get(offset))));
31841
- if (backup === -1) {
31842
- throw new Error("this should not happen");
31843
- }
31844
- return backup;
31845
- }
31846
- return firstSampleAboveMinProgress;
31847
- };
31848
- var calculateJumpMarks = ({
31849
- sampleMap,
31850
- offsetsSorted,
31851
- trackIds,
31852
- endOfMdat
31853
- }) => {
31854
- const progresses = {};
31855
- for (const trackId of trackIds) {
31856
- progresses[trackId] = 0;
31857
- }
31858
- const jumpMarks = [];
31859
- let indexToVisit = 0;
31860
- const visited = new Set;
31861
- const increaseIndex = () => {
31862
- indexToVisit++;
31863
- if (indexToVisit >= offsetsSorted.length) {
31864
- throw new Error("should not roll over, should jump");
31865
- }
31866
- };
31867
- let lastVisitedSample = null;
31868
- const addJumpMark = ({
31869
- firstSampleAboveMinProgress
31870
- }) => {
31871
- if (!lastVisitedSample) {
31872
- throw new Error("no last visited sample");
31873
- }
31874
- const jumpMark = {
31875
- afterSampleWithOffset: lastVisitedSample.samplePosition.offset,
31876
- jumpToOffset: offsetsSorted[firstSampleAboveMinProgress]
31877
- };
31878
- if (firstSampleAboveMinProgress === offsetsSorted.indexOf(lastVisitedSample.samplePosition.offset) + 1) {
31879
- indexToVisit = firstSampleAboveMinProgress;
31880
- return;
31881
- }
31882
- indexToVisit = firstSampleAboveMinProgress;
31883
- jumpMarks.push(jumpMark);
31884
- };
31885
- const addFinalJumpIfNecessary = () => {
31886
- if (indexToVisit === offsetsSorted.length - 1) {
31887
- return;
31888
- }
31889
- jumpMarks.push({
31890
- afterSampleWithOffset: offsetsSorted[indexToVisit],
31891
- jumpToOffset: endOfMdat
31892
- });
31893
- };
31894
- const considerJump = () => {
31895
- const firstSampleAboveMinProgress = findBestJump({
31896
- sampleMap,
31897
- offsetsSorted,
31898
- visited,
31899
- progresses
31900
- });
31901
- addJumpMark({ firstSampleAboveMinProgress });
31902
- };
31903
- while (true) {
31904
- const currentSamplePosition = sampleMap.get(offsetsSorted[indexToVisit]);
31905
- const sampleKey = getKey(currentSamplePosition);
31906
- if (visited.has(sampleKey)) {
31907
- considerJump();
31908
- continue;
31909
- }
31910
- visited.add(sampleKey);
31911
- lastVisitedSample = currentSamplePosition;
31912
- if (visited.size === offsetsSorted.length) {
31913
- addFinalJumpIfNecessary();
31914
- break;
31915
- }
31916
- const timestamp = currentSamplePosition.samplePosition.decodingTimestamp / currentSamplePosition.track.originalTimescale;
31917
- progresses[currentSamplePosition.track.trackId] = timestamp;
31918
- const progressValues = Object.values(progresses);
31919
- const maxProgress = Math.max(...progressValues);
31920
- const minProgress = Math.min(...progressValues);
31921
- const spread = maxProgress - minProgress;
31922
- if (visited.size === offsetsSorted.length) {
31923
- addFinalJumpIfNecessary();
31924
- break;
31925
- }
31926
- if (spread > MAX_SPREAD_IN_SECONDS) {
31927
- considerJump();
31928
- } else if (indexToVisit === offsetsSorted.length - 1) {
31929
- considerJump();
31930
- } else {
31931
- increaseIndex();
31932
- }
31933
- }
31934
- return jumpMarks;
31935
- };
31936
31887
  var postprocessBytes = ({
31937
31888
  bytes,
31938
31889
  bigEndian,
@@ -31990,52 +31941,53 @@ var parseMdatSection = async (state) => {
31990
31941
  endOfMdat,
31991
31942
  state
31992
31943
  });
31944
+ const tracksFromMoov = getTracksFromMoovBox(moov);
31993
31945
  state.iso.moov.setMoovBox({
31994
31946
  moovBox: moov,
31995
31947
  precomputed: false
31996
31948
  });
31949
+ const existingTracks = state.callbacks.tracks.getTracks();
31950
+ for (const trackFromMoov of tracksFromMoov) {
31951
+ if (existingTracks.find((t) => t.trackId === trackFromMoov.trackId)) {
31952
+ continue;
31953
+ }
31954
+ if (trackFromMoov.type === "other") {
31955
+ continue;
31956
+ }
31957
+ state.callbacks.tracks.addTrack(trackFromMoov);
31958
+ }
31997
31959
  state.callbacks.tracks.setIsDone(state.logLevel);
31998
31960
  state.structure.getIsoStructure().boxes.push(moov);
31999
31961
  return parseMdatSection(state);
32000
31962
  }
31963
+ const tracks2 = state.callbacks.tracks.getTracks();
32001
31964
  if (!state.iso.flatSamples.getSamples(mediaSection.start)) {
32002
- const {
32003
- flatSamples: flatSamplesMap,
32004
- offsets,
32005
- trackIds
32006
- } = calculateFlatSamples({
31965
+ const samplePosition = calculateSamplePositions({
32007
31966
  state,
32008
- mediaSectionStart: mediaSection.start
32009
- });
32010
- const calcedJumpMarks = calculateJumpMarks({
32011
- sampleMap: flatSamplesMap,
32012
- offsetsSorted: offsets,
32013
- trackIds,
32014
- endOfMdat
31967
+ mediaSectionStart: mediaSection.start,
31968
+ trackIds: tracks2.map((t) => t.trackId)
32015
31969
  });
32016
- state.iso.flatSamples.setJumpMarks(mediaSection.start, calcedJumpMarks);
32017
- state.iso.flatSamples.setSamples(mediaSection.start, flatSamplesMap);
31970
+ state.iso.flatSamples.setSamples(mediaSection.start, samplePosition);
32018
31971
  }
32019
- const flatSamples = state.iso.flatSamples.getSamples(mediaSection.start);
32020
- const jumpMarks = state.iso.flatSamples.getJumpMarks(mediaSection.start);
32021
- const { iterator } = state;
32022
- const samplesWithIndex = flatSamples.get(iterator.counter.getOffset());
32023
- if (!samplesWithIndex) {
32024
- const offsets = Array.from(flatSamples.keys());
32025
- const nextSample_ = offsets.filter((s) => s > iterator.counter.getOffset()).sort((a, b) => a - b)[0];
32026
- if (nextSample_) {
32027
- iterator.discard(nextSample_ - iterator.counter.getOffset());
32028
- return null;
32029
- }
32030
- Log.verbose(state.logLevel, "Could not find sample at offset", iterator.counter.getOffset(), "skipping to end of mdat");
31972
+ const samplePositions = state.iso.flatSamples.getSamples(mediaSection.start);
31973
+ const sampleIndices = state.iso.flatSamples.getCurrentSampleIndices(mediaSection.start);
31974
+ const nextSampleArray = getSampleWithLowestDts(samplePositions, sampleIndices);
31975
+ if (nextSampleArray.length === 0) {
31976
+ Log.verbose(state.logLevel, "Iterated over all samples.", endOfMdat);
32031
31977
  return makeSkip(endOfMdat);
32032
31978
  }
32033
- if (samplesWithIndex.samplePosition.offset + samplesWithIndex.samplePosition.size > state.contentLength) {
32034
- Log.verbose(state.logLevel, "Sample is beyond the end of the file. Don't process it.", samplesWithIndex.samplePosition.offset + samplesWithIndex.samplePosition.size, endOfMdat);
31979
+ const exactMatch = nextSampleArray.find((s) => s.samplePosition.offset === state.iterator.counter.getOffset());
31980
+ const nextSample = exactMatch ?? nextSampleArray[0];
31981
+ if (nextSample.samplePosition.offset !== state.iterator.counter.getOffset()) {
31982
+ return makeSkip(nextSample.samplePosition.offset);
31983
+ }
31984
+ if (nextSample.samplePosition.offset + nextSample.samplePosition.size > state.contentLength) {
31985
+ Log.verbose(state.logLevel, "Sample is beyond the end of the file. Don't process it.", nextSample.samplePosition.offset + nextSample.samplePosition.size, endOfMdat);
32035
31986
  return makeSkip(endOfMdat);
32036
31987
  }
32037
- if (iterator.bytesRemaining() < samplesWithIndex.samplePosition.size) {
32038
- return makeFetchMoreData(samplesWithIndex.samplePosition.size - iterator.bytesRemaining());
31988
+ const { iterator } = state;
31989
+ if (iterator.bytesRemaining() < nextSample.samplePosition.size) {
31990
+ return makeFetchMoreData(nextSample.samplePosition.size - iterator.bytesRemaining());
32039
31991
  }
32040
31992
  const {
32041
31993
  timestamp: rawCts,
@@ -32045,21 +31997,22 @@ var parseMdatSection = async (state) => {
32045
31997
  offset,
32046
31998
  bigEndian,
32047
31999
  chunkSize
32048
- } = samplesWithIndex.samplePosition;
32000
+ } = nextSample.samplePosition;
32001
+ const track = tracks2.find((t) => t.trackId === nextSample.trackId);
32049
32002
  const {
32050
32003
  originalTimescale,
32051
32004
  startInSeconds,
32052
32005
  trackMediaTimeOffsetInTrackTimescale,
32053
32006
  timescale: trackTimescale
32054
- } = samplesWithIndex.track;
32007
+ } = track;
32055
32008
  const cts = rawCts + startInSeconds * originalTimescale - trackMediaTimeOffsetInTrackTimescale / trackTimescale * WEBCODECS_TIMESCALE;
32056
32009
  const dts = rawDts + startInSeconds * originalTimescale - trackMediaTimeOffsetInTrackTimescale / trackTimescale * WEBCODECS_TIMESCALE;
32057
32010
  const bytes = postprocessBytes({
32058
- bytes: iterator.getSlice(samplesWithIndex.samplePosition.size),
32011
+ bytes: iterator.getSlice(nextSample.samplePosition.size),
32059
32012
  bigEndian,
32060
32013
  chunkSize
32061
32014
  });
32062
- if (samplesWithIndex.track.type === "audio") {
32015
+ if (track.type === "audio") {
32063
32016
  const audioSample = convertAudioOrVideoSampleToWebCodecsTimestamps({
32064
32017
  sample: {
32065
32018
  data: bytes,
@@ -32073,10 +32026,10 @@ var parseMdatSection = async (state) => {
32073
32026
  });
32074
32027
  await state.callbacks.onAudioSample({
32075
32028
  audioSample,
32076
- trackId: samplesWithIndex.track.trackId
32029
+ trackId: track.trackId
32077
32030
  });
32078
32031
  }
32079
- if (samplesWithIndex.track.type === "video") {
32032
+ if (track.type === "video") {
32080
32033
  const nalUnitType = bytes[4] & 31;
32081
32034
  let isRecoveryPoint = false;
32082
32035
  if (nalUnitType === 6) {
@@ -32096,14 +32049,10 @@ var parseMdatSection = async (state) => {
32096
32049
  });
32097
32050
  await state.callbacks.onVideoSample({
32098
32051
  videoSample,
32099
- trackId: samplesWithIndex.track.trackId
32052
+ trackId: track.trackId
32100
32053
  });
32101
32054
  }
32102
- const jump = jumpMarks.find((j) => j.afterSampleWithOffset === offset);
32103
- if (jump) {
32104
- Log.verbose(state.logLevel, "Found jump mark", jump.jumpToOffset, "skipping to jump mark");
32105
- return makeSkip(jump.jumpToOffset);
32106
- }
32055
+ state.iso.flatSamples.setCurrentSampleIndex(mediaSection.start, nextSample.trackId, nextSample.index + 1);
32107
32056
  return null;
32108
32057
  };
32109
32058
  var parseIsoBaseMedia = async (state) => {
@@ -35995,7 +35944,8 @@ var parseLoop = async ({
35995
35944
  fields: state.fields,
35996
35945
  src: state.src,
35997
35946
  discardReadBytes: state.discardReadBytes,
35998
- prefetchCache: state.prefetchCache
35947
+ prefetchCache: state.prefetchCache,
35948
+ isoState: state.iso
35999
35949
  });
36000
35950
  state.timings.timeSeeking += Date.now() - seekStart;
36001
35951
  }
@@ -183,7 +183,7 @@ var renderContent = (Root) => {
183
183
  renderToDOM(/* @__PURE__ */ jsx("div", {
184
184
  children: /* @__PURE__ */ jsx(DelayedSpinner, {})
185
185
  }));
186
- import("./chunk-1g0vys7t.js").then(({ StudioInternals }) => {
186
+ import("./chunk-s0cbvv3s.js").then(({ StudioInternals }) => {
187
187
  renderToDOM(/* @__PURE__ */ jsx(StudioInternals.Studio, {
188
188
  readOnly: true,
189
189
  rootComponent: Root
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "url": "https://github.com/remotion-dev/remotion/tree/main/packages/studio"
4
4
  },
5
5
  "name": "@remotion/studio",
6
- "version": "4.0.333",
6
+ "version": "4.0.334",
7
7
  "description": "APIs for interacting with the Remotion Studio",
8
8
  "main": "dist",
9
9
  "sideEffects": false,
@@ -23,21 +23,21 @@
23
23
  "source-map": "0.7.3",
24
24
  "open": "^8.4.2",
25
25
  "zod": "3.22.3",
26
- "@remotion/media-utils": "4.0.333",
27
- "@remotion/media-parser": "4.0.333",
28
- "@remotion/renderer": "4.0.333",
29
- "@remotion/studio-shared": "4.0.333",
30
- "@remotion/zod-types": "4.0.333",
31
- "@remotion/player": "4.0.333",
32
- "@remotion/webcodecs": "4.0.333",
33
- "remotion": "4.0.333"
26
+ "@remotion/player": "4.0.334",
27
+ "@remotion/media-utils": "4.0.334",
28
+ "@remotion/media-parser": "4.0.334",
29
+ "@remotion/renderer": "4.0.334",
30
+ "@remotion/studio-shared": "4.0.334",
31
+ "@remotion/webcodecs": "4.0.334",
32
+ "@remotion/zod-types": "4.0.334",
33
+ "remotion": "4.0.334"
34
34
  },
35
35
  "devDependencies": {
36
36
  "react": "19.0.0",
37
37
  "react-dom": "19.0.0",
38
38
  "@types/semver": "^7.3.4",
39
39
  "eslint": "9.19.0",
40
- "@remotion/eslint-config-internal": "4.0.333"
40
+ "@remotion/eslint-config-internal": "4.0.334"
41
41
  },
42
42
  "publishConfig": {
43
43
  "access": "public"