mediabunny 1.1.1 → 1.2.0

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.
@@ -9411,6 +9411,18 @@ ${cue.notes ?? ""}`;
9411
9411
  this.pos += 4;
9412
9412
  return view2.getUint32(offset, this.littleEndian);
9413
9413
  }
9414
+ readU64() {
9415
+ let low;
9416
+ let high;
9417
+ if (this.littleEndian) {
9418
+ low = this.readU32();
9419
+ high = this.readU32();
9420
+ } else {
9421
+ high = this.readU32();
9422
+ low = this.readU32();
9423
+ }
9424
+ return high * 4294967296 + low;
9425
+ }
9414
9426
  readAscii(length) {
9415
9427
  const { view: view2, offset } = this.reader.getViewAndOffset(this.pos, this.pos + length);
9416
9428
  this.pos += length;
@@ -9438,25 +9450,38 @@ ${cue.notes ?? ""}`;
9438
9450
  return this.metadataPromise ??= (async () => {
9439
9451
  const actualFileSize = await this.metadataReader.reader.source.getSize();
9440
9452
  const riffType = this.metadataReader.readAscii(4);
9441
- this.metadataReader.littleEndian = riffType === "RIFF";
9442
- const totalFileSize = Math.min(this.metadataReader.readU32() + 8, actualFileSize);
9453
+ this.metadataReader.littleEndian = riffType !== "RIFX";
9454
+ const isRf64 = riffType === "RF64";
9455
+ const outerChunkSize = this.metadataReader.readU32();
9456
+ let totalFileSize = isRf64 ? actualFileSize : Math.min(outerChunkSize + 8, actualFileSize);
9443
9457
  const format = this.metadataReader.readAscii(4);
9444
9458
  if (format !== "WAVE") {
9445
9459
  throw new Error("Invalid WAVE file - wrong format");
9446
9460
  }
9447
9461
  this.metadataReader.pos = 12;
9462
+ let chunksRead = 0;
9463
+ let dataChunkSize = null;
9448
9464
  while (this.metadataReader.pos < totalFileSize) {
9449
9465
  await this.metadataReader.reader.loadRange(this.metadataReader.pos, this.metadataReader.pos + 8);
9450
9466
  const chunkId = this.metadataReader.readAscii(4);
9451
9467
  const chunkSize = this.metadataReader.readU32();
9452
9468
  const startPos = this.metadataReader.pos;
9469
+ if (isRf64 && chunksRead === 0 && chunkId !== "ds64") {
9470
+ throw new Error('Invalid RF64 file: First chunk must be "ds64".');
9471
+ }
9453
9472
  if (chunkId === "fmt ") {
9454
9473
  await this.parseFmtChunk(chunkSize);
9455
9474
  } else if (chunkId === "data") {
9475
+ dataChunkSize ??= chunkSize;
9456
9476
  this.dataStart = this.metadataReader.pos;
9457
- this.dataSize = Math.min(chunkSize, totalFileSize - this.dataStart);
9477
+ this.dataSize = Math.min(dataChunkSize, totalFileSize - this.dataStart);
9478
+ } else if (chunkId === "ds64") {
9479
+ const riffChunkSize = this.metadataReader.readU64();
9480
+ dataChunkSize = this.metadataReader.readU64();
9481
+ totalFileSize = Math.min(riffChunkSize + 8, actualFileSize);
9458
9482
  }
9459
9483
  this.metadataReader.pos = startPos + chunkSize + (chunkSize & 1);
9484
+ chunksRead++;
9460
9485
  }
9461
9486
  if (!this.audioInfo) {
9462
9487
  throw new Error('Invalid WAVE file - missing "fmt " chunk');
@@ -9651,13 +9676,18 @@ ${cue.notes ?? ""}`;
9651
9676
  this.helper = new Uint8Array(8);
9652
9677
  this.helperView = new DataView(this.helper.buffer);
9653
9678
  }
9679
+ writeU16(value) {
9680
+ this.helperView.setUint16(0, value, true);
9681
+ this.writer.write(this.helper.subarray(0, 2));
9682
+ }
9654
9683
  writeU32(value) {
9655
9684
  this.helperView.setUint32(0, value, true);
9656
9685
  this.writer.write(this.helper.subarray(0, 4));
9657
9686
  }
9658
- writeU16(value) {
9659
- this.helperView.setUint16(0, value, true);
9660
- this.writer.write(this.helper.subarray(0, 2));
9687
+ writeU64(value) {
9688
+ this.helperView.setUint32(0, value, true);
9689
+ this.helperView.setUint32(4, Math.floor(value / 2 ** 32), true);
9690
+ this.writer.write(this.helper);
9661
9691
  }
9662
9692
  writeAscii(text) {
9663
9693
  this.writer.write(new TextEncoder().encode(text));
@@ -9670,9 +9700,12 @@ ${cue.notes ?? ""}`;
9670
9700
  super(output);
9671
9701
  this.headerWritten = false;
9672
9702
  this.dataSize = 0;
9703
+ this.sampleRate = null;
9704
+ this.sampleCount = 0;
9673
9705
  this.format = format;
9674
9706
  this.writer = output._writer;
9675
9707
  this.riffWriter = new RiffWriter(output._writer);
9708
+ this.isRf64 = !!format._options.large;
9676
9709
  }
9677
9710
  async start() {
9678
9711
  }
@@ -9690,11 +9723,18 @@ ${cue.notes ?? ""}`;
9690
9723
  assert(meta);
9691
9724
  assert(meta.decoderConfig);
9692
9725
  this.writeHeader(track, meta.decoderConfig);
9726
+ this.sampleRate = meta.decoderConfig.sampleRate;
9693
9727
  this.headerWritten = true;
9694
9728
  }
9695
9729
  this.validateAndNormalizeTimestamp(track, packet.timestamp, packet.type === "key");
9730
+ if (!this.isRf64 && this.writer.getPos() + packet.data.byteLength >= 2 ** 32) {
9731
+ throw new Error(
9732
+ "Adding more audio data would exceed the maximum RIFF size of 4 GiB. To write larger files, use RF64 by setting `large: true` in the WavOutputFormatOptions."
9733
+ );
9734
+ }
9696
9735
  this.writer.write(packet.data);
9697
9736
  this.dataSize += packet.data.byteLength;
9737
+ this.sampleCount += Math.round(packet.duration * this.sampleRate);
9698
9738
  await this.writer.flush();
9699
9739
  } finally {
9700
9740
  release();
@@ -9722,9 +9762,21 @@ ${cue.notes ?? ""}`;
9722
9762
  const channels = config.numberOfChannels;
9723
9763
  const sampleRate = config.sampleRate;
9724
9764
  const blockSize = pcmInfo.sampleSize * channels;
9725
- this.riffWriter.writeAscii("RIFF");
9726
- this.riffWriter.writeU32(0);
9765
+ this.riffWriter.writeAscii(this.isRf64 ? "RF64" : "RIFF");
9766
+ if (this.isRf64) {
9767
+ this.riffWriter.writeU32(4294967295);
9768
+ } else {
9769
+ this.riffWriter.writeU32(0);
9770
+ }
9727
9771
  this.riffWriter.writeAscii("WAVE");
9772
+ if (this.isRf64) {
9773
+ this.riffWriter.writeAscii("ds64");
9774
+ this.riffWriter.writeU32(28);
9775
+ this.riffWriter.writeU64(0);
9776
+ this.riffWriter.writeU64(0);
9777
+ this.riffWriter.writeU64(0);
9778
+ this.riffWriter.writeU32(0);
9779
+ }
9728
9780
  this.riffWriter.writeAscii("fmt ");
9729
9781
  this.riffWriter.writeU32(16);
9730
9782
  this.riffWriter.writeU16(format);
@@ -9734,7 +9786,11 @@ ${cue.notes ?? ""}`;
9734
9786
  this.riffWriter.writeU16(blockSize);
9735
9787
  this.riffWriter.writeU16(8 * pcmInfo.sampleSize);
9736
9788
  this.riffWriter.writeAscii("data");
9737
- this.riffWriter.writeU32(0);
9789
+ if (this.isRf64) {
9790
+ this.riffWriter.writeU32(4294967295);
9791
+ } else {
9792
+ this.riffWriter.writeU32(0);
9793
+ }
9738
9794
  if (this.format._options.onHeader) {
9739
9795
  const { data, start } = this.writer.stopTrackingWrites();
9740
9796
  this.format._options.onHeader(data, start);
@@ -9743,10 +9799,19 @@ ${cue.notes ?? ""}`;
9743
9799
  async finalize() {
9744
9800
  const release = await this.mutex.acquire();
9745
9801
  const endPos = this.writer.getPos();
9746
- this.writer.seek(4);
9747
- this.riffWriter.writeU32(this.dataSize + 36);
9748
- this.writer.seek(40);
9749
- this.riffWriter.writeU32(this.dataSize);
9802
+ if (this.isRf64) {
9803
+ this.writer.seek(20);
9804
+ this.riffWriter.writeU64(endPos - 8);
9805
+ this.writer.seek(28);
9806
+ this.riffWriter.writeU64(this.dataSize);
9807
+ this.writer.seek(36);
9808
+ this.riffWriter.writeU64(this.sampleCount);
9809
+ } else {
9810
+ this.writer.seek(4);
9811
+ this.riffWriter.writeU32(endPos - 8);
9812
+ this.writer.seek(40);
9813
+ this.riffWriter.writeU32(this.dataSize);
9814
+ }
9750
9815
  this.writer.seek(endPos);
9751
9816
  release();
9752
9817
  }
@@ -10005,6 +10070,9 @@ ${cue.notes ?? ""}`;
10005
10070
  if (!options || typeof options !== "object") {
10006
10071
  throw new TypeError("options must be an object.");
10007
10072
  }
10073
+ if (options.large !== void 0 && typeof options.large !== "boolean") {
10074
+ throw new TypeError("options.large, when provided, must be a boolean.");
10075
+ }
10008
10076
  if (options.onHeader !== void 0 && typeof options.onHeader !== "function") {
10009
10077
  throw new TypeError("options.onHeader, when provided, must be a function.");
10010
10078
  }
@@ -15973,7 +16041,7 @@ ${cue.notes ?? ""}`;
15973
16041
  }
15974
16042
  const riffReader = new RiffReader(input._mainReader);
15975
16043
  const riffType = riffReader.readAscii(4);
15976
- if (riffType !== "RIFF" && riffType !== "RIFX") {
16044
+ if (riffType !== "RIFF" && riffType !== "RIFX" && riffType !== "RF64") {
15977
16045
  return false;
15978
16046
  }
15979
16047
  riffReader.pos = 8;