mediabunny 1.10.0 → 1.11.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.
@@ -7759,6 +7759,37 @@ ${cue.notes ?? ""}`;
7759
7759
  );
7760
7760
  context.restore();
7761
7761
  }
7762
+ /**
7763
+ * Draws the sample in the middle of the canvas corresponding to the context with the specified fit behavior.
7764
+ */
7765
+ drawWithFit(context, options) {
7766
+ const canvasWidth = context.canvas.width;
7767
+ const canvasHeight = context.canvas.height;
7768
+ const rotation = options.rotation ?? this.rotation;
7769
+ let dx;
7770
+ let dy;
7771
+ let newWidth;
7772
+ let newHeight;
7773
+ if (options.fit === "fill") {
7774
+ dx = 0;
7775
+ dy = 0;
7776
+ newWidth = canvasWidth;
7777
+ newHeight = canvasHeight;
7778
+ } else {
7779
+ const [sampleWidth, sampleHeight] = rotation % 180 === 0 ? [this.codedWidth, this.codedHeight] : [this.codedHeight, this.codedWidth];
7780
+ const scale = options.fit === "contain" ? Math.min(canvasWidth / sampleWidth, canvasHeight / sampleHeight) : Math.max(canvasWidth / sampleWidth, canvasHeight / sampleHeight);
7781
+ newWidth = sampleWidth * scale;
7782
+ newHeight = sampleHeight * scale;
7783
+ dx = (canvasWidth - newWidth) / 2;
7784
+ dy = (canvasHeight - newHeight) / 2;
7785
+ }
7786
+ const aspectRatioChange = rotation % 180 === 0 ? 1 : newWidth / newHeight;
7787
+ context.translate(canvasWidth / 2, canvasHeight / 2);
7788
+ context.rotate(rotation * Math.PI / 180);
7789
+ context.scale(1 / aspectRatioChange, aspectRatioChange);
7790
+ context.translate(-canvasWidth / 2, -canvasHeight / 2);
7791
+ context.drawImage(this.toCanvasImageSource(), dx, dy, newWidth, newHeight);
7792
+ }
7762
7793
  /**
7763
7794
  * Converts this video sample to a CanvasImageSource for drawing to a canvas.
7764
7795
  *
@@ -9009,6 +9040,7 @@ ${cue.notes ?? ""}`;
9009
9040
  /** @internal */
