mediabunny 1.15.0 → 1.15.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.
Files changed (36) hide show
  1. package/README.md +1 -1
  2. package/dist/bundles/mediabunny.cjs +84 -21
  3. package/dist/bundles/mediabunny.min.cjs +4 -4
  4. package/dist/bundles/mediabunny.min.mjs +4 -4
  5. package/dist/bundles/mediabunny.mjs +96 -21
  6. package/dist/mediabunny.d.ts +5 -4
  7. package/dist/modules/src/conversion.d.ts +4 -4
  8. package/dist/modules/src/conversion.d.ts.map +1 -1
  9. package/dist/modules/src/conversion.js +14 -5
  10. package/dist/modules/src/isobmff/isobmff-demuxer.d.ts.map +1 -1
  11. package/dist/modules/src/isobmff/isobmff-demuxer.js +16 -0
  12. package/dist/modules/src/media-sink.d.ts.map +1 -1
  13. package/dist/modules/src/media-sink.js +11 -3
  14. package/dist/modules/src/media-source.d.ts.map +1 -1
  15. package/dist/modules/src/media-source.js +11 -3
  16. package/dist/modules/src/misc.d.ts +1 -0
  17. package/dist/modules/src/misc.d.ts.map +1 -1
  18. package/dist/modules/src/misc.js +7 -0
  19. package/dist/modules/src/node.d.ts +9 -0
  20. package/dist/modules/src/node.d.ts.map +1 -0
  21. package/dist/modules/src/node.js +9 -0
  22. package/dist/modules/src/sample.d.ts +1 -0
  23. package/dist/modules/src/sample.d.ts.map +1 -1
  24. package/dist/modules/src/sample.js +10 -6
  25. package/dist/modules/src/source.d.ts.map +1 -1
  26. package/dist/modules/src/source.js +4 -4
  27. package/dist/modules/src/tsconfig.tsbuildinfo +1 -1
  28. package/package.json +9 -1
  29. package/src/conversion.ts +22 -9
  30. package/src/isobmff/isobmff-demuxer.ts +15 -0
  31. package/src/media-sink.ts +10 -3
  32. package/src/media-source.ts +19 -4
  33. package/src/misc.ts +9 -0
  34. package/src/node.ts +11 -0
  35. package/src/sample.ts +11 -5
  36. package/src/source.ts +6 -4
package/README.md CHANGED
@@ -50,7 +50,7 @@ Core features include:
50
50
  - **Wide format support**: Read and write MP4, MOV, WebM, MKV, WAVE, MP3, Ogg, ADTS
51
51
  - **Built-in encoding & decoding**: Supports 25+ video, audio, and subtitle codecs, hardware-accelerated using the WebCodecs API
52
52
  - **High precision**: Fine-grained, microsecond-accurate reading and writing operations
53
- - **Conversion API**: Easy-to-use API with features such as transmuxing, transcoding, resizing, rotation, resampling, trimming, and more
53
+ - **Conversion API**: Easy-to-use API with features such as transmuxing, transcoding, resizing, rotation, cropping, resampling, trimming, and more
54
54
  - **Streaming I/O**: Handle reading & writing files of any size with memory-efficient streaming
55
55
  - **Tree-shakable**: Only bundle what you use (as small as 5 kB gzipped)
56
56
  - **Zero dependencies**: Implemented in highly performant TypeScript
@@ -7,10 +7,15 @@
7
7
  */
8
8
  "use strict";
