@remotion/media-parser 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.
@@ -8034,7 +8034,8 @@ var performSeek = async ({
8034
8034
  src,
8035
8035
  discardReadBytes,
8036
8036
  fields,
8037
- prefetchCache
8037
+ prefetchCache,
8038
+ isoState
8038
8039
  }) => {
8039
8040
  const byteInMediaSection = isByteInMediaSection({
8040
8041
  position: seekTo,
@@ -8098,6 +8099,9 @@ var performSeek = async ({
8098
8099
  prefetchCache
8099
8100
  });
8100
8101
  }
8102
+ if (userInitiated) {
8103
+ isoState.flatSamples.updateAfterSeek(seekTo);
8104
+ }
8101
8105
  await controller._internals.checkForAbortAndPause();
8102
8106
  };
8103
8107
 
@@ -8276,7 +8280,8 @@ var workOnSeekRequest = async (options) => {
8276
8280
  src,
8277
8281
  discardReadBytes,
8278
8282
  fields,
8279
- prefetchCache
8283
+ prefetchCache,
8284
+ isoState
8280
8285
  });
8281
8286
  return;
8282
8287
  }
@@ -8296,7 +8301,8 @@ var workOnSeekRequest = async (options) => {
8296
8301
  src,
8297
8302
  discardReadBytes,
8298
8303
  fields,
8299
- prefetchCache
8304
+ prefetchCache,
8305
+ isoState
8300
8306
  });
8301
8307
  const { hasChanged } = controller._internals.seekSignal.clearSeekIfStillSame(seek2);
