mediabunny 1.13.1 → 1.13.3

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.
package/README.md CHANGED
@@ -3,6 +3,7 @@
3
3
  [![](https://img.shields.io/npm/v/mediabunny)](https://www.npmjs.com/package/mediabunny)
4
4
  [![](https://img.shields.io/bundlephobia/minzip/mediabunny)](https://bundlephobia.com/package/mediabunny)
5
5
  [![](https://img.shields.io/npm/dm/mediabunny)](https://www.npmjs.com/package/mediabunny)
6
+ [![](https://img.shields.io/discord/1390044844285497344?logo=discord&label=Discord)](https://discord.gg/hmpkyYuS4U)
6
7
 
7
8
  <div align="center">
8
9
  <img src="./docs/public/mediabunny-logo.svg" width="180" height="180">
@@ -11178,6 +11178,7 @@ ${cue.notes ?? ""}`;
11178
11178
  if (this.encoder) {
11179
11179
  return;
11180
11180
  }
11181
+ const encoderError = new Error();
11181
11182
  return this.ensureEncoderPromise = (async () => {
11182
11183
  const encoderConfig = buildVideoEncoderConfig({
11183
11184
  width: videoSample.codedWidth,
@@ -11222,7 +11223,7 @@ ${cue.notes ?? ""}`;
11222
11223
  void this.muxer.addEncodedVideoPacket(this.source._connectedTrack, packet, meta);
11223
11224
  },
11224
11225
  error: (error) => {
11225
- error.stack = new Error().stack;
11226
+ error.stack = encoderError.stack;
11226
11227
  this.encoderError ??= error;
11227
11228
  }
11228
11229
  });
@@ -11234,7 +11235,7 @@ ${cue.notes ?? ""}`;
11234
11235
  })();
11235
11236
  }
11236
11237
  async flushAndClose(forceClose) {
11237
- this.checkForEncoderError();
11238
+ if (!forceClose) this.checkForEncoderError();
11238
11239
  if (this.customEncoder) {
11239
11240
  if (!forceClose) {
11240
11241
  void this.customEncoderCallSerializer.call(() => this.customEncoder.flush());
@@ -11244,9 +11245,11 @@ ${cue.notes ?? ""}`;
11244
11245
  if (!forceClose) {
11245
11246
  await this.encoder.flush();
11246
11247
  }
11247
- this.encoder.close();
11248
+ if (this.encoder.state !== "closed") {
11249
+ this.encoder.close();
11250
+ }
11248
11251
  }
11249
- this.checkForEncoderError();
11252
+ if (!forceClose) this.checkForEncoderError();
11250
11253
  }
11251
11254
  getQueueSize() {
11252
11255
  if (this.customEncoder) {
@@ -11257,6 +11260,7 @@ ${cue.notes ?? ""}`;
11257
11260
  }
11258
11261
  checkForEncoderError() {
11259
11262
  if (this.encoderError) {
11263
+ this.encoderError.stack = new Error().stack;
11260
11264
  throw this.encoderError;
11261
11265
  }
11262
11266
  }
@@ -11634,6 +11638,7 @@ ${cue.notes ?? ""}`;
11634
11638
  if (this.encoderInitialized) {
11635
11639
  return;
11636
11640
  }
11641
+ const encoderError = new Error();
11637
11642
  return this.ensureEncoderPromise = (async () => {
11638
11643
  const { numberOfChannels, sampleRate } = audioSample;
11639
11644
  const encoderConfig = buildAudioEncoderConfig({
@@ -11680,7 +11685,7 @@ ${cue.notes ?? ""}`;
11680
11685
  void this.muxer.addEncodedAudioPacket(this.source._connectedTrack, packet, meta);
11681
11686
  },
11682
11687
  error: (error) => {
11683
- error.stack = new Error().stack;
11688
+ error.stack = encoderError.stack;
11684
11689
  this.encoderError ??= error;
11685
11690
  }
11686
11691
  });
@@ -11787,7 +11792,7 @@ ${cue.notes ?? ""}`;
11787
11792
  }
11788
11793
  }
11789
11794
  async flushAndClose(forceClose) {
11790
- this.checkForEncoderError();
11795
+ if (!forceClose) this.checkForEncoderError();
11791
11796
  if (this.customEncoder) {
11792
11797
  if (!forceClose) {
11793
11798
  void this.customEncoderCallSerializer.call(() => this.customEncoder.flush());
@@ -11797,9 +11802,11 @@ ${cue.notes ?? ""}`;
11797
11802
  if (!forceClose) {
11798
11803
  await this.encoder.flush();
11799
11804
  }
11800
- this.encoder.close();
11805
+ if (this.encoder.state !== "closed") {
11806
+ this.encoder.close();
11807
+ }
11801
11808
  }
11802
- this.checkForEncoderError();
11809
+ if (!forceClose) this.checkForEncoderError();
11803
11810
  }
11804
11811
  getQueueSize() {
11805
11812
  if (this.customEncoder) {
@@ -11812,6 +11819,7 @@ ${cue.notes ?? ""}`;
11812
11819
  }
11813
11820
  checkForEncoderError() {
11814
11821
  if (this.encoderError) {
11822
+ this.encoderError.stack = new Error().stack;
11815
11823
  throw this.encoderError;
11816
11824
  }
11817
11825
  }
@@ -16947,8 +16955,7 @@ ${cue.notes ?? ""}`;
16947
16955
  this.lastLoadedPos += 10 + id3Tag.size;
16948
16956
  }
16949
16957
  }
16950
- const startPos = this.lastLoadedPos;
16951
- const result = await readNextFrameHeader(this.reader, startPos, this.reader.fileSize);
16958
+ const result = await readNextFrameHeader(this.reader, this.lastLoadedPos, this.reader.fileSize);
16952
16959
  if (!result) {
16953
16960
  this.lastSampleLoaded = true;
16954
16961
  return;
@@ -16956,13 +16963,14 @@ ${cue.notes ?? ""}`;
16956
16963
  const header = result.header;
16957
16964
  this.lastLoadedPos = result.startPos + header.totalSize - 1;
16958
16965
  const xingOffset = getXingOffset(header.mpegVersionId, header.channel);
16959
- let slice = this.reader.requestSlice(startPos + xingOffset, 4);
16966
+ let slice = this.reader.requestSlice(result.startPos + xingOffset, 4);
16960
16967
  if (slice instanceof Promise) slice = await slice;
16961
- assert(slice);
16962
- const word = readU32Be(slice);
16963
- const isXing = word === XING || word === INFO;
16964
- if (isXing) {
16965
- return;
16968
+ if (slice) {
16969
+ const word = readU32Be(slice);
16970
+ const isXing = word === XING || word === INFO;
16971
+ if (isXing) {
16972
+ return;
16973
+ }
16966
16974
  }
16967
16975
  if (!this.firstFrameHeader) {
16968
16976
  this.firstFrameHeader = header;
@@ -16971,7 +16979,7 @@ ${cue.notes ?? ""}`;
16971
16979
  const sample = {
16972
16980
  timestamp: this.nextTimestampInSamples / header.sampleRate,
16973
16981
  duration: sampleDuration,
16974
- dataStart: startPos,
16982
+ dataStart: result.startPos,
16975
16983
  dataSize: header.totalSize
16976
16984
  };
16977
16985
  this.loadedSamples.push(sample);
@@ -18771,7 +18779,7 @@ ${cue.notes ?? ""}`;
18771
18779
  }
18772
18780
  const firstTimestamp = await track.getFirstTimestamp();
18773
18781
  const needsTranscode = !!trackOptions.forceTranscode || this._startTimestamp > 0 || firstTimestamp < 0 || !!trackOptions.frameRate;
18774
- const needsRerender = width !== originalWidth || height !== originalHeight || totalRotation !== 0 && !outputSupportsRotation;
18782
+ let needsRerender = width !== originalWidth || height !== originalHeight || totalRotation !== 0 && !outputSupportsRotation;
18775
18783
  let videoCodecs = this.output.format.getSupportedVideoCodecs();
18776
18784
  if (!needsTranscode && !trackOptions.bitrate && !needsRerender && videoCodecs.includes(sourceCodec) && (!trackOptions.codec || trackOptions.codec === sourceCodec)) {
18777
18785
  const source = new EncodedVideoPacketSource(sourceCodec);
@@ -18824,6 +18832,31 @@ ${cue.notes ?? ""}`;
18824
18832
  };
18825
18833
  const source = new VideoSampleSource(encodingConfig);
18826
18834
  videoSource = source;
18835
+ if (!needsRerender) {
18836
+ const tempOutput = new Output({
18837
+ format: new Mp4OutputFormat(),
18838
+ // Supports all video codecs
18839
+ target: new NullTarget()
18840
+ });
18841
+ const tempSource = new VideoSampleSource(encodingConfig);
18842
+ tempOutput.addVideoTrack(tempSource);
18843
+ await tempOutput.start();
18844
+ const sink = new VideoSampleSink(track);
18845
+ const firstSample = await sink.getSample(this._startTimestamp);
18846
+ if (firstSample) {
18847
+ try {
18848
+ await tempSource.add(firstSample);
18849
+ firstSample.close();
18850
+ await tempOutput.finalize();
18851
+ } catch (error) {
18852
+ console.info("Error when probing encoder support. Falling back to rerender path.", error);
18853
+ needsRerender = true;
18854
+ void tempOutput.cancel();
18855
+ }
18856
+ } else {
18857
+ await tempOutput.cancel();
18858
+ }
18859
+ }
18827
18860
  if (needsRerender) {
18828
18861
  this._trackPromises.push((async () => {
18829
18862
  await this._started;
@@ -19129,12 +19162,8 @@ ${cue.notes ?? ""}`;
19129
19162
  }
19130
19163
  assert(this._totalDuration !== null);
19131
19164
  this._maxTimestamps.set(trackId, Math.max(endTimestamp, this._maxTimestamps.get(trackId) ?? -Infinity));
19132
- let totalTimestamps = 0;
19133
- for (const [, timestamp] of this._maxTimestamps) {
19134
- totalTimestamps += timestamp;
19135
- }
19136
- const averageTimestamp = totalTimestamps / this._totalTrackCount;
19137
- const newProgress = clamp(averageTimestamp / this._totalDuration, 0, 1);
19165
+ const minTimestamp = Math.min(...this._maxTimestamps.values());
19166
+ const newProgress = clamp(minTimestamp / this._totalDuration, 0, 1);
19138
19167
  if (newProgress !== this._lastProgress) {
19139
19168
  this._lastProgress = newProgress;
19140
19169
  this.onProgress?.(newProgress);