9
9
  var Mediabunny = (() => {
10
+ var __create = Object.create;
10
11
  var __defProp = Object.defineProperty;
11
12
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
13
  var __getOwnPropNames = Object.getOwnPropertyNames;
14
+ var __getProtoOf = Object.getPrototypeOf;
13
15
  var __hasOwnProp = Object.prototype.hasOwnProperty;
16
+ var __commonJS = (cb, mod) => function __require() {
17
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
18
+ };
14
19
  var __export = (target, all) => {
15
20
  for (var name in all)
16
21
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -23,8 +28,22 @@ var Mediabunny = (() => {
23
28
  }
24
29
  return to;
25
30
  };
31
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
32
+ // If the importer is in node compatibility mode or this is not an ESM
33
+ // file that has been converted to a CommonJS file using a Babel-
34
+ // compatible transform (i.e. "__esModule" has not been set), then set
35
+ // "default" to the CommonJS "module.exports" for node compatibility.
36
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
37
+ mod
38
+ ));
26
39
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
27
40
 
41
+ // (disabled):src/node
42
+ var require_node = __commonJS({
43
+ "(disabled):src/node"() {
44
+ }
45
+ });
46
+
28
47
  // src/index.ts
29
48
  var index_exports = {};
30
49
  __export(index_exports, {
@@ -586,6 +605,13 @@ var Mediabunny = (() => {
586
605
  isSafariCache = result;
587
606
  return result;
588
607
  };
608
+ var isFirefoxCache = null;
609
+ var isFirefox = () => {
610
+ if (isFirefoxCache !== null) {
611
+ return isFirefoxCache;
612
+ }
613
+ return isFirefoxCache = typeof navigator !== "undefined" && navigator.userAgent?.includes("Firefox");
614
+ };
589
615
  var coalesceIndex = (a, b) => {
590
616
  return a !== -1 ? a : b;
591
617
  };
@@ -9321,7 +9347,8 @@ ${cue.notes ?? ""}`;
9321
9347
  return new _VideoSample(
9322
9348
  new VideoFrame(data, {
9323
9349
  timestamp: Math.trunc(init.timestamp * SECOND_TO_MICROSECOND_FACTOR),
9324
- duration: Math.trunc((init.duration ?? 0) * SECOND_TO_MICROSECOND_FACTOR)
9350
+ // Drag 0 to undefined
9351
+ duration: Math.trunc((init.duration ?? 0) * SECOND_TO_MICROSECOND_FACTOR) || void 0
9325
9352
  }),
9326
9353
  init
9327
9354
  );
@@ -9342,7 +9369,11 @@ ${cue.notes ?? ""}`;
9342
9369
  throw new TypeError("Could not determine dimensions.");
9343
9370
  }
9344
9371
  const canvas = new OffscreenCanvas(width, height);
9345
- const context = canvas.getContext("2d", { alpha: false, willReadFrequently: true });
9372
+ const context = canvas.getContext("2d", {
9373
+ alpha: isFirefox(),
9374
+ // Firefox has VideoFrame glitches with opaque canvases
9375
+ willReadFrequently: true
9376
+ });
9346
9377
  assert(context);
9347
9378
  context.drawImage(data, 0, 0);
9348
9379
  this._data = canvas;
@@ -9457,7 +9488,7 @@ ${cue.notes ?? ""}`;
9457
9488
  dest.set(this._data);
9458
9489
  } else {
9459
9490
  const canvas = this._data;
9460
- const context = canvas.getContext("2d", { alpha: false });
9491
+ const context = canvas.getContext("2d");
9461
9492
  assert(context);
9462
9493
  const imageData = context.getImageData(0, 0, this.codedWidth, this.codedHeight);
9463
9494
  const dest = toUint8Array(destination);
@@ -9485,13 +9516,13 @@ ${cue.notes ?? ""}`;
9485
9516
  codedWidth: this.codedWidth,
9486
9517
  codedHeight: this.codedHeight,
9487
9518
  timestamp: this.microsecondTimestamp,
9488
- duration: this.microsecondDuration,
9519
+ duration: this.microsecondDuration || void 0,
9489
9520
  colorSpace: this.colorSpace
9490
9521
  });
9491
9522
  } else {
9492
9523
  return new VideoFrame(this._data, {
9493
9524
  timestamp: this.microsecondTimestamp,
9494
- duration: this.microsecondDuration
9525
+ duration: this.microsecondDuration || void 0
9495
9526
  });
9496
9527
  }
9497
9528
  }
@@ -10988,11 +11019,19 @@ ${cue.notes ?? ""}`;
10988
11019
  if (this._canvasPool.length > 0) {
10989
11020
  this._nextCanvasIndex = (this._nextCanvasIndex + 1) % this._canvasPool.length;
10990
11021
  }
10991
- const context = canvas.getContext("2d", { alpha: false });
11022
+ const context = canvas.getContext("2d", {
11023
+ alpha: isFirefox()
11024
+ // Firefox has VideoFrame glitches with opaque canvases
11025
+ });
10992
11026
  assert(context);
10993
11027
  context.resetTransform();
10994
11028
  if (!canvasIsNew) {
10995
- context.clearRect(0, 0, this._width, this._height);
11029
+ if (isFirefox()) {
11030
+ context.fillStyle = "black";
11031
+ context.fillRect(0, 0, this._width, this._height);
11032
+ } else {
11033
+ context.clearRect(0, 0, this._width, this._height);
11034
+ }
10996
11035
  }
10997
11036
  sample.drawWithFit(context, {
10998
11037
  fit: this._fit,
@@ -13280,10 +13319,18 @@ ${cue.notes ?? ""}`;
13280
13319
  }
13281
13320
  canvasIsNew = true;
13282
13321
  }
13283
- const context = this.resizeCanvas.getContext("2d", { alpha: false });
13322
+ const context = this.resizeCanvas.getContext("2d", {
13323
+ alpha: isFirefox()
13324
+ // Firefox has VideoFrame glitches with opaque canvases
13325
+ });
13284
13326
  assert(context);
13285
13327
  if (!canvasIsNew) {
13286
- context.clearRect(0, 0, this.codedWidth, this.codedHeight);
13328
+ if (isFirefox()) {
13329
+ context.fillStyle = "black";
13330
+ context.fillRect(0, 0, this.codedWidth, this.codedHeight);
13331
+ } else {
13332
+ context.clearRect(0, 0, this.codedWidth, this.codedHeight);
13333
+ }
13287
13334
  }
