jassub 2.0.16 → 2.0.18

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,25 @@
1
+ export interface SubtitleCallbackMetadata {
2
+ fps: number;
3
+ processingDuration: number;
4
+ droppedFrames: number;
5
+ presentedFrames: number;
6
+ mistimedFrames: number;
7
+ presentationTime: DOMHighResTimeStamp;
8
+ expectedDisplayTime: DOMHighResTimeStamp;
9
+ width: number;
10
+ height: number;
11
+ mediaTime: number;
12
+ frameDelay: DOMHighResTimeStamp;
13
+ }
14
+ export declare class Debug {
15
+ fps: (delta: any) => number;
16
+ processingDuration: (delta: any) => number;
17
+ droppedFrames: number;
18
+ presentedFrames: number;
19
+ mistimedFrames: number;
20
+ _drop(): void;
21
+ _startTime: number;
22
+ _startFrame(): void;
23
+ onsubtitleFrameCallback?: (now: DOMHighResTimeStamp, metadata: SubtitleCallbackMetadata) => void;
24
+ _endFrame(meta: VideoFrameCallbackMetadata): void;
25
+ }
package/dist/debug.js ADDED
@@ -0,0 +1,41 @@
1
+ import throughput from 'throughput';
2
+ export class Debug {
3
+ // 5 second average
4
+ fps = throughput(5);
5
+ processingDuration = throughput(5);
6
+ droppedFrames = 0;
7
+ presentedFrames = 0;
8
+ mistimedFrames = 0;
9
+ _drop() {
10
+ ++this.droppedFrames;
11
+ }
12
+ _startTime = 0;
13
+ _startFrame() {
14
+ this._startTime = performance.now();
15
+ }
16
+ onsubtitleFrameCallback = console.log;
17
+ _endFrame(meta) {
18
+ ++this.presentedFrames;
19
+ const fps = this.fps(1);
20
+ const now = performance.now();
21
+ const processingDuration = this.processingDuration((now - this._startTime) / fps);
22
+ const frameDelay = Math.max(0, meta.expectedDisplayTime - now);
23
+ if (frameDelay)
24
+ ++this.mistimedFrames;
25
+ this.onsubtitleFrameCallback?.(now, {
26
+ fps,
27
+ processingDuration,
28
+ droppedFrames: this.droppedFrames,
29
+ presentedFrames: this.presentedFrames,
30
+ mistimedFrames: this.mistimedFrames,
31
+ presentationTime: now,
32
+ expectedDisplayTime: meta.expectedDisplayTime + (frameDelay > 0 ? fps / 1000 : 0),
33
+ frameDelay,
34
+ width: meta.width,
35
+ height: meta.height,
36
+ mediaTime: meta.mediaTime
37
+ });
38
+ console.info('%cFPS: %c%f %c| Frame Time: %c%d ms %c| Dropped Frames: %c%d %c| 5s Avg', 'color: #888', 'color: #0f0; font-weight: bold', fps.toFixed(1), 'color: #888', 'color: #0ff; font-weight: bold', processingDuration, 'color: #888', 'color: #f00; font-weight: bold', this.droppedFrames, 'color: #888');
39
+ }
40
+ }
41
+ //# sourceMappingURL=debug.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debug.js","sourceRoot":"","sources":["../src/debug.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,YAAY,CAAA;AAgBnC,MAAM,OAAO,KAAK;IAChB,mBAAmB;IACnB,GAAG,GAAG,UAAU,CAAC,CAAC,CAAC,CAAA;IACnB,kBAAkB,GAAG,UAAU,CAAC,CAAC,CAAC,CAAA;IAClC,aAAa,GAAG,CAAC,CAAA;IACjB,eAAe,GAAG,CAAC,CAAA;IACnB,cAAc,GAAG,CAAC,CAAA;IAElB,KAAK;QACH,EAAE,IAAI,CAAC,aAAa,CAAA;IACtB,CAAC;IAED,UAAU,GAAG,CAAC,CAAA;IACd,WAAW;QACT,IAAI,CAAC,UAAU,GAAG,WAAW,CAAC,GAAG,EAAE,CAAA;IACrC,CAAC;IAED,uBAAuB,GAA4E,OAAO,CAAC,GAAG,CAAA;IAE9G,SAAS,CAAE,IAAgC;QACzC,EAAE,IAAI,CAAC,eAAe,CAAA;QACtB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;QACvB,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,EAAE,CAAA;QAC7B,MAAM,kBAAkB,GAAG,IAAI,CAAC,kBAAkB,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC,CAAA;QACjF,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,mBAAmB,GAAG,GAAG,CAAC,CAAA;QAC9D,IAAI,UAAU;YAAE,EAAE,IAAI,CAAC,cAAc,CAAA;QAErC,IAAI,CAAC,uBAAuB,EAAE,CAAC,GAAG,EAAE;YAClC,GAAG;YACH,kBAAkB;YAClB,aAAa,EAAE,IAAI,CAAC,aAAa;YACjC,eAAe,EAAE,IAAI,CAAC,eAAe;YACrC,cAAc,EAAE,IAAI,CAAC,cAAc;YACnC,gBAAgB,EAAE,GAAG;YACrB,mBAAmB,EAAE,IAAI,CAAC,mBAAmB,GAAG,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;YACjF,UAAU;YACV,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,SAAS,EAAE,IAAI,CAAC,SAAS;SAC1B,CAAC,CAAA;QAEF,OAAO,CAAC,IAAI,CACV,yEAAyE,EACzE,aAAa,EACb,gCAAgC,EAChC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EACd,aAAa,EACb,gCAAgC,EAChC,kBAAkB,EAClB,aAAa,EACb,gCAAgC,EAChC,IAAI,CAAC,aAAa,EAClB,aAAa,CACd,CAAA;IACH,CAAC;CACF"}
Binary file
@@ -0,0 +1,138 @@
1
+ // TypeScript bindings for emscripten-generated code. Automatically generated at compile time.
2
+ declare namespace RuntimeExports {
3
+ function getTempRet0(val: any): any;
4
+ function setTempRet0(val: any): any;
5
+ }
6
+ interface WasmModule {
7
+ __ZdlPvm(_0: number, _1: number): void;
8
+ _malloc(_0: number): number;
9
+ _calloc(_0: number, _1: number): number;
10
+ _emscripten_builtin_free(_0: number): void;
11
+ ___libc_free(_0: number): void;
12
+ _emscripten_builtin_malloc(_0: number): number;
13
+ ___libc_malloc(_0: number): number;
14
+ __ZdaPv(_0: number): void;
15
+ __ZdaPvm(_0: number, _1: number): void;
16
+ __ZdlPv(_0: number): void;
17
+ __Znaj(_0: number): number;
18
+ __ZnajSt11align_val_t(_0: number, _1: number): number;
19
+ __Znwj(_0: number): number;
20
+ __ZnwjSt11align_val_t(_0: number, _1: number): number;
21
+ ___libc_calloc(_0: number, _1: number): number;
22
+ ___libc_realloc(_0: number, _1: number): number;
23
+ _emscripten_builtin_calloc(_0: number, _1: number): number;
24
+ _emscripten_builtin_realloc(_0: number, _1: number): number;
25
+ _malloc_size(_0: number): number;
26
+ _malloc_usable_size(_0: number): number;
27
+ _reallocf(_0: number, _1: number): number;
28
+ }
29
+
30
+ type EmbindString = ArrayBuffer|Uint8Array|Uint8ClampedArray|Int8Array|string;
31
+ export interface ClassHandle {
32
+ isAliasOf(other: ClassHandle): boolean;
33
+ delete(): void;
34
+ deleteLater(): this;
35
+ isDeleted(): boolean;
36
+ // @ts-ignore - If targeting lower than ESNext, this symbol might not exist.
37
+ [Symbol.dispose](): void;
38
+ clone(): this;
39
+ }
40
+ export interface ASS_Image extends ClassHandle {
41
+ readonly next: ASS_Image;
42
+ w: number;
43
+ h: number;
44
+ dst_x: number;
45
+ dst_y: number;
46
+ stride: number;
47
+ color: number;
48
+ readonly bitmap: number;
49
+ }
50
+
51
+ export interface ASS_Style extends ClassHandle {
52
+ Bold: number;
53
+ Italic: number;
54
+ Underline: number;
55
+ StrikeOut: number;
56
+ BorderStyle: number;
57
+ Alignment: number;
58
+ MarginL: number;
59
+ MarginR: number;
60
+ MarginV: number;
61
+ Encoding: number;
62
+ treat_fontname_as_pattern: number;
63
+ Justify: number;
64
+ PrimaryColour: number;
65
+ SecondaryColour: number;
66
+ OutlineColour: number;
67
+ BackColour: number;
68
+ FontSize: number;
69
+ ScaleX: number;
70
+ ScaleY: number;
71
+ Spacing: number;
72
+ Angle: number;
73
+ Outline: number;
74
+ Shadow: number;
75
+ Blur: number;
76
+ get Name(): string;
77
+ set Name(value: EmbindString);
78
+ get FontName(): string;
79
+ set FontName(value: EmbindString);
80
+ }
81
+
82
+ export interface ASS_Event extends ClassHandle {
83
+ ReadOrder: number;
84
+ Layer: number;
85
+ Style: number;
86
+ MarginL: number;
87
+ MarginR: number;
88
+ MarginV: number;
89
+ Start: number;
90
+ Duration: number;
91
+ get Name(): string;
92
+ set Name(value: EmbindString);
93
+ get Effect(): string;
94
+ set Effect(value: EmbindString);
95
+ get Text(): string;
96
+ set Text(value: EmbindString);
97
+ }
98
+
99
+ export interface JASSUB extends ClassHandle {
100
+ trackColorSpace: number;
101
+ changed: number;
102
+ count: number;
103
+ removeTrack(): void;
104
+ quitLibrary(): void;
105
+ reloadFonts(): void;
106
+ removeAllEvents(): void;
107
+ styleOverride(_0: ASS_Style): void;
108
+ disableStyleOverride(): void;
109
+ setLogLevel(_0: number): void;
110
+ resizeCanvas(_0: number, _1: number, _2: number, _3: number): void;
111
+ setMargin(_0: number, _1: number, _2: number, _3: number): void;
112
+ getEventCount(): number;
113
+ allocEvent(): number;
114
+ allocStyle(): number;
115
+ removeEvent(_0: number): void;
116
+ getStyleCount(): number;
117
+ removeStyle(_0: number): void;
118
+ setMemoryLimits(_0: number, _1: number): void;
119
+ getEvent(_0: number): ASS_Event | null;
120
+ getStyle(_0: number): ASS_Style | null;
121
+ setThreads(_0: number): number;
122
+ rawRender(_0: number, _1: number): ASS_Image | null;
123
+ createTrackMem(_0: EmbindString): void;
124
+ addFont(_0: EmbindString, _1: number, _2: number): void;
125
+ setDefaultFont(_0: EmbindString): void;
126
+ }
127
+
128
+ interface EmbindModule {
129
+ ASS_Image: {};
130
+ ASS_Style: {};
131
+ ASS_Event: {};
132
+ JASSUB: {
133
+ new(_0: number, _1: number, _2: EmbindString): JASSUB;
134
+ };
135
+ }
136
+
137
+ export type MainModule = WasmModule & typeof RuntimeExports & EmbindModule;
138
+ export default function MainModuleFactory (options?: unknown): Promise<MainModule>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jassub",
3
- "version": "2.0.16",
3
+ "version": "2.0.18",
4
4
  "description": "libass subtitle renderer for modern browsers",
