mediabunny 1.17.0 → 1.17.2

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.
@@ -7906,37 +7906,158 @@ ${cue.notes ?? ""}`;
7906
7906
 
7907
7907
  // shared/mp3-misc.ts
7908
7908
  var FRAME_HEADER_SIZE = 4;
7909
- var MPEG_V1_BITRATES = {
7910
- // Layer 3
7911
- 1: [-1, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1],
7912
- // Layer 2
7913
- 2: [-1, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, -1],
7914
- // Layer 1
7915
- 3: [-1, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1]
7916
- };
7917
- var MPEG_V2_BITRATES = {
7918
- // Layer 3
7919
- 1: [-1, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, -1],
7920
- // Layer 2
7921
- 2: [-1, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1],
7922
- // Layer 1
7923
- 3: [-1, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1]
7924
- };
7925
- var SAMPLING_RATES = {
7926
- // MPEG Version 2.5
7927
- 0: [11025, 12e3, 8e3, -1],
7928
- // MPEG Version 2 (ISO/IEC 13818-3)
7929
- 2: [22050, 24e3, 16e3, -1],
7930
- // MPEG Version 1 (ISO/IEC 11172-3)
7931
- 3: [44100, 48e3, 32e3, -1]
7932
- };
7909
+ var SAMPLING_RATES = [44100, 48e3, 32e3];
7910
+ var KILOBIT_RATES = [
7911
+ // lowSamplingFrequency === 0
7912
+ -1,
7913
+ -1,
7914
+ -1,
7915
+ -1,
7916
+ -1,
7917
+ -1,
7918
+ -1,
7919
+ -1,
7920
+ -1,
7921
+ -1,
7922
+ -1,
7923
+ -1,
7924
+ -1,
7925
+ -1,
7926
+ -1,
7927
+ -1,
7928
+ // layer = 0
7929
+ -1,
7930
+ 32,
7931
+ 40,
7932
+ 48,
7933
+ 56,
7934
+ 64,
7935
+ 80,
7936
+ 96,
7937
+ 112,
7938
+ 128,
7939
+ 160,
7940
+ 192,
7941
+ 224,
7942
+ 256,
7943
+ 320,
7944
+ -1,
7945
+ // layer 1
7946
+ -1,
7947
+ 32,
7948
+ 48,
7949
+ 56,
7950
+ 64,
7951
+ 80,
7952
+ 96,
7953
+ 112,
7954
+ 128,
7955
+ 160,
7956
+ 192,
7957
+ 224,
7958
+ 256,
7959
+ 320,
7960
+ 384,
7961
+ -1,
7962
+ // layer = 2
7963
+ -1,
7964
+ 32,
7965
+ 64,
7966
+ 96,
7967
+ 128,
7968
+ 160,
7969
+ 192,
7970
+ 224,
7971
+ 256,
7972
+ 288,
7973
+ 320,
7974
+ 352,
7975
+ 384,
7976
+ 416,
7977
+ 448,
7978
+ -1,
7979
+ // layer = 3
7980
+ // lowSamplingFrequency === 1
7981
+ -1,
7982
+ -1,
7983
+ -1,
7984
+ -1,
7985
+ -1,
7986
+ -1,
7987
+ -1,
7988
+ -1,
7989
+ -1,
7990
+ -1,
7991
+ -1,
7992
+ -1,
7993
+ -1,
7994
+ -1,
7995
+ -1,
7996
+ -1,
7997
+ // layer = 0
7998
+ -1,
7999
+ 8,
8000
+ 16,
8001
+ 24,
8002
+ 32,
8003
+ 40,
8004
+ 48,
8005
+ 56,
8006
+ 64,
8007
+ 80,
8008
+ 96,
8009
+ 112,
8010
+ 128,
8011
+ 144,
8012
+ 160,
8013
+ -1,
8014
+ // layer = 1
8015
+ -1,
8016
+ 8,
8017
+ 16,
8018
+ 24,
8019
+ 32,
8020
+ 40,
8021
+ 48,
8022
+ 56,
8023
+ 64,
8024
+ 80,
8025
+ 96,
8026
+ 112,
8027
+ 128,
8028
+ 144,
8029
+ 160,
8030
+ -1,
8031
+ // layer = 2
8032
+ -1,
8033
+ 32,
8034
+ 48,
8035
+ 56,
8036
+ 64,
8037
+ 80,
8038
+ 96,
8039
+ 112,
8040
+ 128,
8041
+ 144,
8042
+ 160,
8043
+ 176,
8044
+ 192,
8045
+ 224,
8046
+ 256,
8047
+ -1
8048
+ // layer = 3
8049
+ ];
7933
8050
  var XING = 1483304551;
7934
8051
  var INFO = 1231971951;
7935
- var computeMp3FrameSize = (layer, bitrate, sampleRate, padding) => {
7936
- if (layer === 3) {
7937
- return Math.floor((12 * bitrate / sampleRate + padding) * 4);
8052
+ var computeMp3FrameSize = (lowSamplingFrequency, layer, bitrate, sampleRate, padding) => {
8053
+ if (layer === 0) {
8054
+ return 0;
8055
+ } else if (layer === 1) {
8056
+ return Math.round(144 * bitrate / (sampleRate << lowSamplingFrequency)) + padding;
8057
+ } else if (layer === 2) {
8058
+ return Math.round(144 * bitrate / sampleRate) + padding;
7938
8059
  } else {
7939
- return Math.floor(144 * bitrate / sampleRate + padding);
8060
+ return (Math.round(12 * bitrate / sampleRate) + padding) * 4;
7940
8061
  }
7941
8062
  };
7942
8063
  var getXingOffset = (mpegVersionId, channel) => {
@@ -7959,26 +8080,31 @@ ${cue.notes ?? ""}`;
7959
8080
  if ((secondByte & 224) !== 224) {
7960
8081
  return { header: null, bytesAdvanced: 1 };
7961
8082
  }