8302
8308
  if (hasChanged) {
@@ -9406,9 +9412,10 @@ var parseFlac = ({
9406
9412
  };
9407
9413
 
9408
9414
  // src/state/iso-base-media/cached-sample-positions.ts
9409
- var calculateFlatSamples = ({
9415
+ var calculateSamplePositions = ({
9410
9416
  state,
9411
- mediaSectionStart
9417
+ mediaSectionStart,
9418
+ trackIds
9412
9419
  }) => {
9413
9420
  const tracks2 = getTracks(state, true);
9414
9421
  const moofBoxes = getMoofBoxes(state.structure.getIsoStructure().boxes);
@@ -9430,11 +9437,13 @@ var calculateFlatSamples = ({
9430
9437
  if (!moov) {
9431
9438
  throw new Error("No moov box found");
9432
9439
  }
9433
- const offsets = [];
9434
- const trackIds = [];
9435
- const map = new Map;
9440
+ const trackIdAndSamplePositions = [];
9436
9441
  for (const track of tracks2) {
9437
9442
  const trakBox = getTrakBoxByTrackId(moov, track.trackId);
9443
+ if (!trackIds.includes(track.trackId)) {
9444
+ Log.verbose(state.logLevel, "Skipping calculating sample positions for track", track.trackId);
9445
+ continue;
9446
+ }
9438
9447
  if (!trakBox) {
9439
9448
  throw new Error("No trak box found");
9440
9449
  }
@@ -9444,36 +9453,88 @@ var calculateFlatSamples = ({
9444
9453
  moofComplete,
9445
9454
  trexBoxes: getTrexBoxes(moov)
9446
9455
  });
9447
- trackIds.push(track.trackId);
9448
- for (const samplePosition of samplePositions) {
9449
- offsets.push(samplePosition.offset);
9450
- map.set(samplePosition.offset, {
9451
- track,
9452
- samplePosition
9453
- });
9456
+ trackIdAndSamplePositions.push({
9457
+ trackId: track.trackId,
9458
+ samplePositions
9459
+ });
9460
+ }
9461
+ return trackIdAndSamplePositions;
9462
+ };
9463
+ var updateSampleIndicesAfterSeek = ({
9464
+ samplePositionsForMdatStart,
9465
+ seekedByte
9466
+ }) => {
9467
+ const currentSampleIndices = {};
9468
+ const keys = Object.keys(samplePositionsForMdatStart).map(Number).sort();
9469
+ const mdat = keys.find((key) => seekedByte >= key);
9470
+ if (!mdat) {
9471
+ return currentSampleIndices;
9472
+ }
9473
+ const samplePositions = samplePositionsForMdatStart[mdat];
9474
+ if (!samplePositions) {
9475
+ return currentSampleIndices;
9476
+ }
9477
+ for (const track of samplePositions) {
9478
+ const currentSampleIndex = track.samplePositions.findIndex((sample) => sample.offset >= seekedByte);
9479
+ if (!currentSampleIndices[mdat]) {
9480
+ currentSampleIndices[mdat] = {};
9481
+ }
9482
+ if (!currentSampleIndices[mdat][track.trackId]) {
9483
+ currentSampleIndices[mdat][track.trackId] = 0;
9484
+ }
9485
+ if (currentSampleIndex === -1) {
9486
+ currentSampleIndices[mdat][track.trackId] = track.samplePositions.length;
9487
+ } else {
9488
+ currentSampleIndices[mdat][track.trackId] = currentSampleIndex;
9454
9489
  }
9455
9490
  }
9456
- offsets.sort((a, b) => a - b);
9457
- return { flatSamples: map, offsets, trackIds };
9491
+ return currentSampleIndices;
9458
9492
  };
9459
9493
  var cachedSamplePositionsState = () => {
9460
- const cachedForMdatStart = {};
9461
- const jumpMarksForMdatStart = {};
9494
+ const samplePositionsForMdatStart = {};
9495
+ let currentSampleIndex = {};
9462
9496
  return {
9463
9497
  getSamples: (mdatStart) => {
9464
- return cachedForMdatStart[mdatStart] ?? null;
9498
+ return samplePositionsForMdatStart[mdatStart] ?? null;
9465
9499
  },
9466
9500
  setSamples: (mdatStart, samples) => {
9467
- cachedForMdatStart[mdatStart] = samples;
9501
+ samplePositionsForMdatStart[mdatStart] = samples;
9468
9502
  },
9469
- setJumpMarks: (mdatStart, marks) => {
9470
- jumpMarksForMdatStart[mdatStart] = marks;
9503
+ setCurrentSampleIndex: (mdatStart, trackId, index) => {
9504
+ if (!currentSampleIndex[mdatStart]) {
9505
+ currentSampleIndex[mdatStart] = {};
9506
+ }
9507
+ if (!currentSampleIndex[mdatStart][trackId]) {
9508
+ currentSampleIndex[mdatStart][trackId] = 0;
9509
+ }
9510
+ currentSampleIndex[mdatStart][trackId] = index;
9471
9511
  },
9472
- getJumpMarks: (mdatStart) => {
9473
- return jumpMarksForMdatStart[mdatStart];
9512
+ getCurrentSampleIndices: (mdatStart) => {
9513
+ return currentSampleIndex[mdatStart] ?? {};
9514
+ },
9515
+ updateAfterSeek: (seekedByte) => {
9516
+ currentSampleIndex = updateSampleIndicesAfterSeek({
9517
+ samplePositionsForMdatStart,
9518
+ seekedByte
9519
+ });
9474
9520
  }
9475
9521
  };
9476
9522
  };
9523
+ var getSampleWithLowestDts = (samplePositions, currentSampleIndexMap) => {
9524
+ const lowestDts = [];
9525
+ for (const track of samplePositions) {
9526
+ const currentSampleIndex = currentSampleIndexMap[track.trackId] ?? 0;
9527
+ const currentSample = track.samplePositions[currentSampleIndex];
9528
+ if (currentSample && (lowestDts.length === 0 || currentSample.decodingTimestamp <= lowestDts[0].samplePosition.decodingTimestamp)) {
9529
+ lowestDts.push({
9530
+ samplePosition: currentSample,
9531
+ trackId: track.trackId,
9532
+ index: currentSampleIndex
9533
+ });
9534
+ }
9535
+ }
9536
+ return lowestDts;
9537
+ };
9477
9538
 
9478
9539
  // src/state/iso-base-media/last-moof-box.ts
9479
9540
  var getLastMoofBox = (boxes) => {
@@ -11830,118 +11891,6 @@ var getMoovAtom = async ({
11830
11891
  return moov;
11831
11892
  };
11832
11893
 
11833
- // src/containers/iso-base-media/mdat/calculate-jump-marks.ts
11834
- var MAX_SPREAD_IN_SECONDS = 8;
11835
- var getKey = (samplePositionTrack) => {
11836
- return `${samplePositionTrack.track.trackId}-${samplePositionTrack.samplePosition.decodingTimestamp}.${samplePositionTrack.samplePosition.offset}`;
11837
- };
11838
- var findBestJump = ({
11839
- sampleMap,
11840
- offsetsSorted,
11841
- visited,
11842
- progresses
11843
- }) => {
11844
- const minProgress = Math.min(...Object.values(progresses));
11845
- const trackNumberWithLowestProgress = Object.entries(progresses).find(([, progress]) => progress === minProgress)?.[0];
11846
- const firstSampleAboveMinProgress = offsetsSorted.findIndex((offset) => sampleMap.get(offset).track.trackId === Number(trackNumberWithLowestProgress) && !visited.has(getKey(sampleMap.get(offset))));
11847
- if (firstSampleAboveMinProgress === -1) {
11848
- const backup = offsetsSorted.findIndex((offset) => !visited.has(getKey(sampleMap.get(offset))));
11849
- if (backup === -1) {
11850
- throw new Error("this should not happen");
11851
- }
11852
- return backup;
11853
- }
11854
- return firstSampleAboveMinProgress;
11855
- };
11856
- var calculateJumpMarks = ({
11857
- sampleMap,
11858
- offsetsSorted,
11859
- trackIds,
11860
- endOfMdat
11861
- }) => {
11862
- const progresses = {};
11863
- for (const trackId of trackIds) {
11864
- progresses[trackId] = 0;
11865
- }
11866
- const jumpMarks = [];
11867
- let indexToVisit = 0;
11868
- const visited = new Set;
11869
- const increaseIndex = () => {
11870
- indexToVisit++;
11871
- if (indexToVisit >= offsetsSorted.length) {
11872
- throw new Error("should not roll over, should jump");
11873
- }
11874
- };
11875
- let lastVisitedSample = null;
11876
- const addJumpMark = ({
11877
- firstSampleAboveMinProgress
11878
- }) => {
11879
- if (!lastVisitedSample) {
11880
- throw new Error("no last visited sample");
11881
- }
11882
- const jumpMark = {
11883
- afterSampleWithOffset: lastVisitedSample.samplePosition.offset,
11884
- jumpToOffset: offsetsSorted[firstSampleAboveMinProgress]
11885
- };
11886
- if (firstSampleAboveMinProgress === offsetsSorted.indexOf(lastVisitedSample.samplePosition.offset) + 1) {
11887
- indexToVisit = firstSampleAboveMinProgress;
11888
- return;
11889
- }
11890
- indexToVisit = firstSampleAboveMinProgress;
11891
- jumpMarks.push(jumpMark);
11892
- };
11893
- const addFinalJumpIfNecessary = () => {
11894
- if (indexToVisit === offsetsSorted.length - 1) {
11895
- return;
11896
- }
11897
- jumpMarks.push({
11898
- afterSampleWithOffset: offsetsSorted[indexToVisit],
11899
- jumpToOffset: endOfMdat
11900
- });
11901
- };
11902
- const considerJump = () => {
11903
- const firstSampleAboveMinProgress = findBestJump({
11904
- sampleMap,
11905
- offsetsSorted,
11906
- visited,
11907
- progresses
11908
- });
11909
- addJumpMark({ firstSampleAboveMinProgress });
11910
- };
11911
- while (true) {
11912
- const currentSamplePosition = sampleMap.get(offsetsSorted[indexToVisit]);
11913
- const sampleKey = getKey(currentSamplePosition);
11914
- if (visited.has(sampleKey)) {
11915
- considerJump();
11916
- continue;
11917
- }
11918
- visited.add(sampleKey);
11919
- lastVisitedSample = currentSamplePosition;
11920
- if (visited.size === offsetsSorted.length) {
11921
- addFinalJumpIfNecessary();
11922
- break;
11923
- }
11924
- const timestamp = currentSamplePosition.samplePosition.decodingTimestamp / currentSamplePosition.track.originalTimescale;
11925
- progresses[currentSamplePosition.track.trackId] = timestamp;
11926
- const progressValues = Object.values(progresses);
11927
- const maxProgress = Math.max(...progressValues);
11928
- const minProgress = Math.min(...progressValues);
11929
- const spread = maxProgress - minProgress;
11930
- if (visited.size === offsetsSorted.length) {
11931
- addFinalJumpIfNecessary();
11932
- break;
11933
- }
11934
- if (spread > MAX_SPREAD_IN_SECONDS) {
11935
- considerJump();
11936
- } else if (indexToVisit === offsetsSorted.length - 1) {
11937
- considerJump();
11938
- } else {
11939
- increaseIndex();
11940
- }
11941
- }
11942
- return jumpMarks;
11943
- };
11944
-
11945
11894
  // src/containers/iso-base-media/mdat/postprocess-bytes.ts
11946
11895
  var postprocessBytes = ({
11947
11896
  bytes,
@@ -12002,52 +11951,53 @@ var parseMdatSection = async (state) => {
12002
11951
  endOfMdat,
12003
11952
  state
12004
11953
  });
11954
+ const tracksFromMoov = getTracksFromMoovBox(moov);
12005
11955
  state.iso.moov.setMoovBox({
12006
11956
  moovBox: moov,
12007
11957
  precomputed: false
12008
11958
  });
11959
+ const existingTracks = state.callbacks.tracks.getTracks();
11960
+ for (const trackFromMoov of tracksFromMoov) {
11961
+ if (existingTracks.find((t) => t.trackId === trackFromMoov.trackId)) {
11962
+ continue;
11963
+ }
11964
+ if (trackFromMoov.type === "other") {
11965
+ continue;
11966
+ }
11967
+ state.callbacks.tracks.addTrack(trackFromMoov);
11968
+ }
12009
11969
  state.callbacks.tracks.setIsDone(state.logLevel);
12010
11970
  state.structure.getIsoStructure().boxes.push(moov);
12011
11971
  return parseMdatSection(state);
12012
11972
  }
11973
+ const tracks2 = state.callbacks.tracks.getTracks();
12013
11974
  if (!state.iso.flatSamples.getSamples(mediaSection.start)) {
12014
- const {
12015
- flatSamples: flatSamplesMap,
12016
- offsets,
12017
- trackIds
12018
- } = calculateFlatSamples({
11975
+ const samplePosition = calculateSamplePositions({
12019
11976
  state,
12020
- mediaSectionStart: mediaSection.start
12021
- });
12022
- const calcedJumpMarks = calculateJumpMarks({
12023
- sampleMap: flatSamplesMap,
12024
- offsetsSorted: offsets,
12025
- trackIds,
12026
- endOfMdat
11977
+ mediaSectionStart: mediaSection.start,
11978
+ trackIds: tracks2.map((t) => t.trackId)
12027
11979
  });
12028
- state.iso.flatSamples.setJumpMarks(mediaSection.start, calcedJumpMarks);
12029
- state.iso.flatSamples.setSamples(mediaSection.start, flatSamplesMap);
11980
+ state.iso.flatSamples.setSamples(mediaSection.start, samplePosition);
12030
11981
  }
12031
- const flatSamples = state.iso.flatSamples.getSamples(mediaSection.start);
12032
- const jumpMarks = state.iso.flatSamples.getJumpMarks(mediaSection.start);
12033
- const { iterator } = state;
12034
- const samplesWithIndex = flatSamples.get(iterator.counter.getOffset());
12035
- if (!samplesWithIndex) {
12036
- const offsets = Array.from(flatSamples.keys());
12037
- const nextSample_ = offsets.filter((s) => s > iterator.counter.getOffset()).sort((a, b) => a - b)[0];
12038
- if (nextSample_) {
12039
- iterator.discard(nextSample_ - iterator.counter.getOffset());
12040
- return null;
12041
- }
12042
- Log.verbose(state.logLevel, "Could not find sample at offset", iterator.counter.getOffset(), "skipping to end of mdat");
11982
+ const samplePositions = state.iso.flatSamples.getSamples(mediaSection.start);
11983
+ const sampleIndices = state.iso.flatSamples.getCurrentSampleIndices(mediaSection.start);
11984
+ const nextSampleArray = getSampleWithLowestDts(samplePositions, sampleIndices);
11985
+ if (nextSampleArray.length === 0) {
11986
+ Log.verbose(state.logLevel, "Iterated over all samples.", endOfMdat);
12043
11987
  return makeSkip(endOfMdat);
12044
11988
  }
12045
- if (samplesWithIndex.samplePosition.offset + samplesWithIndex.samplePosition.size > state.contentLength) {
12046
- Log.verbose(state.logLevel, "Sample is beyond the end of the file. Don't process it.", samplesWithIndex.samplePosition.offset + samplesWithIndex.samplePosition.size, endOfMdat);
11989
+ const exactMatch = nextSampleArray.find((s) => s.samplePosition.offset === state.iterator.counter.getOffset());
11990
+ const nextSample = exactMatch ?? nextSampleArray[0];
11991
+ if (nextSample.samplePosition.offset !== state.iterator.counter.getOffset()) {
11992
+ return makeSkip(nextSample.samplePosition.offset);
11993
+ }
11994
+ if (nextSample.samplePosition.offset + nextSample.samplePosition.size > state.contentLength) {
11995
+ Log.verbose(state.logLevel, "Sample is beyond the end of the file. Don't process it.", nextSample.samplePosition.offset + nextSample.samplePosition.size, endOfMdat);
12047
11996
  return makeSkip(endOfMdat);
12048
11997
  }
12049
- if (iterator.bytesRemaining() < samplesWithIndex.samplePosition.size) {
12050
- return makeFetchMoreData(samplesWithIndex.samplePosition.size - iterator.bytesRemaining());
11998
+ const { iterator } = state;
11999
+ if (iterator.bytesRemaining() < nextSample.samplePosition.size) {
12000
+ return makeFetchMoreData(nextSample.samplePosition.size - iterator.bytesRemaining());
12051
12001
  }
12052
12002
  const {
12053
12003
  timestamp: rawCts,
@@ -12057,21 +12007,22 @@ var parseMdatSection = async (state) => {
12057
12007
  offset,
12058
12008
  bigEndian,
12059
12009
  chunkSize
12060
- } = samplesWithIndex.samplePosition;
12010
+ } = nextSample.samplePosition;
12011
+ const track = tracks2.find((t) => t.trackId === nextSample.trackId);
12061
12012
  const {
12062
12013
  originalTimescale,
12063
12014
  startInSeconds,
12064
12015
  trackMediaTimeOffsetInTrackTimescale,
12065
12016
  timescale: trackTimescale
12066
- } = samplesWithIndex.track;
12017
+ } = track;
12067
12018
  const cts = rawCts + startInSeconds * originalTimescale - trackMediaTimeOffsetInTrackTimescale / trackTimescale * WEBCODECS_TIMESCALE;
12068
12019
  const dts = rawDts + startInSeconds * originalTimescale - trackMediaTimeOffsetInTrackTimescale / trackTimescale * WEBCODECS_TIMESCALE;
12069
12020
  const bytes = postprocessBytes({
12070
- bytes: iterator.getSlice(samplesWithIndex.samplePosition.size),
12021
+ bytes: iterator.getSlice(nextSample.samplePosition.size),
12071
12022
  bigEndian,
12072
12023
  chunkSize
12073
12024
  });
12074
- if (samplesWithIndex.track.type === "audio") {
12025
+ if (track.type === "audio") {
12075
12026
  const audioSample = convertAudioOrVideoSampleToWebCodecsTimestamps({
12076
12027
  sample: {
12077
12028
  data: bytes,
@@ -12085,10 +12036,10 @@ var parseMdatSection = async (state) => {
12085
12036
  });
12086
12037
  await state.callbacks.onAudioSample({
12087
12038
  audioSample,
12088
- trackId: samplesWithIndex.track.trackId
12039
+ trackId: track.trackId
12089
12040
  });
12090
12041
  }
12091
- if (samplesWithIndex.track.type === "video") {
12042
+ if (track.type === "video") {
12092
12043
  const nalUnitType = bytes[4] & 31;
12093
12044
  let isRecoveryPoint = false;
12094
12045
  if (nalUnitType === 6) {
@@ -12108,14 +12059,10 @@ var parseMdatSection = async (state) => {
12108
12059
  });
12109
12060
  await state.callbacks.onVideoSample({
12110
12061
  videoSample,
12111
- trackId: samplesWithIndex.track.trackId
12062
+ trackId: track.trackId
12112
12063
  });
12113
12064
  }
12114
- const jump = jumpMarks.find((j) => j.afterSampleWithOffset === offset);
12115
- if (jump) {
12116
- Log.verbose(state.logLevel, "Found jump mark", jump.jumpToOffset, "skipping to jump mark");
12117
- return makeSkip(jump.jumpToOffset);
12118
- }
12065
+ state.iso.flatSamples.setCurrentSampleIndex(mediaSection.start, nextSample.trackId, nextSample.index + 1);
12119
12066
  return null;
12120
12067
  };
12121
12068
 
@@ -16203,7 +16150,8 @@ var parseLoop = async ({
16203
16150
  fields: state.fields,
16204
16151
  src: state.src,
16205
16152
  discardReadBytes: state.discardReadBytes,
16206
- prefetchCache: state.prefetchCache
16153
+ prefetchCache: state.prefetchCache,
16154
+ isoState: state.iso
16207
16155
  });
16208
16156
  state.timings.timeSeeking += Date.now() - seekStart;
16209
16157
  }