13288
13335
  videoSample.drawWithFit(context, { fit: sizeChangeBehavior });
13289
13336
  if (shouldClose) {
@@ -14594,6 +14641,8 @@ ${cue.notes ?? ""}`;
14594
14641
  };
14595
14642
 
14596
14643
  // src/source.ts
14644
+ var nodeAlias = __toESM(require_node(), 1);
14645
+ var node = nodeAlias;
14597
14646
  var Source = class {
14598
14647
  constructor() {
14599
14648
  /** @internal */
@@ -14916,18 +14965,13 @@ ${cue.notes ?? ""}`;
14916
14965
  let fileHandle = null;
14917
14966
  this._streamSource = new StreamSource({
14918
14967
  getSize: async () => {
14919
- const FS_MODULE_NAME = "node:fs/promises";
14920
- const fs = await import(
14921
- /* @vite-ignore */
14922
- FS_MODULE_NAME
14923
- );
14924
- fileHandle = await fs.open(filePath, "r");
14968
+ fileHandle = await node.fs.open(filePath, "r");
14925
14969
  const stats = await fileHandle.stat();
14926
14970
  return stats.size;
14927
14971
  },
14928
14972
  read: async (start, end) => {
14929
14973
  assert(fileHandle);
14930
- const buffer = Buffer.alloc(end - start);
14974
+ const buffer = new Uint8Array(end - start);
14931
14975
  await fileHandle.read(buffer, 0, end - start, start);
14932
14976
  return buffer;
14933
14977
  },
@@ -17479,6 +17523,22 @@ ${cue.notes ?? ""}`;
17479
17523
  }
17480
17524
  ;
17481
17525
  break;
17526
+ case "track":
17527
+ {
17528
+ if (typeof data === "string") {
17529
+ const parts = data.split("/");
17530
+ const trackNum = Number.parseInt(parts[0], 10);
17531
+ const tracksTotal = parts[1] && Number.parseInt(parts[1], 10);
17532
+ if (Number.isInteger(trackNum) && trackNum > 0) {
17533
+ this.metadataTags.trackNumber ??= trackNum;
17534
+ }
17535
+ if (tracksTotal && Number.isInteger(tracksTotal) && tracksTotal > 0) {
17536
+ this.metadataTags.tracksTotal ??= tracksTotal;
17537
+ }
17538
+ }
17539
+ }
17540
+ ;
17541
+ break;
17482
17542
  case "trkn":
17483
17543
  {
17484
17544
  if (data instanceof Uint8Array) {
@@ -21805,8 +21865,8 @@ ${cue.notes ?? ""}`;
21805
21865
  if (!(options.output instanceof Output)) {
21806
21866
  throw new TypeError("options.output must be an Output.");
21807
21867
  }
21808
- if (options.output._tracks.length > 0 || options.output.state !== "pending") {
21809
- throw new TypeError("options.output must be fresh: no tracks added and not started.");
21868
+ if (options.output._tracks.length > 0 || Object.keys(options.output._metadataTags).length > 0 || options.output.state !== "pending") {
21869
+ throw new TypeError("options.output must be fresh: no tracks or metadata tags added and not started.");
21810
21870
  }
21811
21871
  if (typeof options.video !== "function") {
21812
21872
  validateVideoOptions(options.video);
@@ -21828,8 +21888,11 @@ ${cue.notes ?? ""}`;
21828
21888
  if (options.trim?.start !== void 0 && options.trim.end !== void 0 && options.trim.start >= options.trim.end) {
21829
21889
  throw new TypeError("options.trim.start must be less than options.trim.end.");
21830
21890
  }
21831
- if (options.tags !== void 0 && typeof options.tags !== "function") {
21832
- throw new TypeError("options.tags, when provided, must be a function.");
21891
+ if (options.tags !== void 0 && (typeof options.tags !== "object" || !options.tags) && typeof options.tags !== "function") {
21892
+ throw new TypeError("options.tags, when provided, must be an object or a function.");
21893
+ }
21894
+ if (typeof options.tags === "object") {
21895
+ validateMetadataTags(options.tags);
21833
21896
  }
21834
21897
  this._options = options;
21835
21898
  this.input = options.input;
@@ -21911,7 +21974,7 @@ ${cue.notes ?? ""}`;
21911
21974
  const inputTags = await this.input.getMetadataTags();
21912
21975
  let outputTags;
21913
21976
  if (this._options.tags) {
21914
- const result = await this._options.tags(inputTags);
21977
+ const result = typeof this._options.tags === "function" ? await this._options.tags(inputTags) : this._options.tags;
21915
21978
  validateMetadataTags(result);
21916
21979
  outputTags = result;
21917
21980
  } else {