8083
+ let lowSamplingFrequency = 0;
8084
+ let mpeg25 = 0;
8085
+ if (secondByte & 1 << 4) {
8086
+ lowSamplingFrequency = secondByte & 1 << 3 ? 0 : 1;
8087
+ } else {
8088
+ lowSamplingFrequency = 1;
8089
+ mpeg25 = 1;
8090
+ }
7962
8091
  const mpegVersionId = secondByte >> 3 & 3;
7963
8092
  const layer = secondByte >> 1 & 3;
7964
8093
  const bitrateIndex = thirdByte >> 4 & 15;
7965
- const frequencyIndex = thirdByte >> 2 & 3;
8094
+ const frequencyIndex = (thirdByte >> 2 & 3) % 3;
7966
8095
  const padding = thirdByte >> 1 & 1;
7967
8096
  const channel = fourthByte >> 6 & 3;
7968
8097
  const modeExtension = fourthByte >> 4 & 3;
7969
8098
  const copyright = fourthByte >> 3 & 1;
7970
8099
  const original = fourthByte >> 2 & 1;
7971
8100
  const emphasis = fourthByte & 3;
7972
- const kilobitRate = mpegVersionId === 3 ? MPEG_V1_BITRATES[layer]?.[bitrateIndex] : MPEG_V2_BITRATES[layer]?.[bitrateIndex];
7973
- if (!kilobitRate || kilobitRate === -1) {
8101
+ const kilobitRate = KILOBIT_RATES[lowSamplingFrequency * 16 * 4 + layer * 16 + bitrateIndex];
8102
+ if (kilobitRate === -1) {
7974
8103
  return { header: null, bytesAdvanced: 1 };
7975
8104
  }
7976
8105
  const bitrate = kilobitRate * 1e3;
7977
- const sampleRate = SAMPLING_RATES[mpegVersionId]?.[frequencyIndex];
7978
- if (!sampleRate || sampleRate === -1) {
7979
- return { header: null, bytesAdvanced: 1 };
7980
- }
7981
- const frameLength = computeMp3FrameSize(layer, bitrate, sampleRate, padding);
8106
+ const sampleRate = SAMPLING_RATES[frequencyIndex] >> lowSamplingFrequency + mpeg25;
8107
+ const frameLength = computeMp3FrameSize(lowSamplingFrequency, layer, bitrate, sampleRate, padding);
7982
8108
  if (remainingBytes !== null && remainingBytes < frameLength) {
7983
8109
  return { header: null, bytesAdvanced: 1 };
7984
8110
  }
@@ -8758,6 +8884,65 @@ ${cue.notes ?? ""}`;
8758
8884
  }
8759
8885
  this.writer.write(this.helper.subarray(0, text.length));
8760
8886
  }
8887
+ writeXingFrame(data) {
8888
+ const startPos = this.writer.getPos();
8889
+ const firstByte = 255;
8890
+ const secondByte = 224 | data.mpegVersionId << 3 | data.layer << 1;
8891
+ let lowSamplingFrequency;
8892
+ if (data.mpegVersionId & 2) {
8893
+ lowSamplingFrequency = data.mpegVersionId & 1 ? 0 : 1;
8894
+ } else {
8895
+ lowSamplingFrequency = 1;
8896
+ }
8897
+ const padding = 0;
8898
+ const neededBytes = 155;
8899
+ let bitrateIndex = -1;
8900
+ const bitrateOffset = lowSamplingFrequency * 16 * 4 + data.layer * 16;
8901
+ for (let i = 0; i < 16; i++) {
8902
+ const kbr = KILOBIT_RATES[bitrateOffset + i];
8903
+ const size = computeMp3FrameSize(lowSamplingFrequency, data.layer, 1e3 * kbr, data.sampleRate, padding);
8904
+ if (size >= neededBytes) {
8905
+ bitrateIndex = i;
8906
+ break;
8907
+ }
8908
+ }
8909
+ if (bitrateIndex === -1) {
8910
+ throw new Error("No suitable bitrate found.");
8911
+ }
8912
+ const thirdByte = bitrateIndex << 4 | data.frequencyIndex << 2 | padding << 1;
8913
+ const fourthByte = data.channel << 6 | data.modeExtension << 4 | data.copyright << 3 | data.original << 2 | data.emphasis;
8914
+ this.helper[0] = firstByte;
8915
+ this.helper[1] = secondByte;
8916
+ this.helper[2] = thirdByte;
8917
+ this.helper[3] = fourthByte;
8918
+ this.writer.write(this.helper.subarray(0, 4));
8919
+ const xingOffset = getXingOffset(data.mpegVersionId, data.channel);
8920
+ this.writer.seek(startPos + xingOffset);
8921
+ this.writeU32(XING);
8922
+ let flags = 0;
8923
+ if (data.frameCount !== null) {
8924
+ flags |= 1;
8925
+ }
8926
+ if (data.fileSize !== null) {
8927
+ flags |= 2;
8928
+ }
8929
+ if (data.toc !== null) {
8930
+ flags |= 4;
8931
+ }
8932
+ this.writeU32(flags);
8933
+ this.writeU32(data.frameCount ?? 0);
8934
+ this.writeU32(data.fileSize ?? 0);
8935
+ this.writer.write(data.toc ?? new Uint8Array(100));
8936
+ const kilobitRate = KILOBIT_RATES[bitrateOffset + bitrateIndex];
8937
+ const frameSize = computeMp3FrameSize(
8938
+ lowSamplingFrequency,
8939
+ data.layer,
8940
+ 1e3 * kilobitRate,
8941
+ data.sampleRate,
8942
+ padding
8943
+ );
8944
+ this.writer.seek(startPos + frameSize);
8945
+ }
8761
8946
  writeSynchsafeU32(value) {
8762
8947
  this.writeU32(encodeSynchsafe(value));
8763
8948
  }
@@ -8846,54 +9031,6 @@ ${cue.notes ?? ""}`;
8846
9031
  }