5
5
  "main": "dist/jassub.js",
6
6
  "type": "module",
@@ -8,6 +8,7 @@
8
8
  "dist/wasm/*",
9
9
  "dist/worker/*",
10
10
  "dist/jassub.*",
11
+ "dist/debug.*",
11
12
  "!dist/wasm/jassub-worker-modern.js",
12
13
  "README.md",
13
14
  "LICENSE",
package/dist/jassub.js DELETED
@@ -1,286 +0,0 @@
1
- /* eslint-disable camelcase */
2
- import 'rvfc-polyfill';
3
- import { proxy, releaseProxy } from 'abslink';
4
- import { wrap } from 'abslink/w3c';
5
- import { Debug } from "./debug.js";
6
- const webYCbCrMap = {
7
- rgb: 'RGB',
8
- bt709: 'BT709',
9
- // these might not be exactly correct? oops?
10
- bt470bg: 'BT601', // alias BT.601 PAL... whats the difference?
11
- smpte170m: 'BT601' // alias BT.601 NTSC... whats the difference?
12
- };
13
- export default class JASSUB {
14
- timeOffset;
15
- prescaleFactor;
16
- prescaleHeightLimit;
17
- maxRenderHeight;
18
- debug;
19
- renderer;
20
- ready;
21
- busy = false;
22
- _video;
23
- _videoWidth = 0;
24
- _videoHeight = 0;
25
- _videoColorSpace = null;
26
- _canvas;
27
- _canvasParent;
28
- _ctrl = new AbortController();
29
- _ro = new ResizeObserver(() => this.resize());
30
- _destroyed = false;
31
- _lastDemandTime;
32
- _skipped = false;
33
- _worker;
34
- constructor(opts) {
35
- if (!globalThis.Worker)
36
- throw new Error('Worker not supported');
37
- if (!opts)
38
- throw new Error('No options provided');
39
- if (!opts.video && !opts.canvas)
40
- throw new Error('You should give video or canvas in options.');
41
- JASSUB._test();
42
- this.timeOffset = opts.timeOffset ?? 0;
43
- this._video = opts.video;
44
- this._canvas = opts.canvas ?? document.createElement('canvas');
45
- if (this._video && !opts.canvas) {
46
- this._canvasParent = document.createElement('div');
47
- this._canvasParent.className = 'JASSUB';
48
- this._canvasParent.style.position = 'relative';
49
- this._canvas.style.display = 'block';
50
- this._canvas.style.position = 'absolute';
51
- this._canvas.style.pointerEvents = 'none';
52
- this._canvasParent.appendChild(this._canvas);
53
- this._video.insertAdjacentElement('afterend', this._canvasParent);
54
- }
55
- const ctrl = this._canvas.transferControlToOffscreen();
56
- this.debug = opts.debug ? new Debug() : null;
57
- this.prescaleFactor = opts.prescaleFactor ?? 1.0;
58
- this.prescaleHeightLimit = opts.prescaleHeightLimit ?? 1080;
59
- this.maxRenderHeight = opts.maxRenderHeight ?? 0; // 0 - no limit.
60
- // yes this is awful, but bundlers check for new Worker(new URL()) patterns, so can't use new Worker(workerUrl ?? new URL(...)) ... bruh
61
- this._worker = opts.workerUrl
62
- ? new Worker(opts.workerUrl, { name: 'jassub-worker', type: 'module' })
63
- : new Worker(new URL('./worker/worker.js', import.meta.url), { name: 'jassub-worker', type: 'module' });
64
- const Renderer = wrap(this._worker);
65
- const modern = opts.modernWasmUrl ?? new URL('./wasm/jassub-worker-modern.wasm', import.meta.url).href;
66
- const fallback = opts.wasmUrl ?? new URL('./wasm/jassub-worker.wasm', import.meta.url).href;
67
- this.ready = (async () => {
68
- this.renderer = await new Renderer({
69
- wasmUrl: JASSUB._supportsSIMD ? modern : fallback,
70
- width: ctrl.width,
71
- height: ctrl.height,
72
- subUrl: opts.subUrl,
73
- subContent: opts.subContent ?? null,
74
- fonts: opts.fonts ?? [],
75
- availableFonts: opts.availableFonts ?? { 'liberation sans': './default.woff2' },
76
- fallbackFont: opts.fallbackFont ?? 'liberation sans',
77
- debug: !!opts.debug,
78
- libassMemoryLimit: opts.libassMemoryLimit ?? 0,
79
- libassGlyphLimit: opts.libassGlyphLimit ?? 0,
80
- // @ts-expect-error TS doesn't know about queryLocalFonts
81
- useLocalFonts: typeof queryLocalFonts !== 'undefined' && (opts.useLocalFonts ?? true)
82
- }, proxy(font => this._getLocalFont(font)));
83
- await this.renderer.ready();
84
- })();
85
- if (this._video)
86
- this.setVideo(this._video);
87
- this._worker.postMessage({ name: 'offscreenCanvas', ctrl }, [ctrl]);
88
- }
89
- static _supportsSIMD;
90
- static _test() {
91
- if (JASSUB._supportsSIMD != null)
92
- return;
93
- try {
94
- JASSUB._supportsSIMD = WebAssembly.validate(Uint8Array.of(0, 97, 115, 109, 1, 0, 0, 0, 1, 5, 1, 96, 0, 1, 123, 3, 2, 1, 0, 10, 10, 1, 8, 0, 65, 0, 253, 15, 253, 98, 11));
95
- }
96
- catch (e) {
97
- JASSUB._supportsSIMD = false;
98
- }
99
- const module = new WebAssembly.Module(Uint8Array.of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00));
100
- if (!(module instanceof WebAssembly.Module) || !(new WebAssembly.Instance(module) instanceof WebAssembly.Instance))
101
- throw new Error('WASM not supported');
102
- }
103
- async resize(force = !!this._video?.paused, width = 0, height = 0, top = 0, left = 0) {
104
- await this.ready;
105
- if ((!width || !height) && this._video) {
106
- const videoSize = this._getVideoPosition();
107
- let renderSize = null;
108
- // support anamorphic video
109
- if (this._videoWidth) {
110
- const widthRatio = this._video.videoWidth / this._videoWidth;
111
- const heightRatio = this._video.videoHeight / this._videoHeight;
112
- renderSize = this._computeCanvasSize((videoSize.width || 0) / widthRatio, (videoSize.height || 0) / heightRatio);
113
- }
114
- else {
115
- renderSize = this._computeCanvasSize(videoSize.width || 0, videoSize.height || 0);
116
- }
117
- width = renderSize.width;
118
- height = renderSize.height;
119
- if (this._canvasParent) {
120
- top = videoSize.y - (this._canvasParent.getBoundingClientRect().top - this._video.getBoundingClientRect().top);
121
- left = videoSize.x;
122
- }
123
- this._canvas.style.width = videoSize.width + 'px';
124
- this._canvas.style.height = videoSize.height + 'px';
125
- }
126
- this._canvas.style.top = top + 'px';
127
- this._canvas.style.left = left + 'px';
128
- await this.renderer._canvas(width, height, (this._videoWidth || this._video?.videoWidth) ?? width, (this._videoHeight || this._video?.videoHeight) ?? height);
129
- if (force && this._lastDemandTime)
130
- this._demandRender();
131
- }
132
- _getVideoPosition(width = this._video.videoWidth, height = this._video.videoHeight) {
133
- const videoRatio = width / height;
134
- const { offsetWidth, offsetHeight } = this._video;
135
- const elementRatio = offsetWidth / offsetHeight;
136
- width = offsetWidth;
137
- height = offsetHeight;
138
- if (elementRatio > videoRatio) {
139
- width = Math.floor(offsetHeight * videoRatio);
140
- }
141
- else {
142
- height = Math.floor(offsetWidth / videoRatio);
143
- }
144
- const x = (offsetWidth - width) / 2;
145
- const y = (offsetHeight - height) / 2;
146
- return { width, height, x, y };
147
- }
148
- _computeCanvasSize(width = 0, height = 0) {
149
- const scalefactor = this.prescaleFactor <= 0 ? 1.0 : this.prescaleFactor;
150
- const ratio = self.devicePixelRatio || 1;
151
- if (height <= 0 || width <= 0) {
152
- width = 0;
153
- height = 0;
154
- }
155
- else {
156
- const sgn = scalefactor < 1 ? -1 : 1;
157
- let newH = height * ratio;
158
- if (sgn * newH * scalefactor <= sgn * this.prescaleHeightLimit) {
159
- newH *= scalefactor;
160
- }
161
- else if (sgn * newH < sgn * this.prescaleHeightLimit) {
162
- newH = this.prescaleHeightLimit;
163
- }
164
- if (this.maxRenderHeight > 0 && newH > this.maxRenderHeight)
165
- newH = this.maxRenderHeight;
166
- width *= newH / height;
167
- height = newH;
168
- }
169
- return { width, height };
170
- }
171
- async setVideo(video) {
172
- await this.ready;
173
- if (video instanceof HTMLVideoElement) {
174
- this._removeListeners();
175
- this._video = video;
176
- this._video.requestVideoFrameCallback((now, data) => this._handleRVFC(data));
177
- // everything else is unreliable for this, loadedmetadata and loadeddata included.
178
- if ('VideoFrame' in globalThis) {
179
- video.addEventListener('loadedmetadata', () => this._updateColorSpace(), this._ctrl);
180
- if (video.readyState > 2)
181
- this._updateColorSpace();
182
- }
183
- if (video.videoWidth > 0)
184
- this.resize();
185
- this._ro.observe(video);
186
- }
187
- else {
188
- throw new Error('Video element invalid!');
189
- }
190
- }
191
- async _sendLocalFont(name) {
192
- try {
193
- // @ts-expect-error ts doesnt know
194
- const fontData = await queryLocalFonts();
195
- // @ts-expect-error ts doesnt know
196
- const font = fontData?.find(obj => obj.fullName.toLowerCase() === name);
197
- if (font) {
198
- const blob = await font.blob();
199
- this.renderer.addFont(new Uint8Array(await blob.arrayBuffer()));
200
- }
201
- }
202
- catch (e) {
203
- console.warn('Local fonts API:', e);
204
- }
205
- }
206
- async _getLocalFont(font) {
207
- try {
208
- // electron by default has all permissions enabled, and it doesn't have perm query
209
- // if this happens, just send it
210
- if (navigator?.permissions?.query) {
211
- // @ts-expect-error TS doesn't know about local-fonts
212
- const permission = await navigator.permissions.query({ name: 'local-fonts' });
213
- if (permission.state === 'granted') {
214
- await this._sendLocalFont(font);
215
- }
216
- }
217
- else {
218
- await this._sendLocalFont(font);
219
- }
220
- }
221
- catch (e) {
222
- console.warn('Local fonts API:', e);
223
- }
224
- }
225
- _handleRVFC(data) {
226
- if (this._destroyed)
227
- return;
228
- this._lastDemandTime = data;
229
- this._demandRender();
230
- this._video.requestVideoFrameCallback((now, data) => this._handleRVFC(data));
231
- }
232
- async _demandRender() {
233
- const { mediaTime, width, height } = this._lastDemandTime;
234
- if (width !== this._videoWidth || height !== this._videoHeight) {
235
- this._videoWidth = width;
236
- this._videoHeight = height;
237
- this.resize(false);
238
- }
239
- if (this.busy) {
240
- this._skipped = true;
241
- this.debug?._drop();
242
- return;
243
- }
244
- this.busy = true;
245
- this._skipped = false;
246
- this.debug?._startFrame();
247
- await this.renderer._draw(mediaTime + this.timeOffset);
248
- this.debug?._endFrame(this._lastDemandTime);
249
- this.busy = false;
250
- if (this._skipped)
251
- this._demandRender();
252
- }
253
- async _updateColorSpace() {
254
- await this.ready;
255
- this._video.requestVideoFrameCallback(async () => {
256
- try {
257
- const frame = new VideoFrame(this._video);
258
- frame.close();
259
- await this.renderer._setColorSpace(webYCbCrMap[frame.colorSpace.matrix]);
260
- }
261
- catch (e) {
262
- // sources can be tainted
263
- console.warn(e);
264
- }
265
- });
266
- }
267
- _removeListeners() {
268
- if (this._video) {
269
- if (this._ro)
270
- this._ro.unobserve(this._video);
271
- this._ctrl.abort();
272
- this._ctrl = new AbortController();
273
- }
274
- }
275
- async destroy() {
276
- if (this._destroyed)
277
- return;
278
- this._destroyed = true;
279
- if (this._video && this._canvasParent)
280
- this._video.parentNode?.removeChild(this._canvasParent);
281
- this._removeListeners();
282
- await this.renderer[releaseProxy]();
283
- this._worker.terminate();
284
- }
285
- }
286
- //# sourceMappingURL=jassub.js.map