9010
9041
  _videoSampleToWrappedCanvas(sample) {
9011
9042
  let canvas = this._canvasPool[this._nextCanvasIndex];
9043
+ let canvasIsNew = false;
9012
9044
  if (!canvas) {
9013
9045
  if (typeof document !== "undefined") {
9014
9046
  canvas = document.createElement("canvas");
@@ -9020,6 +9052,7 @@ ${cue.notes ?? ""}`;
9020
9052
  if (this._canvasPool.length > 0) {
9021
9053
  this._canvasPool[this._nextCanvasIndex] = canvas;
9022
9054
  }
9055
+ canvasIsNew = true;
9023
9056
  }
9024
9057
  if (this._canvasPool.length > 0) {
9025
9058
  this._nextCanvasIndex = (this._nextCanvasIndex + 1) % this._canvasPool.length;
@@ -9027,29 +9060,13 @@ ${cue.notes ?? ""}`;
9027
9060
  const context = canvas.getContext("2d", { alpha: false });
9028
9061
  assert(context);
9029
9062
  context.resetTransform();
9030
- let dx;
9031
- let dy;
9032
- let newWidth;
9033
- let newHeight;
9034
- if (this._fit === "fill") {
9035
- dx = 0;
9036
- dy = 0;
9037
- newWidth = this._width;
9038
- newHeight = this._height;
9039
- } else {
9040
- const [sampleWidth, sampleHeight] = this._rotation % 180 === 0 ? [sample.codedWidth, sample.codedHeight] : [sample.codedHeight, sample.codedWidth];
9041
- const scale = this._fit === "contain" ? Math.min(this._width / sampleWidth, this._height / sampleHeight) : Math.max(this._width / sampleWidth, this._height / sampleHeight);
9042
- newWidth = sampleWidth * scale;
9043
- newHeight = sampleHeight * scale;
9044
- dx = (this._width - newWidth) / 2;
9045
- dy = (this._height - newHeight) / 2;
9063
+ if (!canvasIsNew) {
9064
+ context.clearRect(0, 0, this._width, this._height);
9046
9065
  }
9047
- const aspectRatioChange = this._rotation % 180 === 0 ? 1 : newWidth / newHeight;
9048
- context.translate(this._width / 2, this._height / 2);
9049
- context.rotate(this._rotation * Math.PI / 180);
9050
- context.scale(1 / aspectRatioChange, aspectRatioChange);
9051
- context.translate(-this._width / 2, -this._height / 2);
9052
- context.drawImage(sample.toCanvasImageSource(), dx, dy, newWidth, newHeight);
9066
+ sample.drawWithFit(context, {
9067
+ fit: this._fit,
9068
+ rotation: this._rotation
9069
+ });
9053
9070
  const result = {
9054
9071
  canvas,
9055
9072
  timestamp: sample.timestamp,
@@ -11079,8 +11096,9 @@ ${cue.notes ?? ""}`;
11079
11096
  this.encoder = null;
11080
11097
  this.muxer = null;
11081
11098
  this.lastMultipleOfKeyFrameInterval = -1;
11082
- this.lastWidth = null;
11083
- this.lastHeight = null;
11099
+ this.codedWidth = null;
11100
+ this.codedHeight = null;
11101
+ this.resizeCanvas = null;
11084
11102
  this.customEncoder = null;
11085
11103
  this.customEncoderCallSerializer = new CallSerializer();
11086
11104
  this.customEncoderQueueSize = 0;
@@ -11095,15 +11113,46 @@ ${cue.notes ?? ""}`;
11095
11113
  try {
11096
11114
  this.checkForEncoderError();
11097
11115
  this.source._ensureValidAdd();
11098
- if (this.lastWidth !== null && this.lastHeight !== null) {
11099
- if (videoSample.codedWidth !== this.lastWidth || videoSample.codedHeight !== this.lastHeight) {
11100
- throw new Error(
11101
- `Video sample size must remain constant. Expected ${this.lastWidth}x${this.lastHeight}, got ${videoSample.codedWidth}x${videoSample.codedHeight}.`
11102
- );
11116
+ if (this.codedWidth !== null && this.codedHeight !== null) {
11117
+ if (videoSample.codedWidth !== this.codedWidth || videoSample.codedHeight !== this.codedHeight) {
11118
+ const sizeChangeBehavior = this.encodingConfig.sizeChangeBehavior ?? "deny";
11119
+ if (sizeChangeBehavior === "passThrough") {
11120
+ } else if (sizeChangeBehavior === "deny") {
11121
+ throw new Error(
11122
+ `Video sample size must remain constant. Expected ${this.codedWidth}x${this.codedHeight}, got ${videoSample.codedWidth}x${videoSample.codedHeight}. To allow the sample size to change over time, set \`sizeChangeBehavior\` to a value other than 'strict' in the encoding options.`
11123
+ );
11124
+ } else {
11125
+ let canvasIsNew = false;
11126
+ if (!this.resizeCanvas) {
11127
+ if (typeof document !== "undefined") {
11128
+ this.resizeCanvas = document.createElement("canvas");
11129
+ this.resizeCanvas.width = this.codedWidth;
11130
+ this.resizeCanvas.height = this.codedHeight;
11131
+ } else {
11132
+ this.resizeCanvas = new OffscreenCanvas(this.codedWidth, this.codedHeight);
11133
+ }
11134
+ canvasIsNew = true;
11135
+ }
11136
+ const context = this.resizeCanvas.getContext("2d", { alpha: false });
11137
+ assert(context);
11138
+ if (!canvasIsNew) {
11139
+ context.clearRect(0, 0, this.codedWidth, this.codedHeight);
11140
+ }
11141
+ videoSample.drawWithFit(context, { fit: sizeChangeBehavior });
11142
+ if (shouldClose) {
11143
+ videoSample.close();
11144
+ }
11145
+ videoSample = new VideoSample(this.resizeCanvas, {
11146
+ timestamp: videoSample.timestamp,
11147
+ duration: videoSample.duration,
11148
+ rotation: videoSample.rotation
11149
+ });
11150
+ shouldClose = true;
11151
+ }
11103
11152
  }
11104
11153
  } else {
11105
- this.lastWidth = videoSample.codedWidth;
11106
- this.lastHeight = videoSample.codedHeight;
11154
+ this.codedWidth = videoSample.codedWidth;
11155
+ this.codedHeight = videoSample.codedHeight;
11107
11156
  }
11108
11157
  if (!this.encoderInitialized) {
11109
11158
  if (!this.ensureEncoderPromise) {
@@ -14588,7 +14637,11 @@ ${cue.notes ?? ""}`;
14588
14637
  const scaleX = Math.hypot(m11, m21);
14589
14638
  const cosTheta = m11 / scaleX;
14590
14639
  const sinTheta = m21 / scaleX;
14591
- return -Math.atan2(sinTheta, cosTheta) * (180 / Math.PI);
14640
+ const result = -Math.atan2(sinTheta, cosTheta) * (180 / Math.PI);
14641
+ if (!Number.isFinite(result)) {
14642
+ return 0;
14643
+ }
14644
+ return result;
14592
14645
  };
14593
14646
  var sampleTableIsEmpty = (sampleTable) => {
14594
14647
  return sampleTable.sampleSizes.length === 0;
@@ -18027,6 +18080,7 @@ ${cue.notes ?? ""}`;
18027
18080
  const encodingConfig = {
18028
18081
  codec: encodableCodec,
18029
18082
  bitrate,
18083
+ sizeChangeBehavior: trackOptions.fit ?? "passThrough",
18030
18084
  onEncodedPacket: (sample) => this._reportProgress(track.id, sample.timestamp + sample.duration)
18031
18085
  };
18032
18086
  const source = new VideoSampleSource(encodingConfig);
@@ -18167,6 +18221,7 @@ ${cue.notes ?? ""}`;
18167
18221
  this.output.addVideoTrack(videoSource, {
18168
18222
  frameRate: trackOptions.frameRate,
18169
18223
  languageCode: track.languageCode,
18224
+ name: track.name ?? void 0,
18170
18225
  rotation: needsRerender ? 0 : totalRotation
18171
18226
  // Rerendering will bake the rotation into the output
18172
18227
  });
@@ -18284,7 +18339,8 @@ ${cue.notes ?? ""}`;
18284
18339
  }
18285
18340
  }
18286
18341
  this.output.addAudioTrack(audioSource, {
18287
- languageCode: track.languageCode
18342
+ languageCode: track.languageCode,
18343
+ name: track.name ?? void 0
18288
18344
  });
18289
18345
  this._addedCounts.audio++;
18290
18346
  this._totalTrackCount++;