8847
9032
  this.writer.write(imageData);
8848
9033
  }
8849
- writeXingFrame(data) {
8850
- const startPos = this.writer.getPos();
8851
- const firstByte = 255;
8852
- const secondByte = 224 | data.mpegVersionId << 3 | data.layer << 1;
8853
- const bitrateGroup = data.mpegVersionId === 3 ? MPEG_V1_BITRATES : MPEG_V2_BITRATES;
8854
- const bitrates = bitrateGroup?.[data.layer];
8855
- if (!bitrates) {
8856
- throw new Error("Invalid MPEG version and layer combination.");
8857
- }
8858
- const sampleRate = SAMPLING_RATES[data.mpegVersionId]?.[data.frequencyIndex];
8859
- if (!sampleRate || sampleRate === -1) {
8860
- throw new Error("Invalid MPEG version and frequency index combination.");
8861
- }
8862
- const padding = 0;
8863
- const neededBytes = 155;
8864
- const bitrateIndex = bitrates.findIndex((kbr) => {
8865
- return computeMp3FrameSize(data.layer, 1e3 * kbr, sampleRate, padding) >= neededBytes;
8866
- });
8867
- if (bitrateIndex === -1) {
8868
- throw new Error("No suitable bitrate found.");
8869
- }
8870
- const thirdByte = bitrateIndex << 4 | data.frequencyIndex << 2 | padding << 1;
8871
- const fourthByte = data.channel << 6 | data.modeExtension << 4 | data.copyright << 3 | data.original << 2 | data.emphasis;
8872
- this.helper[0] = firstByte;
8873
- this.helper[1] = secondByte;
8874
- this.helper[2] = thirdByte;
8875
- this.helper[3] = fourthByte;
8876
- this.writer.write(this.helper.subarray(0, 4));
8877
- const xingOffset = getXingOffset(data.mpegVersionId, data.channel);
8878
- this.writer.seek(startPos + xingOffset);
8879
- this.writeU32(XING);
8880
- let flags = 0;
8881
- if (data.frameCount !== null) {
8882
- flags |= 1;
8883
- }
8884
- if (data.fileSize !== null) {
8885
- flags |= 2;
8886
- }
8887
- if (data.toc !== null) {
8888
- flags |= 4;
8889
- }
8890
- this.writeU32(flags);
8891
- this.writeU32(data.frameCount ?? 0);
8892
- this.writeU32(data.fileSize ?? 0);
8893
- this.writer.write(data.toc ?? new Uint8Array(100));
8894
- const frameSize = computeMp3FrameSize(data.layer, 1e3 * bitrates[bitrateIndex], sampleRate, padding);
8895
- this.writer.seek(startPos + frameSize);
8896
- }
8897
9034
  };
