mediabunny 1.0.5 → 1.0.6

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.
@@ -6224,6 +6224,9 @@ ${cue.notes ?? ""}`;
6224
6224
  return null;
6225
6225
  }
6226
6226
  reader.pos += 1;
6227
+ if (firstByte !== 255) {
6228
+ return null;
6229
+ }
6227
6230
  if ((secondByte & 224) !== 224) {
6228
6231
  return null;
6229
6232
  }
@@ -11823,6 +11826,7 @@ ${cue.notes ?? ""}`;
11823
11826
  fragmentLookupTable: null,
11824
11827
  currentFragmentState: null,
11825
11828
  fragments: [],
11829
+ fragmentsWithKeyFrame: [],
11826
11830
  editListPreviousSegmentDurations: 0,
11827
11831
  editListOffset: 0
11828
11832
  };
@@ -11911,7 +11915,8 @@ ${cue.notes ?? ""}`;
11911
11915
  continue;
11912
11916
  }
11913
11917
  if (mediaRate !== 1) {
11914
- throw new Error("Unsupported edit list: media rate must be 1.");
11918
+ console.warn("Unsupported edit list entry: media rate must be 1.");
11919
+ break;
11915
11920
  }
11916
11921
  track.editListPreviousSegmentDurations = previousSegmentDurations;
11917
11922
  track.editListOffset = mediaTime;
@@ -12099,7 +12104,8 @@ ${cue.notes ?? ""}`;
12099
12104
  } else if (sampleSize === 16) {
12100
12105
  track.info.codec = "pcm-s16be";
12101
12106
  } else {
12102
- throw new Error(`Unsupported sample size ${sampleSize} for codec 'twos'.`);
12107
+ console.warn(`Unsupported sample size ${sampleSize} for codec 'twos'.`);
12108
+ track.info.codec = null;
12103
12109
  }
