pixi-effects 0.47.5 → 0.48.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.
@@ -0,0 +1,53 @@
1
+ // src/core/mediabunny.ts
2
+ var source = null;
3
+ var pending = null;
4
+ function useMediabunny(from) {
5
+ if (from == null || typeof from !== "string" && typeof from !== "function" && typeof from !== "object") {
6
+ throw new TypeError(`pixi-effects: useMediabunny() takes the mediabunny module, a URL or a function that returns the module; it got ${String(from)}`);
7
+ }
8
+ source = from;
9
+ pending = null;
10
+ }
11
+ function loadMediabunny() {
12
+ if (!pending) {
13
+ const from = source;
14
+ const p = fetchModule(from).then(
15
+ (mod) => {
16
+ if (!mod || typeof mod.Output !== "function") {
17
+ throw new Error(`pixi-effects: ${describe(from)} did not give the mediabunny module (no Output in it). ${HOW}`);
18
+ }
19
+ return mod;
20
+ },
21
+ (err) => {
22
+ const why = err instanceof Error ? err.message : String(err);
23
+ throw new Error(`pixi-effects: could not load mediabunny from ${describe(from)} (${why}). ${HOW}`, { cause: err });
24
+ }
25
+ );
26
+ pending = p;
27
+ p.catch(() => {
28
+ if (pending === p) pending = null;
29
+ });
30
+ }
31
+ return pending;
32
+ }
33
+ var HOW = 'mediabunny is needed to export (movie.render(), the download button) and for a video layer; playing needs nothing. Add it to the import map ("mediabunny": "https://cdn.jsdelivr.net/npm/mediabunny@1/+esm"), install it next to pixi-effects, or call useMediabunny(module | url | () => import(...)) before you export.';
34
+ function fetchModule(from) {
35
+ if (from === null) return import('mediabunny');
36
+ if (typeof from === "string") return import(
37
+ /* @vite-ignore */
38
+ /* webpackIgnore: true */
39
+ from
40
+ );
41
+ if (typeof from === "function") return Promise.resolve().then(from);
42
+ return Promise.resolve(from);
43
+ }
44
+ function describe(from) {
45
+ if (from === null) return "'mediabunny' (the bare name: an import map or a bundler resolves it)";
46
+ if (typeof from === "string") return from;
47
+ if (typeof from === "function") return "the function given to useMediabunny()";
48
+ return "the object given to useMediabunny()";
49
+ }
50
+
51
+ export { loadMediabunny, useMediabunny };
52
+ //# sourceMappingURL=chunk-K3XOEC3C.js.map
53
+ //# sourceMappingURL=chunk-K3XOEC3C.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/mediabunny.ts"],"names":[],"mappings":";AAeA,IAAI,MAAA,GAAkC,IAAA;AACtC,IAAI,OAAA,GAA4C,IAAA;AAOzC,SAAS,cAAc,IAAA,EAA8B;AAC1D,EAAA,IAAI,IAAA,IAAQ,IAAA,IAAS,OAAO,IAAA,KAAS,QAAA,IAAY,OAAO,IAAA,KAAS,UAAA,IAAc,OAAO,IAAA,KAAS,QAAA,EAAW;AACxG,IAAA,MAAM,IAAI,SAAA,CAAU,CAAA,+GAAA,EAAkH,MAAA,CAAO,IAAI,CAAC,CAAA,CAAE,CAAA;AAAA,EACtJ;AACA,EAAA,MAAA,GAAS,IAAA;AACT,EAAA,OAAA,GAAU,IAAA;AACZ;AAGO,SAAS,cAAA,GAA4C;AAC1D,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,MAAM,IAAA,GAAO,MAAA;AACb,IAAA,MAAM,CAAA,GAAI,WAAA,CAAY,IAAI,CAAA,CAAE,IAAA;AAAA,MAC1B,CAAC,GAAA,KAAQ;AACP,QAAA,IAAI,CAAC,GAAA,IAAO,OAAQ,GAAA,CAA6B,WAAW,UAAA,EAAY;AACtE,UAAA,MAAM,IAAI,MAAM,CAAA,cAAA,EAAiB,QAAA,CAAS,IAAI,CAAC,CAAA,uDAAA,EAA0D,GAAG,CAAA,CAAE,CAAA;AAAA,QAChH;AACA,QAAA,OAAO,GAAA;AAAA,MACT,CAAA;AAAA,MACA,CAAC,GAAA,KAAiB;AAChB,QAAA,MAAM,MAAM,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,OAAO,GAAG,CAAA;AAC3D,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,6CAAA,EAAgD,QAAA,CAAS,IAAI,CAAC,CAAA,EAAA,EAAK,GAAG,CAAA,GAAA,EAAM,GAAG,CAAA,CAAA,EAAI,EAAE,KAAA,EAAO,KAAK,CAAA;AAAA,MACnH;AAAA,KACF;AACA,IAAA,OAAA,GAAU,CAAA;AACV,IAAA,CAAA,CAAE,MAAM,MAAM;AAAE,MAAA,IAAI,OAAA,KAAY,GAAG,OAAA,GAAU,IAAA;AAAA,IAAM,CAAC,CAAA;AAAA,EACtD;AACA,EAAA,OAAO,OAAA;AACT;AAEA,IAAM,GAAA,GAAM,2TAAA;AAIZ,SAAS,YAAY,IAAA,EAA0D;AAC7E,EAAA,IAAI,IAAA,KAAS,IAAA,EAAM,OAAO,OAAO,YAAY,CAAA;AAC7C,EAAA,IAAI,OAAO,IAAA,KAAS,QAAA,EAAU,OAAO;AAAA;AAAA;AAAA,IAAoD;AAAA,GAAA;AACzF,EAAA,IAAI,OAAO,SAAS,UAAA,EAAY,OAAO,QAAQ,OAAA,EAAQ,CAAE,KAAK,IAAI,CAAA;AAClE,EAAA,OAAO,OAAA,CAAQ,QAAQ,IAAI,CAAA;AAC7B;AAEA,SAAS,SAAS,IAAA,EAAuC;AACvD,EAAA,IAAI,IAAA,KAAS,MAAM,OAAO,sEAAA;AAC1B,EAAA,IAAI,OAAO,IAAA,KAAS,QAAA,EAAU,OAAO,IAAA;AACrC,EAAA,IAAI,OAAO,IAAA,KAAS,UAAA,EAAY,OAAO,uCAAA;AACvC,EAAA,OAAO,qCAAA;AACT","file":"chunk-K3XOEC3C.js","sourcesContent":["// mediabunny (about 180 KB gzipped) is what writes a video file and decodes a `video` layer. A page that only plays never needs it, so it is\n// fetched the first time something asks for it: `movie.render()`, a video asset. Nothing imports it at the top of a module.\nimport type * as Mediabunny from 'mediabunny';\n\n/** The mediabunny module, as `import * as mb from 'mediabunny'` gives it. */\nexport type MediabunnyModule = typeof Mediabunny;\n\n/**\n * Where mediabunny comes from, for {@link useMediabunny}:\n * - the module itself (`import * as mb from 'mediabunny'`: it is ready, nothing is fetched),\n * - a URL to `import()` (a page with no import map entry for it),\n * - a function that returns the module (`() => import('mediabunny')`, your own copy, a bundler chunk).\n */\nexport type MediabunnySource = MediabunnyModule | string | (() => Promise<MediabunnyModule>);\n\nlet source: MediabunnySource | null = null;\nlet pending: Promise<MediabunnyModule> | null = null;\n\n/**\n * Says where mediabunny comes from. Without it, the bare name `'mediabunny'` is imported the first time it is needed, which your bundler or the\n * page's import map resolves. A page that only plays (no export, no `video` layer) needs neither this nor an import map entry for it.\n * Calling it again replaces the source for the next load; a module that was already loaded stays in use by what holds it.\n */\nexport function useMediabunny(from: MediabunnySource): void {\n if (from == null || (typeof from !== 'string' && typeof from !== 'function' && typeof from !== 'object')) {\n throw new TypeError(`pixi-effects: useMediabunny() takes the mediabunny module, a URL or a function that returns the module; it got ${String(from)}`);\n }\n source = from;\n pending = null;\n}\n\n/** The mediabunny module, fetched once (the first call starts it; later calls share it). A failed load is tried again on the next call. */\nexport function loadMediabunny(): Promise<MediabunnyModule> {\n if (!pending) {\n const from = source;\n const p = fetchModule(from).then(\n (mod) => {\n if (!mod || typeof (mod as { Output?: unknown }).Output !== 'function') {\n throw new Error(`pixi-effects: ${describe(from)} did not give the mediabunny module (no Output in it). ${HOW}`);\n }\n return mod;\n },\n (err: unknown) => {\n const why = err instanceof Error ? err.message : String(err);\n throw new Error(`pixi-effects: could not load mediabunny from ${describe(from)} (${why}). ${HOW}`, { cause: err });\n },\n );\n pending = p;\n p.catch(() => { if (pending === p) pending = null; }); // the next call tries again (a network blip, an import map added later)\n }\n return pending;\n}\n\nconst HOW = 'mediabunny is needed to export (movie.render(), the download button) and for a video layer; playing needs nothing. '\n + 'Add it to the import map (\"mediabunny\": \"https://cdn.jsdelivr.net/npm/mediabunny@1/+esm\"), install it next to pixi-effects, '\n + 'or call useMediabunny(module | url | () => import(...)) before you export.';\n\nfunction fetchModule(from: MediabunnySource | null): Promise<MediabunnyModule> {\n if (from === null) return import('mediabunny');\n if (typeof from === 'string') return import(/* @vite-ignore */ /* webpackIgnore: true */ from) as Promise<MediabunnyModule>;\n if (typeof from === 'function') return Promise.resolve().then(from);\n return Promise.resolve(from);\n}\n\nfunction describe(from: MediabunnySource | null): string {\n if (from === null) return \"'mediabunny' (the bare name: an import map or a bundler resolves it)\";\n if (typeof from === 'string') return from;\n if (typeof from === 'function') return 'the function given to useMediabunny()';\n return 'the object given to useMediabunny()';\n}\n"]}
@@ -1,13 +1,13 @@
1
1
  'use strict';