8898
9035
 
8899
9036
  // src/mp3/mp3-muxer.ts
@@ -8945,6 +9082,7 @@ ${cue.notes ?? ""}`;
8945
9082
  mpegVersionId: header.mpegVersionId,
8946
9083
  layer: header.layer,
8947
9084
  frequencyIndex: header.frequencyIndex,
9085
+ sampleRate: header.sampleRate,
8948
9086
  channel: header.channel,
8949
9087
  modeExtension: header.modeExtension,
8950
9088
  copyright: header.copyright,
@@ -20790,9 +20928,14 @@ ${cue.notes ?? ""}`;
20790
20928
  if (!this.firstFrameHeader) {
20791
20929
  this.firstFrameHeader = header;
20792
20930
  }
20793
- const sampleDuration = header.audioSamplesInFrame / header.sampleRate;
20931
+ if (header.sampleRate !== this.firstFrameHeader.sampleRate) {
20932
+ console.warn(
20933
+ `MP3 changed sample rate mid-file: ${this.firstFrameHeader.sampleRate} Hz to ${header.sampleRate} Hz. Might be a bug, so please report this file.`
20934
+ );
20935
+ }
20936
+ const sampleDuration = header.audioSamplesInFrame / this.firstFrameHeader.sampleRate;
20794
20937
  const sample = {
20795
- timestamp: this.nextTimestampInSamples / header.sampleRate,
20938
+ timestamp: this.nextTimestampInSamples / this.firstFrameHeader.sampleRate,
20796
20939
  duration: sampleDuration,
20797
20940
  dataStart: result.startPos,
20798
20941
  dataSize: header.totalSize