12104
12110
  } else if (lowercaseBoxName === "sowt") {
12105
12111
  if (sampleSize === 8) {
@@ -12107,7 +12113,8 @@ ${cue.notes ?? ""}`;
12107
12113
  } else if (sampleSize === 16) {
12108
12114
  track.info.codec = "pcm-s16";
12109
12115
  } else {
12110
- throw new Error(`Unsupported sample size ${sampleSize} for codec 'sowt'.`);
12116
+ console.warn(`Unsupported sample size ${sampleSize} for codec 'sowt'.`);
12117
+ track.info.codec = null;
12111
12118
  }
12112
12119
  } else if (lowercaseBoxName === "raw ") {
12113
12120
  track.info.codec = "pcm-u8";
@@ -12327,7 +12334,8 @@ ${cue.notes ?? ""}`;
12327
12334
  } else if (pcmSampleSize === 32) {
12328
12335
  track.info.codec = "pcm-s32";
12329
12336
  } else {
12330
- throw new Error(`Invalid ipcm sample size ${pcmSampleSize}.`);
12337
+ console.warn(`Invalid ipcm sample size ${pcmSampleSize}.`);
12338
+ track.info.codec = null;
12331
12339
  }
12332
12340
  } else {
12333
12341
  if (pcmSampleSize === 16) {
@@ -12337,7 +12345,8 @@ ${cue.notes ?? ""}`;
12337
12345
  } else if (pcmSampleSize === 32) {
12338
12346
  track.info.codec = "pcm-s32be";
12339
12347
  } else {
12340
- throw new Error(`Invalid ipcm sample size ${pcmSampleSize}.`);
12348
+ console.warn(`Invalid ipcm sample size ${pcmSampleSize}.`);
12349
+ track.info.codec = null;
12341
12350
  }
12342
12351
  }
12343
12352
  } else if (track.info.codec === "pcm-f32be") {
@@ -12347,7 +12356,8 @@ ${cue.notes ?? ""}`;
12347
12356
  } else if (pcmSampleSize === 64) {
12348
12357
  track.info.codec = "pcm-f64";
12349
12358
  } else {
12350
- throw new Error(`Invalid fpcm sample size ${pcmSampleSize}.`);
12359
+ console.warn(`Invalid fpcm sample size ${pcmSampleSize}.`);
12360
+ track.info.codec = null;
12351
12361
  }
12352
12362
  } else {
12353
12363
  if (pcmSampleSize === 32) {
@@ -12355,7 +12365,8 @@ ${cue.notes ?? ""}`;
12355
12365
  } else if (pcmSampleSize === 64) {
12356
12366
  track.info.codec = "pcm-f64be";
12357
12367
  } else {
12358
- throw new Error(`Invalid fpcm sample size ${pcmSampleSize}.`);
12368
+ console.warn(`Invalid fpcm sample size ${pcmSampleSize}.`);
12369
+ track.info.codec = null;
12359
12370
  }
12360
12371
  }
12361
12372
  }
@@ -12505,9 +12516,24 @@ ${cue.notes ?? ""}`;
12505
12516
  break;
12506
12517
  case "stz2":
12507
12518
  {
12508
- throw new Error("Unsupported.");
12519
+ const track = this.currentTrack;
12520
+ assert(track);
12521
+ if (!track.sampleTable) {
12522
+ break;
12523
+ }
12524
+ this.metadataReader.pos += 4;
12525
+ this.metadataReader.pos += 3;
12526
+ const fieldSize = this.metadataReader.readU8();
12527
+ const sampleCount = this.metadataReader.readU32();
12528
+ const bytes2 = this.metadataReader.readBytes(Math.ceil(sampleCount * fieldSize / 8));
12529
+ const bitstream = new Bitstream(bytes2);
12530
+ for (let i = 0; i < sampleCount; i++) {
12531
+ const sampleSize = bitstream.readBits(fieldSize);
12532
+ track.sampleTable.sampleSizes.push(sampleSize);
12533
+ }
12509
12534
  }
12510
12535
  ;
12536
+ break;
12511
12537
  case "stss":
12512
12538
  {
12513
12539
  const track = this.currentTrack;
@@ -12705,6 +12731,15 @@ ${cue.notes ?? ""}`;
12705
12731
  (x) => x.moofOffset
12706
12732
  );
12707
12733
  this.currentTrack.fragments.splice(insertionIndex + 1, 0, this.currentFragment);
12734
+ const hasKeyFrame = trackData.firstKeyFrameTimestamp !== null;
12735
+ if (hasKeyFrame) {
12736
+ const insertionIndex2 = binarySearchLessOrEqual(
12737
+ this.currentTrack.fragmentsWithKeyFrame,
12738
+ this.currentFragment.moofOffset,
12739
+ (x) => x.moofOffset
12740
+ );
12741
+ this.currentTrack.fragmentsWithKeyFrame.splice(insertionIndex2 + 1, 0, this.currentFragment);
12742
+ }
12708
12743
  const { currentFragmentState } = this.currentTrack;
12709
12744
  assert(currentFragmentState);
12710
12745
  if (currentFragmentState.startTimestamp !== null) {
@@ -12791,7 +12826,8 @@ ${cue.notes ?? ""}`;
12791
12826
  assert(this.currentFragment);
12792
12827
  assert(track.currentFragmentState);
12793
12828
  if (this.currentFragment.trackData.has(track.id)) {
12794
- throw new Error("Can't have two trun boxes for the same track in one fragment.");
12829
+ console.warn("Can't have two trun boxes for the same track in one fragment. Ignoring...");
12830
+ break;
12795
12831
  }
12796
12832
  const version = this.metadataReader.readU8();
12797
12833
  const flags = this.metadataReader.readU24();
@@ -12819,6 +12855,7 @@ ${cue.notes ?? ""}`;
12819
12855
  const trackData = {
12820
12856
  startTimestamp: 0,
12821
12857
  endTimestamp: 0,
12858
+ firstKeyFrameTimestamp: null,
12822
12859
  samples: [],
12823
12860
  presentationTimestamps: [],
12824
12861
  startTimestampIsFinal: false
@@ -12869,11 +12906,16 @@ ${cue.notes ?? ""}`;
12869
12906
  currentTimestamp += sampleDuration;
12870
12907
  }
12871
12908
  trackData.presentationTimestamps = trackData.samples.map((x, i) => ({ presentationTimestamp: x.presentationTimestamp, sampleIndex: i })).sort((a, b) => a.presentationTimestamp - b.presentationTimestamp);
12872
- for (let i = 0; i < trackData.presentationTimestamps.length - 1; i++) {
12873
- const current = trackData.presentationTimestamps[i];
12874
- const next = trackData.presentationTimestamps[i + 1];
12875
- const duration = next.presentationTimestamp - current.presentationTimestamp;
12876
- trackData.samples[current.sampleIndex].duration = duration;
12909
+ for (let i = 0; i < trackData.presentationTimestamps.length; i++) {
12910
+ const currentEntry = trackData.presentationTimestamps[i];
12911
+ const currentSample = trackData.samples[currentEntry.sampleIndex];
12912
+ if (trackData.firstKeyFrameTimestamp === null && currentSample.isKeyFrame) {
12913
+ trackData.firstKeyFrameTimestamp = currentSample.presentationTimestamp;
12914
+ }
12915
+ if (i < trackData.presentationTimestamps.length - 1) {
12916
+ const nextEntry = trackData.presentationTimestamps[i + 1];
12917
+ currentSample.duration = nextEntry.presentationTimestamp - currentEntry.presentationTimestamp;
12918
+ }
12877
12919
  }
12878
12920
  const firstSample = trackData.samples[trackData.presentationTimestamps[0].sampleIndex];
12879
12921
  const lastSample = trackData.samples[last(trackData.presentationTimestamps).sampleIndex];
@@ -13072,7 +13114,7 @@ ${cue.notes ?? ""}`;
13072
13114
  while (currentFragment.nextFragment) {
13073
13115
  currentFragment = currentFragment.nextFragment;
13074
13116
  const trackData2 = currentFragment.trackData.get(this.internalTrack.id);
13075
- if (trackData2) {
13117
+ if (trackData2 && trackData2.firstKeyFrameTimestamp !== null) {
13076
13118
  const fragmentIndex2 = binarySearchExact(
13077
13119
  this.internalTrack.fragments,
13078
13120
  currentFragment.moofOffset,
@@ -13080,9 +13122,7 @@ ${cue.notes ?? ""}`;
13080
13122
  );
13081
13123
  assert(fragmentIndex2 !== -1);
13082
13124
  const keyFrameIndex = trackData2.samples.findIndex((x) => x.isKeyFrame);
13083
- if (keyFrameIndex === -1) {
13084
- throw new Error("Not supported: Fragment does not contain key sample.");
13085
- }
13125
+ assert(keyFrameIndex !== -1);
13086
13126
  return {
13087
13127
  fragmentIndex: fragmentIndex2,
13088
13128
  sampleIndex: keyFrameIndex,
@@ -13195,24 +13235,29 @@ ${cue.notes ?? ""}`;
13195
13235
  return { fragmentIndex, sampleIndex, correctSampleFound };
13196
13236
  }
13197
13237
  findKeySampleInFragmentsForTimestamp(timestampInTimescale) {
13198
- const fragmentIndex = binarySearchLessOrEqual(
13238
+ const indexInKeyFrameFragments = binarySearchLessOrEqual(
13199
13239
  // This array is technically not sorted by start timestamp, but for any reasonable file, it basically is.
13200
- this.internalTrack.fragments,
13240
+ this.internalTrack.fragmentsWithKeyFrame,
13201
13241
  timestampInTimescale,
13202
13242
  (x) => x.trackData.get(this.internalTrack.id).startTimestamp
13203
13243
  );
13244
+ let fragmentIndex = -1;
13204
13245
  let sampleIndex = -1;
13205
13246
  let correctSampleFound = false;
13206
- if (fragmentIndex !== -1) {
13207
- const fragment = this.internalTrack.fragments[fragmentIndex];
13247
+ if (indexInKeyFrameFragments !== -1) {
13248
+ const fragment = this.internalTrack.fragmentsWithKeyFrame[indexInKeyFrameFragments];
13249
+ fragmentIndex = binarySearchExact(
13250
+ this.internalTrack.fragments,
13251
+ fragment.moofOffset,
13252
+ (x) => x.moofOffset
13253
+ );
13254
+ assert(fragmentIndex !== -1);
13208
13255
  const trackData = fragment.trackData.get(this.internalTrack.id);
13209
13256
  const index = findLastIndex(trackData.presentationTimestamps, (x) => {
13210
13257
  const sample = trackData.samples[x.sampleIndex];
13211
13258
  return sample.isKeyFrame && x.presentationTimestamp <= timestampInTimescale;
13212
13259
  });
13213
- if (index === -1) {
13214
- throw new Error("Not supported: Fragment does not begin with a key sample.");
13215
- }
13260
+ assert(index !== -1);
13216
13261
  const entry = trackData.presentationTimestamps[index];
13217
13262
  sampleIndex = entry.sampleIndex;
13218
13263
  correctSampleFound = timestampInTimescale < trackData.endTimestamp;
@@ -13735,20 +13780,15 @@ ${cue.notes ?? ""}`;
13735
13780
  trackData.blocks = sortBlocksByReferences(trackData.blocks);
13736
13781
  }
13737
13782
  trackData.presentationTimestamps = trackData.blocks.map((block, i) => ({ timestamp: block.timestamp, blockIndex: i })).sort((a, b) => a.timestamp - b.timestamp);
13738
- let hasKeyFrame = false;
13739
13783
  for (let i = 0; i < trackData.presentationTimestamps.length; i++) {
13740
- const entry = trackData.presentationTimestamps[i];
13741
- const block = trackData.blocks[entry.blockIndex];
13742
- if (block.isKeyFrame) {
13743
- hasKeyFrame = true;
13744
- if (trackData.firstKeyFrameTimestamp === null && block.isKeyFrame) {
13745
- trackData.firstKeyFrameTimestamp = block.timestamp;
13746
- }
13784
+ const currentEntry = trackData.presentationTimestamps[i];
13785
+ const currentBlock = trackData.blocks[currentEntry.blockIndex];
13786
+ if (trackData.firstKeyFrameTimestamp === null && currentBlock.isKeyFrame) {
13787
+ trackData.firstKeyFrameTimestamp = currentBlock.timestamp;
13747
13788
  }
13748
13789
  if (i < trackData.presentationTimestamps.length - 1) {
13749
13790
  const nextEntry = trackData.presentationTimestamps[i + 1];
13750
- const nextBlock = trackData.blocks[nextEntry.blockIndex];
13751
- block.duration = nextBlock.timestamp - block.timestamp;
13791
+ currentBlock.duration = nextEntry.timestamp - currentBlock.timestamp;
13752
13792
  }
13753
13793
  }
13754
13794
  const firstBlock = trackData.blocks[trackData.presentationTimestamps[0].blockIndex];
@@ -13763,6 +13803,7 @@ ${cue.notes ?? ""}`;
13763
13803
  (x) => x.elementStartPos
13764
13804
  );
13765
13805
  track.clusters.splice(insertionIndex2 + 1, 0, cluster);
13806
+ const hasKeyFrame = trackData.firstKeyFrameTimestamp !== null;
13766
13807
  if (hasKeyFrame) {
13767
13808
  const insertionIndex3 = binarySearchLessOrEqual(
13768
13809
  track.clustersWithKeyFrame,
@@ -14801,7 +14842,7 @@ ${cue.notes ?? ""}`;
14801
14842
  readNextFrameHeader(until) {
14802
14843
  assert(this.fileSize);
14803
14844
  until ??= this.fileSize;
14804
- while (this.pos < until - FRAME_HEADER_SIZE) {
14845
+ while (this.pos <= until - FRAME_HEADER_SIZE) {
14805
14846
  const word = this.readU32();
14806
14847
  this.pos -= 4;
14807
14848
  const header = readFrameHeader(word, this);
@@ -15843,7 +15884,8 @@ ${cue.notes ?? ""}`;
15843
15884
  return true;
15844
15885
  }
15845
15886
  mp3Reader.pos = firstHeader.startPos + firstHeader.totalSize;
15846
- const secondHeader = mp3Reader.readNextFrameHeader(Math.min(framesStartPos + 4096, sourceSize));
15887
+ await mp3Reader.reader.loadRange(mp3Reader.pos, mp3Reader.pos + FRAME_HEADER_SIZE);
15888
+ const secondHeader = mp3Reader.readNextFrameHeader(mp3Reader.pos + FRAME_HEADER_SIZE);
15847
15889
  if (!secondHeader) {
15848
15890
  return false;
15849
15891
  }