2
2
 
3
3
  var chunkOGLRSR6C_cjs = require('./chunk-OGLRSR6C.cjs');
4
+ var chunkVQXZ2NOI_cjs = require('./chunk-VQXZ2NOI.cjs');
4
5
  var chunkECLBZV4N_cjs = require('./chunk-ECLBZV4N.cjs');
5
6
  var chunkZAHCGFGC_cjs = require('./chunk-ZAHCGFGC.cjs');
6
7
  var chunkWYR2AU4W_cjs = require('./chunk-WYR2AU4W.cjs');
7
8
  var chunkNGJXVJB7_cjs = require('./chunk-NGJXVJB7.cjs');
8
9
  var chunkDOLTCXCL_cjs = require('./chunk-DOLTCXCL.cjs');
9
10
  var pixi_js = require('pixi.js');
10
- var mediabunny = require('mediabunny');
11
11
 
12
12
  // src/core/gpuShare.ts
13
13
  function sharedGpuOf(renderer) {
@@ -43,8 +43,9 @@ function ensureLoadersRegistered(audioContext) {
43
43
  extension: { type: pixi_js.ExtensionType.LoadParser, name: "pixi-effects-video", priority: 1 },
44
44
  test: (url) => /\.(mp4|webm|mov|mkv)$/i.test(url),
45
45
  async load(url) {
46
- const blob = await fetch(url).then((r) => r.blob());
47
- const input = new mediabunny.Input({ source: new mediabunny.BlobSource(blob), formats: mediabunny.ALL_FORMATS });
46
+ const [M, blob] = await Promise.all([chunkVQXZ2NOI_cjs.loadMediabunny(), fetch(url).then((r) => r.blob())]);
47
+ const { Input, BlobSource, ALL_FORMATS, Output, WavOutputFormat, BufferTarget, Conversion, VideoSampleSink } = M;
48
+ const input = new Input({ source: new BlobSource(blob), formats: ALL_FORMATS });
48
49
  const videoTrack = await input.getPrimaryVideoTrack();
49
50
  if (!videoTrack || !await videoTrack.canDecode()) {
50
51
  throw new Error("pixi-effects: video track cannot be decoded");
@@ -55,8 +56,8 @@ function ensureLoadersRegistered(audioContext) {
55
56
  let audioBuffer = null;
56
57
  if (audioTrack) {
57
58
  try {
58
- const out = new mediabunny.Output({ format: new mediabunny.WavOutputFormat(), target: new mediabunny.BufferTarget() });
59
- const conv = await mediabunny.Conversion.init({ input, output: out, video: { discard: true } });
59
+ const out = new Output({ format: new WavOutputFormat(), target: new BufferTarget() });
60
+ const conv = await Conversion.init({ input, output: out, video: { discard: true } });
60
61
  await conv.execute();
61
62
  audioBuffer = await audioContext.decodeAudioData(out.target.buffer);
62
63
  } catch (e) {
@@ -69,7 +70,7 @@ function ensureLoadersRegistered(audioContext) {
69
70
  videoDuration,
70
71
  audioDuration,
71
72
  duration: Math.max(videoDuration, audioDuration),
72
- sink: new mediabunny.VideoSampleSink(videoTrack)
73
+ sink: new VideoSampleSink(videoTrack)
73
74
  };
74
75
  }
75
76
  });
@@ -600,10 +601,10 @@ var AUDIO_PREFERENCE = {
600
601
  mkv: ["opus", "vorbis", "aac", "flac", "mp3"],
601
602
  ogg: ["opus", "vorbis", "flac"]
602
603
  };
603
- async function chooseAudioCodec(fmt, requested, container, audio, bitrate) {
604
+ async function chooseAudioCodec(M, fmt, requested, container, audio, bitrate) {
604
605
  const supported = container.getSupportedAudioCodecs?.();
605
606
  const preferred = AUDIO_PREFERENCE[fmt].filter((c) => !supported || supported.includes(c));
606
- const canEncode = (list) => mediabunny.getFirstEncodableAudioCodec(list, { numberOfChannels: audio.numberOfChannels ?? 2, sampleRate: audio.sampleRate, bitrate });
607
+ const canEncode = (list) => M.getFirstEncodableAudioCodec(list, { numberOfChannels: audio.numberOfChannels ?? 2, sampleRate: audio.sampleRate, bitrate });
607
608
  if (requested) {
608
609
  if (await canEncode([requested])) return requested;
609
610
  const alt = await canEncode(preferred.filter((c) => c !== requested));
@@ -616,27 +617,34 @@ async function chooseAudioCodec(fmt, requested, container, audio, bitrate) {
616
617
  }
617
618
  return chosen;
618
619
  }
619
- var qualityMap = {
620
- "very-low": mediabunny.QUALITY_VERY_LOW,
621
- "low": mediabunny.QUALITY_LOW,
622
- "medium": mediabunny.QUALITY_MEDIUM,
623
- "high": mediabunny.QUALITY_HIGH,
624
- "very-high": mediabunny.QUALITY_VERY_HIGH
625
- };
626
- function bitrateOf(v, fallback) {
620
+ function qualityOf(M, name) {
621
+ switch (name) {
622
+ case "very-low":
623
+ return M.QUALITY_VERY_LOW;
624
+ case "low":
625
+ return M.QUALITY_LOW;
626
+ case "medium":
627
+ return M.QUALITY_MEDIUM;
628
+ case "very-high":
629
+ return M.QUALITY_VERY_HIGH;
630
+ default:
631
+ return M.QUALITY_HIGH;
632
+ }
633
+ }
634
+ function bitrateOf(M, v) {
627
635
  const b = parseBitrate(v);
628
- return b.bps ?? (b.quality ? qualityMap[b.quality] : fallback);
636
+ return b.bps ?? qualityOf(M, b.quality ?? "high");
629
637
  }
630
- function makeOutputFormat(name) {
638
+ function makeOutputFormat(M, name) {
631
639
  switch (name) {
632
640
  case "mp4":
633
- return new mediabunny.Mp4OutputFormat({ fastStart: "in-memory" });
641
+ return new M.Mp4OutputFormat({ fastStart: "in-memory" });
634
642
  case "mov":
635
- return new mediabunny.MovOutputFormat({ fastStart: "in-memory" });
643
+ return new M.MovOutputFormat({ fastStart: "in-memory" });
636
644
  case "webm":
637
- return new mediabunny.WebMOutputFormat();
645
+ return new M.WebMOutputFormat();
638
646
  case "mkv":
639
- return new mediabunny.MkvOutputFormat();
647
+ return new M.MkvOutputFormat();
640
648
  }
641
649
  }
642
650
  function sliceAudio(buffer, fromSec, toSec, fadeIn, fadeOut) {
@@ -651,18 +659,19 @@ async function exportAudioOnly(movie, options, fmt, range2) {
651
659
  throw new Error(`pixi-effects: render({ format: '${fmt}' }): this movie has no sound to export (add an audio layer, an sfx or a music score); for the picture use mp4, webm, mov or mkv`);
652
660
  }
653
661
  if (options.video) console.warn(`pixi-effects: render({ format: '${fmt}' }): video options are ignored, only the sound is written`);
662
+ const M = await chunkVQXZ2NOI_cjs.loadMediabunny();
654
663
  const audio = range2.partial ? sliceAudio(movie.audioBuffer, range2.fromSec, range2.toSec, range2.fromFrame > 0, range2.toFrame < movie.totalFrames) : movie.audioBuffer;
655
- const container = fmt === "wav" ? new mediabunny.WavOutputFormat() : new mediabunny.OggOutputFormat();
664
+ const container = fmt === "wav" ? new M.WavOutputFormat() : new M.OggOutputFormat();
656
665
  let codec;
657
666
  if (fmt === "wav") {
658
667
  codec = options.audio?.codec ?? "pcm-s16";
659
668
  const held = container.getSupportedAudioCodecs();
660
669
  if (!held.includes(codec)) throw new Error(`pixi-effects: render({ format: 'wav', audio: { codec: "${codec}" } }): wav holds ${held.join(", ")} (the usual is pcm-s16)`);
661
670
  } else {
662
- codec = await chooseAudioCodec("ogg", options.audio?.codec, container, audio, bitrateOf(options.audio?.bitrate, mediabunny.QUALITY_HIGH));
671
+ codec = await chooseAudioCodec(M, "ogg", options.audio?.codec, container, audio, bitrateOf(M, options.audio?.bitrate));
663
672
  }
664
- const output = new mediabunny.Output({ format: container, target: new mediabunny.BufferTarget() });
665
- const source = new mediabunny.AudioBufferSource({ codec, ...fmt === "wav" ? {} : { bitrate: bitrateOf(options.audio?.bitrate, mediabunny.QUALITY_HIGH) } });
673
+ const output = new M.Output({ format: container, target: new M.BufferTarget() });
674
+ const source = new M.AudioBufferSource({ codec, ...fmt === "wav" ? {} : { bitrate: bitrateOf(M, options.audio?.bitrate) } });
666
675
  output.addAudioTrack(source);
667
676
  movie.emit("progress", { progress: 0, frame: range2.fromFrame, totalFrames: movie.totalFrames });
668
677
  await output.start();
@@ -680,21 +689,22 @@ async function exportFrames(movie, options = {}) {
680
689
  if (!["mp4", "mov", "webm", "mkv"].includes(fmt)) throw new Error(`pixi-effects: render({ format: "${String(fmt)}" }): use mp4, mov, webm, mkv (a picture) or wav, ogg (only the sound)`);
681
690
  chunkDOLTCXCL_cjs.warnUnknownOptions("movie.render({ video })", options.video, ["codec", "bitrate", "hardware", "keyFrameInterval"]);
682
691
  chunkDOLTCXCL_cjs.warnUnknownOptions("movie.render({ audio })", options.audio, ["codec", "bitrate"]);
683
- const videoBitrate = bitrateOf(eff.bitrate ?? "high", mediabunny.QUALITY_HIGH);
692
+ const M = await chunkVQXZ2NOI_cjs.loadMediabunny();
693
+ const videoBitrate = bitrateOf(M, eff.bitrate ?? "high");
684
694
  const opts = {
685
695
  format: fmt,
686
696
  video: { codec: "", bitrate: videoBitrate },
687
697
  audio: {
688
698
  codec: options.audio?.codec ?? (fmt === "mp4" || fmt === "mov" ? "aac" : "opus"),
689
- bitrate: bitrateOf(options.audio?.bitrate, mediabunny.QUALITY_HIGH)
699
+ bitrate: bitrateOf(M, options.audio?.bitrate)
690
700
  }
691
701
  };
692
- const container = makeOutputFormat(opts.format);
702
+ const container = makeOutputFormat(M, opts.format);
693
703
  const audio = movie.audioBuffer && range2.partial ? sliceAudio(movie.audioBuffer, range2.fromSec, range2.toSec, range2.fromFrame > 0, range2.toFrame < movie.totalFrames) : movie.audioBuffer;
694
- if (audio) opts.audio.codec = await chooseAudioCodec(fmt, options.audio?.codec, container, audio, opts.audio.bitrate);
695
- const output = new mediabunny.Output({
704
+ if (audio) opts.audio.codec = await chooseAudioCodec(M, fmt, options.audio?.codec, container, audio, opts.audio.bitrate);
705
+ const output = new M.Output({
696
706
  format: container,
697
- target: new mediabunny.BufferTarget()
707
+ target: new M.BufferTarget()
698
708
  });
699
709
  const mb = eff.motionBlur !== void 0 ? resolveMotionBlur(eff.motionBlur, "movie.render()") : movie.motionBlur ?? null;
700
710
  const stage = movie.app.canvas;
@@ -706,7 +716,7 @@ async function exportFrames(movie, options = {}) {
706
716
  fmt,
707
717
  requested: options.video?.codec,
708
718
  supported: container.getSupportedVideoCodecs(),
709
- canEncode: (c) => mediabunny.canEncodeVideo(c, { width: picture.width, height: picture.height, bitrate: opts.video.bitrate })
719
+ canEncode: (c) => M.canEncodeVideo(c, { width: picture.width, height: picture.height, bitrate: opts.video.bitrate })
710
720
  });
711
721
  if (chosen.fellBackFrom) console.warn(`pixi-effects: this browser cannot encode ${chosen.fellBackFrom.toUpperCase()} video, so the ${fmt} carries ${chosen.codec.toUpperCase()} instead (name a codec with render({ video: { codec } }) to choose yourself).`);
712
722
  opts.video.codec = chosen.codec;
@@ -714,14 +724,14 @@ async function exportFrames(movie, options = {}) {
714
724
  if (hardware !== void 0 && !["no-preference", "prefer-hardware", "prefer-software"].includes(hardware)) {
715
725
  throw new Error(`pixi-effects: render({ video: { hardware: "${String(hardware)}" } }): use 'prefer-hardware', 'prefer-software' or 'no-preference'`);
716
726
  }
717
- const canvasSource = new mediabunny.CanvasSource(picture, {
727
+ const canvasSource = new M.CanvasSource(picture, {
718
728
  codec: opts.video.codec,
719
729
  bitrate: opts.video.bitrate,
720
730
  ...hardware ? { hardwareAcceleration: hardware } : {}
721
731
  });
722
732
  output.addVideoTrack(canvasSource, { frameRate: movie.frameRate });
723
733
  if (audio) {
724
- const audioSource = new mediabunny.AudioBufferSource({
734
+ const audioSource = new M.AudioBufferSource({
725
735
  codec: opts.audio.codec,
726
736
  bitrate: opts.audio.bitrate
727
737
  }, { startTimestamp: opts.audio.codec === "aac" ? -2112 / audio.sampleRate : 0 });
@@ -5038,5 +5048,5 @@ exports.splitText = splitText;
5038
5048
  exports.stagger = stagger;
5039
5049
  exports.wiggle = wiggle;
5040
5050
  exports.withFade = withFade;
5041
- //# sourceMappingURL=chunk-2AT5WSSV.cjs.map
5042
- //# sourceMappingURL=chunk-2AT5WSSV.cjs.map
5051
+ //# sourceMappingURL=chunk-NGK4E536.cjs.map
5052
+ //# sourceMappingURL=chunk-NGK4E536.cjs.map