mediabunny 1.39.2 → 1.40.1

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.
@@ -10470,15 +10470,18 @@ var Mediabunny = (() => {
10470
10470
  const firstPacket = await this.getFirstPacket({});
10471
10471
  this.internalTrack.info.av1CodecInfo = firstPacket && extractAv1CodecInfoFromPacket(firstPacket.data);
10472
10472
  }
10473
- return {
10473
+ const config = {
10474
10474
  codec: extractVideoCodecString(this.internalTrack.info),
10475
10475
  codedWidth: this.internalTrack.info.width,
10476
10476
  codedHeight: this.internalTrack.info.height,
10477
- displayAspectWidth: this.internalTrack.info.squarePixelWidth,
10478
- displayAspectHeight: this.internalTrack.info.squarePixelHeight,
10479
10477
  description: this.internalTrack.info.codecDescription ?? void 0,
10480
10478
  colorSpace: this.internalTrack.info.colorSpace ?? void 0
10481
10479
  };
10480
+ if (this.internalTrack.info.width !== this.internalTrack.info.squarePixelWidth || this.internalTrack.info.height !== this.internalTrack.info.squarePixelHeight) {
10481
+ config.displayAspectWidth = this.internalTrack.info.squarePixelWidth;
10482
+ config.displayAspectHeight = this.internalTrack.info.squarePixelHeight;
10483
+ }
10484
+ return config;
10482
10485
  })();
10483
10486
  }
10484
10487
  };
@@ -10639,15 +10642,12 @@ var Mediabunny = (() => {
10639
10642
  }
10640
10643
  };
