@sangwonl/pocato-core 0.4.10 → 0.4.11

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/dist/index.js CHANGED
@@ -2028,6 +2028,9 @@ var FaceRenderer = class {
2028
2028
  this.loadedLayers = [];
2029
2029
  this.layerLoadVersion = 0;
2030
2030
  this.layerLoadAbort = null;
2031
+ this.videoActivationVersion = 0;
2032
+ this.videoActivationAbort = null;
2033
+ this.destroyed = false;
2031
2034
  bootstrapShaders();
2032
2035
  this.scene = new THREE3.Scene();
2033
2036
  this.camera = new THREE3.Camera();
@@ -2078,6 +2081,9 @@ var FaceRenderer = class {
2078
2081
  }
2079
2082
  async loadLayers(layers, onError) {
2080
2083
  const version = ++this.layerLoadVersion;
2084
+ this.videoActivationVersion++;
2085
+ this.videoActivationAbort?.abort();
2086
+ this.videoActivationAbort = null;
2081
2087
  this.layerLoadAbort?.abort();
2082
2088
  const abort = new AbortController();
2083
2089
  this.layerLoadAbort = abort;
@@ -2117,16 +2123,25 @@ var FaceRenderer = class {
2117
2123
  this.material.uniforms.uResolution.value.set(width, height);
2118
2124
  }
2119
2125
  async playLoadedVideos() {
2126
+ const activationVersion = ++this.videoActivationVersion;
2127
+ this.videoActivationAbort?.abort();
2128
+ const activationAbort = new AbortController();
2129
+ this.videoActivationAbort = activationAbort;
2120
2130
  await Promise.all(this.loadedLayers.map(async (loaded, i) => {
2131
+ if (this.destroyed || activationAbort.signal.aborted || activationVersion !== this.videoActivationVersion) return;
2121
2132
  if (!loaded.liveTexture) {
2122
2133
  loaded.play?.();
2123
2134
  return;
2124
2135
  }
2125
2136
  loaded.play?.();
2126
- if (await waitForVideoFrame(loaded.videoEl)) {
2137
+ const hasFrame = await waitForVideoFrame(loaded.videoEl, activationAbort.signal);
2138
+ if (hasFrame && !this.destroyed && !activationAbort.signal.aborted && activationVersion === this.videoActivationVersion) {
2127
2139
  this.material.uniforms[`uLayer${i}`].value = loaded.liveTexture;
2128
2140
  }
2129
2141
  }));
2142
+ if (this.videoActivationAbort === activationAbort) {
2143
+ this.videoActivationAbort = null;
2144
+ }
2130
2145
  }
2131
2146
  updateShader(fragmentShader) {
2132
2147
  this.material.fragmentShader = resolveIncludes(fragmentShader);
@@ -2144,7 +2159,11 @@ var FaceRenderer = class {
2144
2159
  this.material.uniforms.uLayerCount.value = 0;
2145
2160
  }
2146
2161
  destroy() {
2162
+ this.destroyed = true;
2147
2163
  this.layerLoadVersion++;
2164
+ this.videoActivationVersion++;
2165
+ this.videoActivationAbort?.abort();
2166
+ this.videoActivationAbort = null;
2148
2167
  this.layerLoadAbort?.abort();
2149
2168
  this.layerLoadAbort = null;
2150
2169
  this.disposeLayers();
@@ -2152,17 +2171,37 @@ var FaceRenderer = class {
2152
2171
  this.material.dispose();
2153
2172
  }
2154
2173
  };
2155
- function waitForVideoFrame(video) {
2174
+ function waitForVideoFrame(video, signal) {
2156
2175
  return new Promise((resolve) => {
2176
+ if (signal?.aborted) {
2177
+ resolve(false);
2178
+ return;
2179
+ }
2180
+ let settled = false;
2181
+ let timeoutId = null;
2182
+ let videoFrameId = null;
2183
+ const finish = (hasFrame) => {
2184
+ if (settled) return;
2185
+ settled = true;
2186
+ if (timeoutId != null) globalThis.clearTimeout(timeoutId);
2187
+ if (video && videoFrameId != null && "cancelVideoFrameCallback" in video) {
2188
+ video.cancelVideoFrameCallback(videoFrameId);
2189
+ }
2190
+ signal?.removeEventListener("abort", abort);
2191
+ resolve(hasFrame);
2192
+ };
2193
+ const abort = () => finish(false);
2157
2194
  if (video && "requestVideoFrameCallback" in video) {
2158
- const timeoutId = globalThis.setTimeout(() => resolve(false), VIDEO_FRAME_WAIT_TIMEOUT_MS);
2159
- video.requestVideoFrameCallback(() => {
2160
- globalThis.clearTimeout(timeoutId);
2161
- resolve(true);
2162
- });
2195
+ timeoutId = globalThis.setTimeout(() => finish(false), VIDEO_FRAME_WAIT_TIMEOUT_MS);
2196
+ signal?.addEventListener("abort", abort, { once: true });
2197
+ videoFrameId = video.requestVideoFrameCallback(() => finish(true));
2163
2198
  return;
2164
2199
  }
2165
- requestAnimationFrame(() => resolve(true));
2200
+ const rafId2 = requestAnimationFrame(() => finish(true));
2201
+ signal?.addEventListener("abort", () => {
2202
+ cancelAnimationFrame(rafId2);
2203
+ finish(false);
2204
+ }, { once: true });
2166
2205
  });
2167
2206
  }
2168
2207
  function toThreeUniformValue(value) {