10641
10644
  var extractRotationFromMatrix = (matrix) => {
10642
- const [m11, , , m21] = matrix;
10643
- const scaleX = Math.hypot(m11, m21);
10644
- const cosTheta = m11 / scaleX;
10645
- const sinTheta = m21 / scaleX;
10646
- const result = -Math.atan2(sinTheta, cosTheta) * (180 / Math.PI);
10647
- if (!Number.isFinite(result)) {
10645
+ const [a, b] = matrix;
10646
+ const radians = Math.atan2(b, a);
10647
+ if (!Number.isFinite(radians)) {
10648
10648
  return 0;
10649
10649
  }
10650
- return result;
10650
+ return radians * (180 / Math.PI);
10651
10651
  };
10652
10652
  var sampleTableIsEmpty = (sampleTable) => {
10653
10653
  return sampleTable.sampleSizes.length === 0;
@@ -11726,7 +11726,9 @@ var Mediabunny = (() => {
11726
11726
  defaultDuration: null,
11727
11727
  defaultDurationNs: null,
11728
11728
  name: null,
11729
- languageCode: UNDETERMINED_LANGUAGE,
11729
+ languageCode: "eng",
11730
+ // The default in Matroska
11731
+ hasLanguageBcp47: false,
11730
11732
  decodingInstructions: [],
11731
11733
  info: null
11732
11734
  };
@@ -11776,7 +11778,7 @@ var Mediabunny = (() => {
11776
11778
  const inputTrack = new InputVideoTrack(this.input, new MatroskaVideoTrackBacking(videoTrack));
11777
11779
  this.currentTrack.inputTrack = inputTrack;
11778
11780
  this.currentSegment.tracks.push(this.currentTrack);
11779
- } else if (this.currentTrack.info.type === "audio" && this.currentTrack.info.numberOfChannels !== -1 && this.currentTrack.info.sampleRate !== -1) {
11781
+ } else if (this.currentTrack.info.type === "audio") {
11780
11782
  if (codecIdWithoutSuffix === CODEC_STRING_MAP.aac) {
11781
11783
  this.currentTrack.info.codec = "aac";
11782
11784
  this.currentTrack.info.aacCodecInfo = {
@@ -11869,8 +11871,10 @@ var Mediabunny = (() => {
11869
11871
  } else if (type === 2) {
11870
11872
  this.currentTrack.info = {
11871
11873
  type: "audio",
11872
- numberOfChannels: -1,
11873
- sampleRate: -1,
11874
+ numberOfChannels: 1,
11875
+ // Default value
11876
+ sampleRate: 8e3,
11877
+ // Default value
11874
11878
  bitDepth: -1,
11875
11879
  codec: null,
11876
11880
  codecDescription: null,
@@ -11963,7 +11967,7 @@ var Mediabunny = (() => {
11963
11967
  case 2274716 /* Language */:
11964
11968
  {
11965
11969
  if (!this.currentTrack) break;
11966
- if (this.currentTrack.languageCode !== UNDETERMINED_LANGUAGE) {
11970
+ if (this.currentTrack.hasLanguageBcp47) {
11967
11971
  break;
11968
11972
  }
11969
11973
  this.currentTrack.languageCode = readAsciiString(slice, size);
@@ -11983,6 +11987,7 @@ var Mediabunny = (() => {
11983
11987
  } else {
11984
11988
  this.currentTrack.languageCode = UNDETERMINED_LANGUAGE;
11985
11989
  }
11990
+ this.currentTrack.hasLanguageBcp47 = true;
11986
11991
  }
11987
11992
  ;
11988
11993
  break;
@@ -13034,7 +13039,7 @@ var Mediabunny = (() => {
13034
13039
  if (needsPacketForAdditionalInfo) {
13035
13040
  firstPacket = await this.getFirstPacket({});
13036
13041
  }
13037
- return {
13042
+ const config = {
13038
13043
  codec: extractVideoCodecString({
13039
13044
  width: this.internalTrack.info.width,
13040
13045
  height: this.internalTrack.info.height,
@@ -13050,11 +13055,14 @@ var Mediabunny = (() => {
13050
13055
  }),
13051
13056
  codedWidth: this.internalTrack.info.width,
13052
13057
  codedHeight: this.internalTrack.info.height,
13053
- displayAspectWidth: this.internalTrack.info.squarePixelWidth,
13054
- displayAspectHeight: this.internalTrack.info.squarePixelHeight,
13055
13058
  description: this.internalTrack.info.codecDescription ?? void 0,
13056
13059
  colorSpace: this.internalTrack.info.colorSpace ?? void 0
13057
13060
  };
13061
+ if (this.internalTrack.info.width !== this.internalTrack.info.squarePixelWidth || this.internalTrack.info.height !== this.internalTrack.info.squarePixelHeight) {
13062
+ config.displayAspectWidth = this.internalTrack.info.squarePixelWidth;
13063
+ config.displayAspectHeight = this.internalTrack.info.squarePixelHeight;
13064
+ }
13065
+ return config;
13058
13066
  })();
13059
13067
  }
13060
13068
  };
@@ -15249,11 +15257,15 @@ var Mediabunny = (() => {
15249
15257
  }) {
15250
15258
  assert(this.audioInfo);
15251
15259
  const minimumHeaderLength = 6;
15252
- const maximumHeaderSize = 16;
15253
- const maximumSliceLength = this.audioInfo.maximumFrameSize + maximumHeaderSize;
15260
+ const maximumHeaderLength = 16;
15261
+ const minimumFrameLength = 10;
15262
+ const maximumFrameLength = this.audioInfo.maximumBlockSize * this.audioInfo.numberOfChannels * 4 + maximumHeaderLength + 2;
15263
+ const effectiveMinFrameSize = this.audioInfo.minimumFrameSize || minimumFrameLength;
15264
+ const effectiveMaxFrameSize = this.audioInfo.maximumFrameSize || maximumFrameLength;
15265
+ const maximumSliceLength = effectiveMaxFrameSize + maximumHeaderLength;
15254
15266
  const slice = await this.reader.requestSliceRange(
15255
15267
  startPos,
15256
- this.audioInfo.minimumFrameSize,
15268
+ maximumHeaderLength,
15257
15269
  maximumSliceLength
15258
15270
  );
15259
15271
  if (!slice) {
@@ -15266,7 +15278,7 @@ var Mediabunny = (() => {
15266
15278
  if (!frameHeader) {
15267
15279
  return null;
15268
15280
  }
15269
- slice.filePos = startPos + this.audioInfo.minimumFrameSize;
15281
+ slice.filePos = startPos + effectiveMinFrameSize;
15270
15282
  while (true) {
15271
15283
  if (slice.filePos > slice.end - minimumHeaderLength) {
15272
15284
  return {
@@ -15657,11 +15669,12 @@ var Mediabunny = (() => {
15657
15669
  while (8 * (sectionLength + BYTES_BEFORE_SECTION_LENGTH) - bitstream.pos > BITS_IN_CRC_32) {
15658
15670
  const programNumber = bitstream.readBits(16);
15659
15671
  bitstream.skipBits(3);
15672
+ const id = bitstream.readBits(13);
15660
15673
  if (programNumber !== 0) {
15661
15674
  if (programMapPid !== null) {
15662
15675
  throw new Error("Only files with a single program are supported.");
15663
15676
  } else {
15664
- programMapPid = bitstream.readBits(13);
15677
+ programMapPid = id;
15665
15678
  }
15666
15679
  }
15667
15680
  }
@@ -16623,10 +16636,12 @@ var Mediabunny = (() => {
16623
16636
  }),
16624
16637
  codedWidth: this.elementaryStream.info.width,
16625
16638
  codedHeight: this.elementaryStream.info.height,
16626
- displayAspectWidth: this.elementaryStream.info.squarePixelWidth,
16627
- displayAspectHeight: this.elementaryStream.info.squarePixelHeight,
16628
16639
  colorSpace: this.elementaryStream.info.colorSpace
16629
16640
  };
16641
+ if (this.elementaryStream.info.width !== this.elementaryStream.info.squarePixelWidth || this.elementaryStream.info.height !== this.elementaryStream.info.squarePixelHeight) {
16642
+ this.decoderConfig.displayAspectWidth = this.elementaryStream.info.squarePixelWidth;
16643
+ this.decoderConfig.displayAspectHeight = this.elementaryStream.info.squarePixelHeight;
16644
+ }
16630
16645
  }
16631
16646
  getCodec() {
16632
16647
  return this.elementaryStream.info.codec;
@@ -20055,6 +20070,9 @@ var Mediabunny = (() => {
20055
20070
  this.bitsPerSample = null;
20056
20071
  this.writer = output._writer;
20057
20072
  this.format = format;
20073
+ if (this.format._options.appendOnly) {
20074
+ this.writer.ensureMonotonicity = true;
20075
+ }
20058
20076
  }
20059
20077
  async start() {
20060
20078
  this.writer.write(FLAC_HEADER);
@@ -20124,7 +20142,9 @@ var Mediabunny = (() => {
20124
20142
  this.writer.write(header);
20125
20143
  }
20126
20144
  writeVorbisCommentAndPictureBlock() {
20127
- this.writer.seek(STREAMINFO_SIZE + FLAC_HEADER.byteLength);
20145
+ if (!this.format._options.appendOnly) {
20146
+ this.writer.seek(STREAMINFO_SIZE + FLAC_HEADER.byteLength);
20147
+ }
20128
20148
  if (metadataTagsAreEmpty(this.output._metadataTags)) {
20129
20149
  this.metadataWritten = true;
20130
20150
  return;
@@ -20173,6 +20193,28 @@ var Mediabunny = (() => {
20173
20193
  descriptionBitstream.skipBits(103 + 64);
20174
20194
  const bitsPerSample = descriptionBitstream.readBits(5) + 1;
20175
20195
  this.bitsPerSample = bitsPerSample;
20196
+ if (this.format._options.appendOnly) {
20197
+ this.writeHeader({
20198
+ // https://www.rfc-editor.org/rfc/rfc9639.html#name-streaminfo
20199
+ // Per RFC 9639, min/max block sizes can be looser than
20200
+ // actual values, so we use the full valid range (16–65535).
20201
+ // "The actual max block size MAY be smaller than what's
20202
+ // listed, and the actual min (excluding last block) MAY be
20203
+ // larger. This is because the encoder has to write these
20204
+ // fields before receiving any input audio data and cannot
20205
+ // know beforehand what block sizes it will use."
20206
+ minimumBlockSize: 16,
20207
+ maximumBlockSize: 65535,
20208
+ // https://www.rfc-editor.org/rfc/rfc9639.html#name-streaminfo
20209
+ // "A value of 0 signifies that the value is not known."
20210
+ minimumFrameSize: 0,
20211
+ maximumFrameSize: 0,
20212
+ sampleRate: this.sampleRate,
20213
+ channels: this.channels,
20214
+ bitsPerSample: this.bitsPerSample,
20215
+ totalSamples: 0
20216
+ });
20217
+ }
20176
20218
  }
20177
20219
  if (!this.metadataWritten) {
20178
20220
  this.writeVorbisCommentAndPictureBlock();
@@ -20187,8 +20229,10 @@ var Mediabunny = (() => {
20187
20229
  }
20188
20230
  readCodedNumber(slice);
20189
20231
  const blockSize = readBlockSize(slice, blockSizeOrUncommon);
20190
- this.blockSizes.push(blockSize);
20191
- this.frameSizes.push(packet.data.length);
20232
+ if (!this.format._options.appendOnly) {
20233
+ this.blockSizes.push(blockSize);
20234
+ this.frameSizes.push(packet.data.length);
20235
+ }
20192
20236
  const startPos = this.writer.getPos();
20193
20237
  this.writer.write(packet.data);
20194
20238
  if (this.format._options.onFrame) {
@@ -20204,36 +20248,38 @@ var Mediabunny = (() => {
20204
20248
  }
20205
20249
  async finalize() {
20206
20250
  const release = await this.mutex.acquire();
20207
- let minimumBlockSize = Infinity;
20208
- let maximumBlockSize = 0;
20209
- let minimumFrameSize = Infinity;
20210
- let maximumFrameSize = 0;
20211
- let totalSamples = 0;
20212
- for (let i = 0; i < this.blockSizes.length; i++) {
20213
- minimumFrameSize = Math.min(minimumFrameSize, this.frameSizes[i]);
20214
- maximumFrameSize = Math.max(maximumFrameSize, this.frameSizes[i]);
20215
- maximumBlockSize = Math.max(maximumBlockSize, this.blockSizes[i]);
20216
- totalSamples += this.blockSizes[i];
20217
- const isLastFrame = i === this.blockSizes.length - 1;
20218
- if (isLastFrame) {
20219
- continue;
20220
- }
20221
- minimumBlockSize = Math.min(minimumBlockSize, this.blockSizes[i]);
20222
- }
20223
- assert(this.sampleRate !== null);
20224
- assert(this.channels !== null);
20225
- assert(this.bitsPerSample !== null);
20226
- this.writer.seek(4);
20227
- this.writeHeader({
20228
- minimumBlockSize,
20229
- maximumBlockSize,
20230
- minimumFrameSize,
20231
- maximumFrameSize,
20232
- sampleRate: this.sampleRate,
20233
- channels: this.channels,
20234
- bitsPerSample: this.bitsPerSample,
20235
- totalSamples
20236
- });
20251
+ if (!this.format._options.appendOnly) {
20252
+ let minimumBlockSize = Infinity;
20253
+ let maximumBlockSize = 0;
20254
+ let minimumFrameSize = Infinity;
20255
+ let maximumFrameSize = 0;
20256
+ let totalSamples = 0;
20257
+ for (let i = 0; i < this.blockSizes.length; i++) {
20258
+ minimumFrameSize = Math.min(minimumFrameSize, this.frameSizes[i]);
20259
+ maximumFrameSize = Math.max(maximumFrameSize, this.frameSizes[i]);
20260
+ maximumBlockSize = Math.max(maximumBlockSize, this.blockSizes[i]);
20261
+ totalSamples += this.blockSizes[i];
20262
+ const isLastFrame = i === this.blockSizes.length - 1;
20263
+ if (isLastFrame) {
20264
+ continue;
20265
+ }
20266
+ minimumBlockSize = Math.min(minimumBlockSize, this.blockSizes[i]);
20267
+ }
20268
+ assert(this.sampleRate !== null);
20269
+ assert(this.channels !== null);
20270
+ assert(this.bitsPerSample !== null);
20271
+ this.writer.seek(4);
20272
+ this.writeHeader({
20273
+ minimumBlockSize,
20274
+ maximumBlockSize,
20275
+ minimumFrameSize,
20276
+ maximumFrameSize,
20277
+ sampleRate: this.sampleRate,
20278
+ channels: this.channels,
20279
+ bitsPerSample: this.bitsPerSample,
20280
+ totalSamples
20281
+ });
20282
+ }
20237
20283
  release();
20238
20284
  }
20239
20285
  };
@@ -26092,6 +26138,9 @@ ${cue.notes ?? ""}`;
26092
26138
  if (!options || typeof options !== "object") {
26093
26139
  throw new TypeError("options must be an object.");
26094
26140
  }
26141
+ if (options.appendOnly !== void 0 && typeof options.appendOnly !== "boolean") {
26142
+ throw new TypeError("options.appendOnly, when provided, must be a boolean.");
26143
+ }
26095
26144
  super();
26096
26145
  this._options = options;
26097
26146
  }
@@ -29193,6 +29242,7 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
29193
29242
  }
29194
29243
  }
29195
29244
  if (needsRerender) {
29245
+ outputTrackRotation = 0;
29196
29246
  this._trackPromises.push((async () => {
29197
29247
  await this._started;
29198
29248
  const sink = new CanvasSink(track, {
@@ -29207,7 +29257,6 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
29207
29257
  });
29208
29258
  const iterator = sink.canvases(this._startTimestamp, this._endTimestamp);
29209
29259
  const frameRate = trackOptions.frameRate;
29210
- outputTrackRotation = 0;
29211
29260
  let lastCanvas = null;
29212
29261
  let lastCanvasTimestamp = null;
29213
29262
  let lastCanvasEndTimestamp = null;