jassub 1.7.18 → 1.7.20
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/jassub-worker-modern.wasm +0 -0
- package/dist/jassub-worker.js +15 -15
- package/dist/jassub-worker.wasm +0 -0
- package/dist/jassub-worker.wasm.js +1 -1
- package/dist/jassub.es.js +71 -61
- package/dist/jassub.umd.js +1 -1
- package/package.json +1 -1
- package/src/jassub.js +0 -2
package/dist/jassub.es.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
typeof HTMLVideoElement < "u" && !("requestVideoFrameCallback" in HTMLVideoElement.prototype) && "getVideoPlaybackQuality" in HTMLVideoElement.prototype && (HTMLVideoElement.prototype._rvfcpolyfillmap = {}, HTMLVideoElement.prototype.requestVideoFrameCallback = function(c) {
|
|
2
|
-
const e = performance.now(), t = this.getVideoPlaybackQuality(), s = this.mozPresentedFrames || this.mozPaintedFrames || t.totalVideoFrames - t.droppedVideoFrames,
|
|
3
|
-
const
|
|
2
|
+
const e = performance.now(), t = this.getVideoPlaybackQuality(), s = this.mozPresentedFrames || this.mozPaintedFrames || t.totalVideoFrames - t.droppedVideoFrames, r = (n, a) => {
|
|
3
|
+
const i = this.getVideoPlaybackQuality(), h = this.mozPresentedFrames || this.mozPaintedFrames || i.totalVideoFrames - i.droppedVideoFrames;
|
|
4
4
|
if (h > s) {
|
|
5
|
-
const d = this.mozFrameDelay ||
|
|
6
|
-
c(
|
|
7
|
-
presentationTime:
|
|
8
|
-
expectedDisplayTime:
|
|
5
|
+
const d = this.mozFrameDelay || i.totalFrameDelay - t.totalFrameDelay || 0, l = a - n;
|
|
6
|
+
c(a, {
|
|
7
|
+
presentationTime: a + d * 1e3,
|
|
8
|
+
expectedDisplayTime: a + l,
|
|
9
9
|
width: this.videoWidth,
|
|
10
10
|
height: this.videoHeight,
|
|
11
11
|
mediaTime: Math.max(0, this.currentTime || 0) + l / 1e3,
|
|
@@ -13,9 +13,9 @@ typeof HTMLVideoElement < "u" && !("requestVideoFrameCallback" in HTMLVideoEleme
|
|
|
13
13
|
processingDuration: d
|
|
14
14
|
}), delete this._rvfcpolyfillmap[e];
|
|
15
15
|
} else
|
|
16
|
-
this._rvfcpolyfillmap[e] = requestAnimationFrame((d) =>
|
|
16
|
+
this._rvfcpolyfillmap[e] = requestAnimationFrame((d) => r(a, d));
|
|
17
17
|
};
|
|
18
|
-
return this._rvfcpolyfillmap[e] = requestAnimationFrame((n) =>
|
|
18
|
+
return this._rvfcpolyfillmap[e] = requestAnimationFrame((n) => r(e, n)), e;
|
|
19
19
|
}, HTMLVideoElement.prototype.cancelVideoFrameCallback = function(c) {
|
|
20
20
|
cancelAnimationFrame(this._rvfcpolyfillmap[c]), delete this._rvfcpolyfillmap[c];
|
|
21
21
|
});
|
|
@@ -73,8 +73,10 @@ class o extends EventTarget {
|
|
|
73
73
|
* @param {Number} [options.libassGlyphLimit] libass glyph cache memory limit in MiB (approximate).
|
|
74
74
|
*/
|
|
75
75
|
constructor(e) {
|
|
76
|
-
if (super(), !globalThis.Worker)
|
|
77
|
-
|
|
76
|
+
if (super(), !globalThis.Worker)
|
|
77
|
+
throw this.destroy("Worker not supported");
|
|
78
|
+
if (!e)
|
|
79
|
+
throw this.destroy("No options provided");
|
|
78
80
|
this._loaded = /** @type {Promise<void>} */
|
|
79
81
|
new Promise((s) => {
|
|
80
82
|
this._init = s;
|
|
@@ -84,7 +86,8 @@ class o extends EventTarget {
|
|
|
84
86
|
this._canvasParent = document.createElement("div"), this._canvasParent.className = "JASSUB", this._canvasParent.style.position = "relative", this._canvas = this._createCanvas(), this._video.insertAdjacentElement("afterend", this._canvasParent);
|
|
85
87
|
else if (!this._canvas)
|
|
86
88
|
throw this.destroy("Don't know where to render: you should give video or canvas in options.");
|
|
87
|
-
if (this._bufferCanvas = document.createElement("canvas"), this._bufferCtx = this._bufferCanvas.getContext("2d"), !this._bufferCtx)
|
|
89
|
+
if (this._bufferCanvas = document.createElement("canvas"), this._bufferCtx = this._bufferCanvas.getContext("2d"), !this._bufferCtx)
|
|
90
|
+
throw this.destroy("Canvas rendering not supported");
|
|
88
91
|
this._canvasctrl = this._offscreenRender ? this._canvas.transferControlToOffscreen() : this._canvas, this._ctx = !this._offscreenRender && this._canvasctrl.getContext("2d"), this._lastRenderTime = 0, this.debug = !!e.debug, this.prescaleFactor = e.prescaleFactor || 1, this.prescaleHeightLimit = e.prescaleHeightLimit || 1080, this.maxRenderHeight = e.maxRenderHeight || 0, this._boundResize = this.resize.bind(this), this._boundTimeUpdate = this._timeupdate.bind(this), this._boundSetRate = this.setRate.bind(this), this._boundUpdateColorSpace = this._updateColorSpace.bind(this), this._video && this.setVideo(e.video), this._onDemandRender && (this.busy = !1, this._lastDemandTime = null), this._worker = new Worker(e.workerUrl || "jassub-worker.js"), this._worker.onmessage = (s) => this._onmessage(s), this._worker.onerror = (s) => this._error(s), t.then(() => {
|
|
89
92
|
this._worker.postMessage({
|
|
90
93
|
target: "init",
|
|
@@ -131,9 +134,11 @@ class o extends EventTarget {
|
|
|
131
134
|
}
|
|
132
135
|
}
|
|
133
136
|
static async _testImageBugs() {
|
|
134
|
-
if (o._hasBitmapBug !== null)
|
|
137
|
+
if (o._hasBitmapBug !== null)
|
|
138
|
+
return;
|
|
135
139
|
const e = document.createElement("canvas"), t = e.getContext("2d", { willReadFrequently: !0 });
|
|
136
|
-
if (!t)
|
|
140
|
+
if (!t)
|
|
141
|
+
throw new Error("Canvas rendering not supported");
|
|
137
142
|
if (typeof ImageData.prototype.constructor == "function")
|
|
138
143
|
try {
|
|
139
144
|
new ImageData(new Uint8ClampedArray([0, 0, 0, 0]), 1, 1);
|
|
@@ -143,19 +148,20 @@ class o extends EventTarget {
|
|
|
143
148
|
return h && m.data.set(h), m;
|
|
144
149
|
};
|
|
145
150
|
}
|
|
146
|
-
const s = document.createElement("canvas"),
|
|
147
|
-
if (!
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
i
|
|
155
|
-
|
|
151
|
+
const s = document.createElement("canvas"), r = s.getContext("2d", { willReadFrequently: !0 });
|
|
152
|
+
if (!r)
|
|
153
|
+
throw new Error("Canvas rendering not supported");
|
|
154
|
+
e.width = s.width = 1, e.height = s.height = 1, t.clearRect(0, 0, 1, 1), r.clearRect(0, 0, 1, 1);
|
|
155
|
+
const n = r.getImageData(0, 0, 1, 1).data;
|
|
156
|
+
t.putImageData(new ImageData(new Uint8ClampedArray([0, 255, 0, 0]), 1, 1), 0, 0), r.drawImage(e, 0, 0);
|
|
157
|
+
const a = r.getImageData(0, 0, 1, 1).data;
|
|
158
|
+
if (o._hasAlphaBug = n[1] !== a[1], o._hasAlphaBug && console.log("Detected a browser having issue with transparent pixels, applying workaround"), typeof createImageBitmap < "u") {
|
|
159
|
+
const i = new Uint8ClampedArray([255, 0, 255, 0, 255]).subarray(1, 5);
|
|
160
|
+
r.drawImage(await createImageBitmap(new ImageData(i, 1)), 0, 0);
|
|
161
|
+
const { data: h } = r.getImageData(0, 0, 1, 1);
|
|
156
162
|
o._hasBitmapBug = !1;
|
|
157
163
|
for (const [d, l] of h.entries())
|
|
158
|
-
if (Math.abs(
|
|
164
|
+
if (Math.abs(i[d] - l) > 15) {
|
|
159
165
|
o._hasBitmapBug = !0, console.log("Detected a browser having issue with partial bitmaps, applying workaround");
|
|
160
166
|
break;
|
|
161
167
|
}
|
|
@@ -174,33 +180,33 @@ class o extends EventTarget {
|
|
|
174
180
|
* @param {Number} [left=0]
|
|
175
181
|
* @param {Boolean} [force=false]
|
|
176
182
|
*/
|
|
177
|
-
resize(e = 0, t = 0, s = 0,
|
|
183
|
+
resize(e = 0, t = 0, s = 0, r = 0, n = this._video?.paused) {
|
|
178
184
|
if ((!e || !t) && this._video) {
|
|
179
|
-
const
|
|
180
|
-
let
|
|
185
|
+
const a = this._getVideoPosition();
|
|
186
|
+
let i = null;
|
|
181
187
|
if (this._videoWidth) {
|
|
182
188
|
const h = this._video.videoWidth / this._videoWidth, d = this._video.videoHeight / this._videoHeight;
|
|
183
|
-
|
|
189
|
+
i = this._computeCanvasSize((a.width || 0) / h, (a.height || 0) / d);
|
|
184
190
|
} else
|
|
185
|
-
|
|
186
|
-
e =
|
|
191
|
+
i = this._computeCanvasSize(a.width || 0, a.height || 0);
|
|
192
|
+
e = i.width, t = i.height, this._canvasParent && (s = a.y - (this._canvasParent.getBoundingClientRect().top - this._video.getBoundingClientRect().top), r = a.x), this._canvas.style.width = a.width + "px", this._canvas.style.height = a.height + "px";
|
|
187
193
|
}
|
|
188
|
-
this._canvas.style.top = s + "px", this._canvas.style.left =
|
|
194
|
+
this._canvas.style.top = s + "px", this._canvas.style.left = r + "px", n && this.busy === !1 ? this.busy = !0 : n = !1, this.sendMessage("canvas", { width: e, height: t, force: n });
|
|
189
195
|
}
|
|
190
196
|
_getVideoPosition(e = this._video.videoWidth, t = this._video.videoHeight) {
|
|
191
|
-
const s = e / t, { offsetWidth:
|
|
192
|
-
e =
|
|
193
|
-
const
|
|
194
|
-
return { width: e, height: t, x:
|
|
197
|
+
const s = e / t, { offsetWidth: r, offsetHeight: n } = this._video, a = r / n;
|
|
198
|
+
e = r, t = n, a > s ? e = Math.floor(n * s) : t = Math.floor(r / s);
|
|
199
|
+
const i = (r - e) / 2, h = (n - t) / 2;
|
|
200
|
+
return { width: e, height: t, x: i, y: h };
|
|
195
201
|
}
|
|
196
202
|
_computeCanvasSize(e = 0, t = 0) {
|
|
197
|
-
const s = this.prescaleFactor <= 0 ? 1 : this.prescaleFactor,
|
|
198
|
-
if (
|
|
203
|
+
const s = this.prescaleFactor <= 0 ? 1 : this.prescaleFactor, r = self.devicePixelRatio || 1;
|
|
204
|
+
if (t <= 0 || e <= 0)
|
|
199
205
|
e = 0, t = 0;
|
|
200
206
|
else {
|
|
201
207
|
const n = s < 1 ? -1 : 1;
|
|
202
|
-
let
|
|
203
|
-
n *
|
|
208
|
+
let a = t * r;
|
|
209
|
+
n * a * s <= n * this.prescaleHeightLimit ? a *= s : n * a < n * this.prescaleHeightLimit && (a = this.prescaleHeightLimit), this.maxRenderHeight > 0 && a > this.maxRenderHeight && (a = this.maxRenderHeight), e *= a / t, t = a;
|
|
204
210
|
}
|
|
205
211
|
return { width: e, height: t };
|
|
206
212
|
}
|
|
@@ -385,9 +391,9 @@ class o extends EventTarget {
|
|
|
385
391
|
_sendLocalFont(e) {
|
|
386
392
|
try {
|
|
387
393
|
queryLocalFonts().then((t) => {
|
|
388
|
-
const s = t?.find((
|
|
389
|
-
s && s.blob().then((
|
|
390
|
-
|
|
394
|
+
const s = t?.find((r) => r.fullName.toLowerCase() === e);
|
|
395
|
+
s && s.blob().then((r) => {
|
|
396
|
+
r.arrayBuffer().then((n) => {
|
|
391
397
|
this.addFont(new Uint8Array(n));
|
|
392
398
|
});
|
|
393
399
|
});
|
|
@@ -408,21 +414,24 @@ class o extends EventTarget {
|
|
|
408
414
|
_unbusy() {
|
|
409
415
|
this._lastDemandTime ? this._demandRender(this._lastDemandTime) : this.busy = !1;
|
|
410
416
|
}
|
|
411
|
-
_handleRVFC(e, { mediaTime: t, width: s, height:
|
|
412
|
-
if (this._destroyed)
|
|
413
|
-
|
|
417
|
+
_handleRVFC(e, { mediaTime: t, width: s, height: r }) {
|
|
418
|
+
if (this._destroyed)
|
|
419
|
+
return null;
|
|
420
|
+
this.busy ? this._lastDemandTime = { mediaTime: t, width: s, height: r } : (this.busy = !0, this._demandRender({ mediaTime: t, width: s, height: r })), this._video.requestVideoFrameCallback(this._handleRVFC.bind(this));
|
|
414
421
|
}
|
|
415
422
|
_demandRender({ mediaTime: e, width: t, height: s }) {
|
|
416
423
|
this._lastDemandTime = null, (t !== this._videoWidth || s !== this._videoHeight) && (this._videoWidth = t, this._videoHeight = s, this.resize()), this.sendMessage("demand", { time: e + this.timeOffset });
|
|
417
424
|
}
|
|
418
425
|
// if we're using offscreen render, we can't use ctx filters, so we can't use a transfered canvas
|
|
419
426
|
_detachOffscreen() {
|
|
420
|
-
if (!this._offscreenRender || this._ctx)
|
|
427
|
+
if (!this._offscreenRender || this._ctx)
|
|
428
|
+
return null;
|
|
421
429
|
this._canvas.remove(), this._createCanvas(), this._canvasctrl = this._canvas, this._ctx = this._canvasctrl.getContext("2d"), this.sendMessage("detachOffscreen"), this.busy = !1, this.resize(0, 0, 0, 0, !0);
|
|
422
430
|
}
|
|
423
431
|
// if the video or track changed, we need to re-attach the offscreen canvas
|
|
424
432
|
_reAttachOffscreen() {
|
|
425
|
-
if (!this._offscreenRender || !this._ctx)
|
|
433
|
+
if (!this._offscreenRender || !this._ctx)
|
|
434
|
+
return null;
|
|
426
435
|
this._canvas.remove(), this._createCanvas(), this._canvasctrl = this._canvas.transferControlToOffscreen(), this._ctx = !1, this.sendMessage("offscreenCanvas", null, [this._canvasctrl]), this.resize(0, 0, 0, 0, !0);
|
|
427
436
|
}
|
|
428
437
|
_updateColorSpace() {
|
|
@@ -444,17 +453,18 @@ class o extends EventTarget {
|
|
|
444
453
|
_verifyColorSpace({ subtitleColorSpace: e, videoColorSpace: t = this._videoColorSpace }) {
|
|
445
454
|
!e || !t || e !== t && (this._detachOffscreen(), this._ctx.filter = `url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg'><filter id='f'><feColorMatrix type='matrix' values='${f[e][t]} 0 0 0 0 0 1 0'/></filter></svg>#f")`);
|
|
446
455
|
}
|
|
447
|
-
_render({ images: e, asyncRender: t, times: s, width:
|
|
448
|
-
this._unbusy(), this.debug && (s.IPCTime = Date.now() - s.JSRenderTime), (this._canvasctrl.width !==
|
|
449
|
-
for (const
|
|
450
|
-
|
|
456
|
+
_render({ images: e, asyncRender: t, times: s, width: r, height: n, colorSpace: a }) {
|
|
457
|
+
this._unbusy(), this.debug && (s.IPCTime = Date.now() - s.JSRenderTime), (this._canvasctrl.width !== r || this._canvasctrl.height !== n) && (this._canvasctrl.width = r, this._canvasctrl.height = n, this._verifyColorSpace({ subtitleColorSpace: a })), this._ctx.clearRect(0, 0, this._canvasctrl.width, this._canvasctrl.height);
|
|
458
|
+
for (const i of e)
|
|
459
|
+
i.image && (t ? (this._ctx.drawImage(i.image, i.x, i.y), i.image.close()) : (this._bufferCanvas.width = i.w, this._bufferCanvas.height = i.h, this._bufferCtx.putImageData(new ImageData(this._fixAlpha(new Uint8ClampedArray(i.image)), i.w, i.h), 0, 0), this._ctx.drawImage(this._bufferCanvas, i.x, i.y)));
|
|
451
460
|
if (this.debug) {
|
|
452
461
|
s.JSRenderTime = Date.now() - s.JSRenderTime - s.IPCTime;
|
|
453
|
-
let
|
|
462
|
+
let i = 0;
|
|
454
463
|
const h = s.bitmaps || e.length;
|
|
455
464
|
delete s.bitmaps;
|
|
456
|
-
for (const d in s)
|
|
457
|
-
|
|
465
|
+
for (const d in s)
|
|
466
|
+
i += s[d];
|
|
467
|
+
console.log("Bitmaps: " + h + " Total: " + (i | 0) + "ms", s);
|
|
458
468
|
}
|
|
459
469
|
}
|
|
460
470
|
_fixAlpha(e) {
|
|
@@ -484,14 +494,14 @@ class o extends EventTarget {
|
|
|
484
494
|
}
|
|
485
495
|
_fetchFromWorker(e, t) {
|
|
486
496
|
try {
|
|
487
|
-
const s = e.target,
|
|
488
|
-
|
|
489
|
-
}, 5e3), n = ({ data:
|
|
490
|
-
|
|
491
|
-
},
|
|
492
|
-
t(
|
|
497
|
+
const s = e.target, r = setTimeout(() => {
|
|
498
|
+
a(new Error("Error: Timeout while try to fetch " + s));
|
|
499
|
+
}, 5e3), n = ({ data: i }) => {
|
|
500
|
+
i.target === s && (t(null, i), this._worker.removeEventListener("message", n), this._worker.removeEventListener("error", a), clearTimeout(r));
|
|
501
|
+
}, a = (i) => {
|
|
502
|
+
t(i), this._worker.removeEventListener("message", n), this._worker.removeEventListener("error", a), clearTimeout(r);
|
|
493
503
|
};
|
|
494
|
-
this._worker.addEventListener("message", n), this._worker.addEventListener("error",
|
|
504
|
+
this._worker.addEventListener("message", n), this._worker.addEventListener("error", a), this._worker.postMessage(e);
|
|
495
505
|
} catch (s) {
|
|
496
506
|
this._error(s);
|
|
497
507
|
}
|
package/dist/jassub.umd.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(c,m){typeof exports=="object"&&typeof module<"u"?module.exports=m():typeof define=="function"&&define.amd?define(m):(c=typeof globalThis<"u"?globalThis:c||self,c.JASSUB=m())})(this,function(){"use strict";typeof HTMLVideoElement<"u"&&!("requestVideoFrameCallback"in HTMLVideoElement.prototype)&&"getVideoPlaybackQuality"in HTMLVideoElement.prototype&&(HTMLVideoElement.prototype._rvfcpolyfillmap={},HTMLVideoElement.prototype.requestVideoFrameCallback=function(_){const e=performance.now(),t=this.getVideoPlaybackQuality(),s=this.mozPresentedFrames||this.mozPaintedFrames||t.totalVideoFrames-t.droppedVideoFrames,i=(n,r)=>{const a=this.getVideoPlaybackQuality(),h=this.mozPresentedFrames||this.mozPaintedFrames||a.totalVideoFrames-a.droppedVideoFrames;if(h>s){const d=this.mozFrameDelay||a.totalFrameDelay-t.totalFrameDelay||0,l=r-n;_(r,{presentationTime:r+d*1e3,expectedDisplayTime:r+l,width:this.videoWidth,height:this.videoHeight,mediaTime:Math.max(0,this.currentTime||0)+l/1e3,presentedFrames:h,processingDuration:d}),delete this._rvfcpolyfillmap[e]}else this._rvfcpolyfillmap[e]=requestAnimationFrame(d=>i(r,d))};return this._rvfcpolyfillmap[e]=requestAnimationFrame(n=>i(e,n)),e},HTMLVideoElement.prototype.cancelVideoFrameCallback=function(_){cancelAnimationFrame(this._rvfcpolyfillmap[_]),delete this._rvfcpolyfillmap[_]});const c={bt709:"BT709",bt470bg:"BT601",smpte170m:"BT601"},m={BT601:{BT709:"1.0863 -0.0723 -0.014 0 0 0.0965 0.8451 0.0584 0 0 -0.0141 -0.0277 1.0418"},BT709:{BT601:"0.9137 0.0784 0.0079 0 0 -0.1049 1.1722 -0.0671 0 0 0.0096 0.0322 0.9582"},FCC:{BT709:"1.0873 -0.0736 -0.0137 0 0 0.0974 0.8494 0.0531 0 0 -0.0127 -0.0251 1.0378",BT601:"1.001 -0.0008 -0.0002 0 0 0.0009 1.005 -0.006 0 0 0.0013 0.0027 0.996"},SMPTE240M:{BT709:"0.9993 0.0006 0.0001 0 0 -0.0004 0.9812 0.0192 0 0 -0.0034 -0.0114 1.0148",BT601:"0.913 0.0774 0.0096 0 0 -0.1051 1.1508 -0.0456 0 0 0.0063 0.0207 0.973"}};class o extends EventTarget{constructor(e){if(super(),!globalThis.Worker)throw this.destroy("Worker not supported");if(!e)throw this.destroy("No options provided");this._loaded=new Promise(s=>{this._init=s});const t=o._test();if(this._onDemandRender="requestVideoFrameCallback"in HTMLVideoElement.prototype&&(e.onDemandRender??!0),this._offscreenRender="transferControlToOffscreen"in HTMLCanvasElement.prototype&&!e.canvas&&(e.offscreenRender??!0),this.timeOffset=e.timeOffset||0,this._video=e.video,this._videoHeight=0,this._videoWidth=0,this._videoColorSpace=null,this._canvas=e.canvas,this._video&&!this._canvas)this._canvasParent=document.createElement("div"),this._canvasParent.className="JASSUB",this._canvasParent.style.position="relative",this._canvas=this._createCanvas(),this._video.insertAdjacentElement("afterend",this._canvasParent);else if(!this._canvas)throw this.destroy("Don't know where to render: you should give video or canvas in options.");if(this._bufferCanvas=document.createElement("canvas"),this._bufferCtx=this._bufferCanvas.getContext("2d"),!this._bufferCtx)throw this.destroy("Canvas rendering not supported");this._canvasctrl=this._offscreenRender?this._canvas.transferControlToOffscreen():this._canvas,this._ctx=!this._offscreenRender&&this._canvasctrl.getContext("2d"),this._lastRenderTime=0,this.debug=!!e.debug,this.prescaleFactor=e.prescaleFactor||1,this.prescaleHeightLimit=e.prescaleHeightLimit||1080,this.maxRenderHeight=e.maxRenderHeight||0,this._boundResize=this.resize.bind(this),this._boundTimeUpdate=this._timeupdate.bind(this),this._boundSetRate=this.setRate.bind(this),this._boundUpdateColorSpace=this._updateColorSpace.bind(this),this._video&&this.setVideo(e.video),this._onDemandRender&&(this.busy=!1,this._lastDemandTime=null),this._worker=new Worker(e.workerUrl||"jassub-worker.js"),this._worker.onmessage=s=>this._onmessage(s),this._worker.onerror=s=>this._error(s),t.then(()=>{this._worker.postMessage({target:"init",wasmUrl:o._supportsSIMD&&e.modernWasmUrl?e.modernWasmUrl:e.wasmUrl??"jassub-worker.wasm",legacyWasmUrl:e.legacyWasmUrl??"jassub-worker.wasm.js",asyncRender:typeof createImageBitmap<"u"&&(e.asyncRender??!0),onDemandRender:this._onDemandRender,width:this._canvasctrl.width||0,height:this._canvasctrl.height||0,blendMode:e.blendMode||"js",subUrl:e.subUrl,subContent:e.subContent||null,fonts:e.fonts||[],availableFonts:e.availableFonts||{"liberation sans":"./default.woff2"},fallbackFont:e.fallbackFont||"liberation sans",debug:this.debug,targetFps:e.targetFps||24,dropAllAnimations:e.dropAllAnimations,dropAllBlur:e.dropAllBlur,libassMemoryLimit:e.libassMemoryLimit||0,libassGlyphLimit:e.libassGlyphLimit||0,useLocalFonts:typeof queryLocalFonts<"u"&&(e.useLocalFonts??!0),hasBitmapBug:o._hasBitmapBug}),this._offscreenRender===!0&&this.sendMessage("offscreenCanvas",null,[this._canvasctrl])})}_createCanvas(){return this._canvas=document.createElement("canvas"),this._canvas.style.display="block",this._canvas.style.position="absolute",this._canvas.style.pointerEvents="none",this._canvasParent.appendChild(this._canvas),this._canvas}static _supportsSIMD=null;static _hasAlphaBug=null;static _hasBitmapBug=null;static _testSIMD(){if(o._supportsSIMD===null)try{o._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))}catch{o._supportsSIMD=!1}}static async _testImageBugs(){if(o._hasBitmapBug!==null)return;const e=document.createElement("canvas"),t=e.getContext("2d",{willReadFrequently:!0});if(!t)throw new Error("Canvas rendering not supported");if(typeof ImageData.prototype.constructor=="function")try{new ImageData(new Uint8ClampedArray([0,0,0,0]),1,1)}catch{console.log("Detected that ImageData is not constructable despite browser saying so"),self.ImageData=function(h,d,l){const f=t.createImageData(d,l);return h&&f.data.set(h),f}}const s=document.createElement("canvas"),i=s.getContext("2d",{willReadFrequently:!0});if(!i)throw new Error("Canvas rendering not supported");e.width=s.width=1,e.height=s.height=1,t.clearRect(0,0,1,1),i.clearRect(0,0,1,1);const n=i.getImageData(0,0,1,1).data;t.putImageData(new ImageData(new Uint8ClampedArray([0,255,0,0]),1,1),0,0),i.drawImage(e,0,0);const r=i.getImageData(0,0,1,1).data;if(o._hasAlphaBug=n[1]!==r[1],o._hasAlphaBug&&console.log("Detected a browser having issue with transparent pixels, applying workaround"),typeof createImageBitmap<"u"){const a=new Uint8ClampedArray([255,0,255,0,255]).subarray(1,5);i.drawImage(await createImageBitmap(new ImageData(a,1)),0,0);const{data:h}=i.getImageData(0,0,1,1);o._hasBitmapBug=!1;for(const[d,l]of h.entries())if(Math.abs(a[d]-l)>15){o._hasBitmapBug=!0,console.log("Detected a browser having issue with partial bitmaps, applying workaround");break}}else o._hasBitmapBug=!1;e.remove(),s.remove()}static async _test(){o._testSIMD(),await o._testImageBugs()}resize(e=0,t=0,s=0,i=0,n=this._video?.paused){if((!e||!t)&&this._video){const r=this._getVideoPosition();let a=null;if(this._videoWidth){const h=this._video.videoWidth/this._videoWidth,d=this._video.videoHeight/this._videoHeight;a=this._computeCanvasSize((r.width||0)/h,(r.height||0)/d)}else a=this._computeCanvasSize(r.width||0,r.height||0);e=a.width,t=a.height,this._canvasParent&&(s=r.y-(this._canvasParent.getBoundingClientRect().top-this._video.getBoundingClientRect().top),i=r.x),this._canvas.style.width=r.width+"px",this._canvas.style.height=r.height+"px"}this._canvas.style.top=s+"px",this._canvas.style.left=i+"px",n&&this.busy===!1?this.busy=!0:n=!1,this.sendMessage("canvas",{width:e,height:t,force:n})}_getVideoPosition(e=this._video.videoWidth,t=this._video.videoHeight){const s=e/t,{offsetWidth:i,offsetHeight:n}=this._video,r=i/n;e=i,t=n,r>s?e=Math.floor(n*s):t=Math.floor(i/s);const a=(i-e)/2,h=(n-t)/2;return{width:e,height:t,x:a,y:h}}_computeCanvasSize(e=0,t=0){const s=this.prescaleFactor<=0?1:this.prescaleFactor,i=self.devicePixelRatio||1;if(e=e*i,t=t*i,t<=0||e<=0)e=0,t=0;else{const n=s<1?-1:1;let r=t*i;n*r*s<=n*this.prescaleHeightLimit?r*=s:n*r<n*this.prescaleHeightLimit&&(r=this.prescaleHeightLimit),this.maxRenderHeight>0&&r>this.maxRenderHeight&&(r=this.maxRenderHeight),e*=r/t,t=r}return{width:e,height:t}}_timeupdate({type:e}){const s={seeking:!0,waiting:!0,playing:!1}[e];s!=null&&(this._playstate=s),this.setCurrentTime(this._video.paused||this._playstate,this._video.currentTime+this.timeOffset)}setVideo(e){e instanceof HTMLVideoElement?(this._removeListeners(),this._video=e,this._onDemandRender?this._video.requestVideoFrameCallback(this._handleRVFC.bind(this)):(this._playstate=e.paused,e.addEventListener("timeupdate",this._boundTimeUpdate,!1),e.addEventListener("progress",this._boundTimeUpdate,!1),e.addEventListener("waiting",this._boundTimeUpdate,!1),e.addEventListener("seeking",this._boundTimeUpdate,!1),e.addEventListener("playing",this._boundTimeUpdate,!1),e.addEventListener("ratechange",this._boundSetRate,!1),e.addEventListener("resize",this._boundResize,!1)),"VideoFrame"in window&&(e.addEventListener("loadedmetadata",this._boundUpdateColorSpace,!1),e.readyState>2&&this._updateColorSpace()),e.videoWidth>0&&this.resize(),typeof ResizeObserver<"u"&&(this._ro||(this._ro=new ResizeObserver(()=>this.resize())),this._ro.observe(e))):this._error("Video element invalid!")}runBenchmark(){this.sendMessage("runBenchmark")}setTrackByUrl(e){this.sendMessage("setTrackByUrl",{url:e}),this._reAttachOffscreen(),this._ctx&&(this._ctx.filter="none")}setTrack(e){this.sendMessage("setTrack",{content:e}),this._reAttachOffscreen(),this._ctx&&(this._ctx.filter="none")}freeTrack(){this.sendMessage("freeTrack")}setIsPaused(e){this.sendMessage("video",{isPaused:e})}setRate(e){this.sendMessage("video",{rate:e})}setCurrentTime(e,t,s){this.sendMessage("video",{isPaused:e,currentTime:t,rate:s,colorSpace:this._videoColorSpace})}createEvent(e){this.sendMessage("createEvent",{event:e})}setEvent(e,t){this.sendMessage("setEvent",{event:e,index:t})}removeEvent(e){this.sendMessage("removeEvent",{index:e})}getEvents(e){this._fetchFromWorker({target:"getEvents"},(t,{events:s})=>{e(t,s)})}createStyle(e){this.sendMessage("createStyle",{style:e})}setStyle(e,t){this.sendMessage("setStyle",{style:e,index:t})}removeStyle(e){this.sendMessage("removeStyle",{index:e})}getStyles(e){this._fetchFromWorker({target:"getStyles"},(t,{styles:s})=>{e(t,s)})}addFont(e){this.sendMessage("addFont",{font:e})}_sendLocalFont(e){try{queryLocalFonts().then(t=>{const s=t?.find(i=>i.fullName.toLowerCase()===e);s&&s.blob().then(i=>{i.arrayBuffer().then(n=>{this.addFont(new Uint8Array(n))})})})}catch(t){console.warn("Local fonts API:",t)}}_getLocalFont({font:e}){try{navigator?.permissions?.query?navigator.permissions.query({name:"local-fonts"}).then(t=>{t.state==="granted"&&this._sendLocalFont(e)}):this._sendLocalFont(e)}catch(t){console.warn("Local fonts API:",t)}}_unbusy(){this._lastDemandTime?this._demandRender(this._lastDemandTime):this.busy=!1}_handleRVFC(e,{mediaTime:t,width:s,height:i}){if(this._destroyed)return null;this.busy?this._lastDemandTime={mediaTime:t,width:s,height:i}:(this.busy=!0,this._demandRender({mediaTime:t,width:s,height:i})),this._video.requestVideoFrameCallback(this._handleRVFC.bind(this))}_demandRender({mediaTime:e,width:t,height:s}){this._lastDemandTime=null,(t!==this._videoWidth||s!==this._videoHeight)&&(this._videoWidth=t,this._videoHeight=s,this.resize()),this.sendMessage("demand",{time:e+this.timeOffset})}_detachOffscreen(){if(!this._offscreenRender||this._ctx)return null;this._canvas.remove(),this._createCanvas(),this._canvasctrl=this._canvas,this._ctx=this._canvasctrl.getContext("2d"),this.sendMessage("detachOffscreen"),this.busy=!1,this.resize(0,0,0,0,!0)}_reAttachOffscreen(){if(!this._offscreenRender||!this._ctx)return null;this._canvas.remove(),this._createCanvas(),this._canvasctrl=this._canvas.transferControlToOffscreen(),this._ctx=!1,this.sendMessage("offscreenCanvas",null,[this._canvasctrl]),this.resize(0,0,0,0,!0)}_updateColorSpace(){this._video.requestVideoFrameCallback(()=>{try{const e=new VideoFrame(this._video);this._videoColorSpace=c[e.colorSpace.matrix],e.close(),this.sendMessage("getColorSpace")}catch(e){console.warn(e)}})}_verifyColorSpace({subtitleColorSpace:e,videoColorSpace:t=this._videoColorSpace}){!e||!t||e!==t&&(this._detachOffscreen(),this._ctx.filter=`url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg'><filter id='f'><feColorMatrix type='matrix' values='${m[e][t]} 0 0 0 0 0 1 0'/></filter></svg>#f")`)}_render({images:e,asyncRender:t,times:s,width:i,height:n,colorSpace:r}){this._unbusy(),this.debug&&(s.IPCTime=Date.now()-s.JSRenderTime),(this._canvasctrl.width!==i||this._canvasctrl.height!==n)&&(this._canvasctrl.width=i,this._canvasctrl.height=n,this._verifyColorSpace({subtitleColorSpace:r})),this._ctx.clearRect(0,0,this._canvasctrl.width,this._canvasctrl.height);for(const a of e)a.image&&(t?(this._ctx.drawImage(a.image,a.x,a.y),a.image.close()):(this._bufferCanvas.width=a.w,this._bufferCanvas.height=a.h,this._bufferCtx.putImageData(new ImageData(this._fixAlpha(new Uint8ClampedArray(a.image)),a.w,a.h),0,0),this._ctx.drawImage(this._bufferCanvas,a.x,a.y)));if(this.debug){s.JSRenderTime=Date.now()-s.JSRenderTime-s.IPCTime;let a=0;const h=s.bitmaps||e.length;delete s.bitmaps;for(const d in s)a+=s[d];console.log("Bitmaps: "+h+" Total: "+(a|0)+"ms",s)}}_fixAlpha(e){if(o._hasAlphaBug)for(let t=3;t<e.length;t+=4)e[t]=e[t]>1?e[t]:1;return e}_ready(){this._init(),this.dispatchEvent(new CustomEvent("ready"))}async sendMessage(e,t={},s){await this._loaded,s?this._worker.postMessage({target:e,transferable:s,...t},[...s]):this._worker.postMessage({target:e,...t})}_fetchFromWorker(e,t){try{const s=e.target,i=setTimeout(()=>{r(new Error("Error: Timeout while try to fetch "+s))},5e3),n=({data:a})=>{a.target===s&&(t(null,a),this._worker.removeEventListener("message",n),this._worker.removeEventListener("error",r),clearTimeout(i))},r=a=>{t(a),this._worker.removeEventListener("message",n),this._worker.removeEventListener("error",r),clearTimeout(i)};this._worker.addEventListener("message",n),this._worker.addEventListener("error",r),this._worker.postMessage(e)}catch(s){this._error(s)}}_console({content:e,command:t}){console[t].apply(console,JSON.parse(e))}_onmessage({data:e}){this["_"+e.target]&&this["_"+e.target](e)}_error(e){const t=e instanceof Error?e:e instanceof ErrorEvent?e.error:new Error(e),s=e instanceof Event?new ErrorEvent(e.type,e):new ErrorEvent("error",{error:t});return this.dispatchEvent(s),console.error(t),t}_removeListeners(){this._video&&(this._ro&&this._ro.unobserve(this._video),this._ctx&&(this._ctx.filter="none"),this._video.removeEventListener("timeupdate",this._boundTimeUpdate),this._video.removeEventListener("progress",this._boundTimeUpdate),this._video.removeEventListener("waiting",this._boundTimeUpdate),this._video.removeEventListener("seeking",this._boundTimeUpdate),this._video.removeEventListener("playing",this._boundTimeUpdate),this._video.removeEventListener("ratechange",this._boundSetRate),this._video.removeEventListener("resize",this._boundResize),this._video.removeEventListener("loadedmetadata",this._boundUpdateColorSpace))}destroy(e){return e&&(e=this._error(e)),this._video&&this._canvasParent&&this._video.parentNode?.removeChild(this._canvasParent),this._destroyed=!0,this._removeListeners(),this.sendMessage("destroy"),this._worker?.terminate(),e}}return o});
|
|
1
|
+
(function(c,m){typeof exports=="object"&&typeof module<"u"?module.exports=m():typeof define=="function"&&define.amd?define(m):(c=typeof globalThis<"u"?globalThis:c||self,c.JASSUB=m())})(this,function(){"use strict";typeof HTMLVideoElement<"u"&&!("requestVideoFrameCallback"in HTMLVideoElement.prototype)&&"getVideoPlaybackQuality"in HTMLVideoElement.prototype&&(HTMLVideoElement.prototype._rvfcpolyfillmap={},HTMLVideoElement.prototype.requestVideoFrameCallback=function(_){const e=performance.now(),t=this.getVideoPlaybackQuality(),s=this.mozPresentedFrames||this.mozPaintedFrames||t.totalVideoFrames-t.droppedVideoFrames,r=(n,a)=>{const i=this.getVideoPlaybackQuality(),h=this.mozPresentedFrames||this.mozPaintedFrames||i.totalVideoFrames-i.droppedVideoFrames;if(h>s){const d=this.mozFrameDelay||i.totalFrameDelay-t.totalFrameDelay||0,l=a-n;_(a,{presentationTime:a+d*1e3,expectedDisplayTime:a+l,width:this.videoWidth,height:this.videoHeight,mediaTime:Math.max(0,this.currentTime||0)+l/1e3,presentedFrames:h,processingDuration:d}),delete this._rvfcpolyfillmap[e]}else this._rvfcpolyfillmap[e]=requestAnimationFrame(d=>r(a,d))};return this._rvfcpolyfillmap[e]=requestAnimationFrame(n=>r(e,n)),e},HTMLVideoElement.prototype.cancelVideoFrameCallback=function(_){cancelAnimationFrame(this._rvfcpolyfillmap[_]),delete this._rvfcpolyfillmap[_]});const c={bt709:"BT709",bt470bg:"BT601",smpte170m:"BT601"},m={BT601:{BT709:"1.0863 -0.0723 -0.014 0 0 0.0965 0.8451 0.0584 0 0 -0.0141 -0.0277 1.0418"},BT709:{BT601:"0.9137 0.0784 0.0079 0 0 -0.1049 1.1722 -0.0671 0 0 0.0096 0.0322 0.9582"},FCC:{BT709:"1.0873 -0.0736 -0.0137 0 0 0.0974 0.8494 0.0531 0 0 -0.0127 -0.0251 1.0378",BT601:"1.001 -0.0008 -0.0002 0 0 0.0009 1.005 -0.006 0 0 0.0013 0.0027 0.996"},SMPTE240M:{BT709:"0.9993 0.0006 0.0001 0 0 -0.0004 0.9812 0.0192 0 0 -0.0034 -0.0114 1.0148",BT601:"0.913 0.0774 0.0096 0 0 -0.1051 1.1508 -0.0456 0 0 0.0063 0.0207 0.973"}};class o extends EventTarget{constructor(e){if(super(),!globalThis.Worker)throw this.destroy("Worker not supported");if(!e)throw this.destroy("No options provided");this._loaded=new Promise(s=>{this._init=s});const t=o._test();if(this._onDemandRender="requestVideoFrameCallback"in HTMLVideoElement.prototype&&(e.onDemandRender??!0),this._offscreenRender="transferControlToOffscreen"in HTMLCanvasElement.prototype&&!e.canvas&&(e.offscreenRender??!0),this.timeOffset=e.timeOffset||0,this._video=e.video,this._videoHeight=0,this._videoWidth=0,this._videoColorSpace=null,this._canvas=e.canvas,this._video&&!this._canvas)this._canvasParent=document.createElement("div"),this._canvasParent.className="JASSUB",this._canvasParent.style.position="relative",this._canvas=this._createCanvas(),this._video.insertAdjacentElement("afterend",this._canvasParent);else if(!this._canvas)throw this.destroy("Don't know where to render: you should give video or canvas in options.");if(this._bufferCanvas=document.createElement("canvas"),this._bufferCtx=this._bufferCanvas.getContext("2d"),!this._bufferCtx)throw this.destroy("Canvas rendering not supported");this._canvasctrl=this._offscreenRender?this._canvas.transferControlToOffscreen():this._canvas,this._ctx=!this._offscreenRender&&this._canvasctrl.getContext("2d"),this._lastRenderTime=0,this.debug=!!e.debug,this.prescaleFactor=e.prescaleFactor||1,this.prescaleHeightLimit=e.prescaleHeightLimit||1080,this.maxRenderHeight=e.maxRenderHeight||0,this._boundResize=this.resize.bind(this),this._boundTimeUpdate=this._timeupdate.bind(this),this._boundSetRate=this.setRate.bind(this),this._boundUpdateColorSpace=this._updateColorSpace.bind(this),this._video&&this.setVideo(e.video),this._onDemandRender&&(this.busy=!1,this._lastDemandTime=null),this._worker=new Worker(e.workerUrl||"jassub-worker.js"),this._worker.onmessage=s=>this._onmessage(s),this._worker.onerror=s=>this._error(s),t.then(()=>{this._worker.postMessage({target:"init",wasmUrl:o._supportsSIMD&&e.modernWasmUrl?e.modernWasmUrl:e.wasmUrl??"jassub-worker.wasm",legacyWasmUrl:e.legacyWasmUrl??"jassub-worker.wasm.js",asyncRender:typeof createImageBitmap<"u"&&(e.asyncRender??!0),onDemandRender:this._onDemandRender,width:this._canvasctrl.width||0,height:this._canvasctrl.height||0,blendMode:e.blendMode||"js",subUrl:e.subUrl,subContent:e.subContent||null,fonts:e.fonts||[],availableFonts:e.availableFonts||{"liberation sans":"./default.woff2"},fallbackFont:e.fallbackFont||"liberation sans",debug:this.debug,targetFps:e.targetFps||24,dropAllAnimations:e.dropAllAnimations,dropAllBlur:e.dropAllBlur,libassMemoryLimit:e.libassMemoryLimit||0,libassGlyphLimit:e.libassGlyphLimit||0,useLocalFonts:typeof queryLocalFonts<"u"&&(e.useLocalFonts??!0),hasBitmapBug:o._hasBitmapBug}),this._offscreenRender===!0&&this.sendMessage("offscreenCanvas",null,[this._canvasctrl])})}_createCanvas(){return this._canvas=document.createElement("canvas"),this._canvas.style.display="block",this._canvas.style.position="absolute",this._canvas.style.pointerEvents="none",this._canvasParent.appendChild(this._canvas),this._canvas}static _supportsSIMD=null;static _hasAlphaBug=null;static _hasBitmapBug=null;static _testSIMD(){if(o._supportsSIMD===null)try{o._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))}catch{o._supportsSIMD=!1}}static async _testImageBugs(){if(o._hasBitmapBug!==null)return;const e=document.createElement("canvas"),t=e.getContext("2d",{willReadFrequently:!0});if(!t)throw new Error("Canvas rendering not supported");if(typeof ImageData.prototype.constructor=="function")try{new ImageData(new Uint8ClampedArray([0,0,0,0]),1,1)}catch{console.log("Detected that ImageData is not constructable despite browser saying so"),self.ImageData=function(h,d,l){const f=t.createImageData(d,l);return h&&f.data.set(h),f}}const s=document.createElement("canvas"),r=s.getContext("2d",{willReadFrequently:!0});if(!r)throw new Error("Canvas rendering not supported");e.width=s.width=1,e.height=s.height=1,t.clearRect(0,0,1,1),r.clearRect(0,0,1,1);const n=r.getImageData(0,0,1,1).data;t.putImageData(new ImageData(new Uint8ClampedArray([0,255,0,0]),1,1),0,0),r.drawImage(e,0,0);const a=r.getImageData(0,0,1,1).data;if(o._hasAlphaBug=n[1]!==a[1],o._hasAlphaBug&&console.log("Detected a browser having issue with transparent pixels, applying workaround"),typeof createImageBitmap<"u"){const i=new Uint8ClampedArray([255,0,255,0,255]).subarray(1,5);r.drawImage(await createImageBitmap(new ImageData(i,1)),0,0);const{data:h}=r.getImageData(0,0,1,1);o._hasBitmapBug=!1;for(const[d,l]of h.entries())if(Math.abs(i[d]-l)>15){o._hasBitmapBug=!0,console.log("Detected a browser having issue with partial bitmaps, applying workaround");break}}else o._hasBitmapBug=!1;e.remove(),s.remove()}static async _test(){o._testSIMD(),await o._testImageBugs()}resize(e=0,t=0,s=0,r=0,n=this._video?.paused){if((!e||!t)&&this._video){const a=this._getVideoPosition();let i=null;if(this._videoWidth){const h=this._video.videoWidth/this._videoWidth,d=this._video.videoHeight/this._videoHeight;i=this._computeCanvasSize((a.width||0)/h,(a.height||0)/d)}else i=this._computeCanvasSize(a.width||0,a.height||0);e=i.width,t=i.height,this._canvasParent&&(s=a.y-(this._canvasParent.getBoundingClientRect().top-this._video.getBoundingClientRect().top),r=a.x),this._canvas.style.width=a.width+"px",this._canvas.style.height=a.height+"px"}this._canvas.style.top=s+"px",this._canvas.style.left=r+"px",n&&this.busy===!1?this.busy=!0:n=!1,this.sendMessage("canvas",{width:e,height:t,force:n})}_getVideoPosition(e=this._video.videoWidth,t=this._video.videoHeight){const s=e/t,{offsetWidth:r,offsetHeight:n}=this._video,a=r/n;e=r,t=n,a>s?e=Math.floor(n*s):t=Math.floor(r/s);const i=(r-e)/2,h=(n-t)/2;return{width:e,height:t,x:i,y:h}}_computeCanvasSize(e=0,t=0){const s=this.prescaleFactor<=0?1:this.prescaleFactor,r=self.devicePixelRatio||1;if(t<=0||e<=0)e=0,t=0;else{const n=s<1?-1:1;let a=t*r;n*a*s<=n*this.prescaleHeightLimit?a*=s:n*a<n*this.prescaleHeightLimit&&(a=this.prescaleHeightLimit),this.maxRenderHeight>0&&a>this.maxRenderHeight&&(a=this.maxRenderHeight),e*=a/t,t=a}return{width:e,height:t}}_timeupdate({type:e}){const s={seeking:!0,waiting:!0,playing:!1}[e];s!=null&&(this._playstate=s),this.setCurrentTime(this._video.paused||this._playstate,this._video.currentTime+this.timeOffset)}setVideo(e){e instanceof HTMLVideoElement?(this._removeListeners(),this._video=e,this._onDemandRender?this._video.requestVideoFrameCallback(this._handleRVFC.bind(this)):(this._playstate=e.paused,e.addEventListener("timeupdate",this._boundTimeUpdate,!1),e.addEventListener("progress",this._boundTimeUpdate,!1),e.addEventListener("waiting",this._boundTimeUpdate,!1),e.addEventListener("seeking",this._boundTimeUpdate,!1),e.addEventListener("playing",this._boundTimeUpdate,!1),e.addEventListener("ratechange",this._boundSetRate,!1),e.addEventListener("resize",this._boundResize,!1)),"VideoFrame"in window&&(e.addEventListener("loadedmetadata",this._boundUpdateColorSpace,!1),e.readyState>2&&this._updateColorSpace()),e.videoWidth>0&&this.resize(),typeof ResizeObserver<"u"&&(this._ro||(this._ro=new ResizeObserver(()=>this.resize())),this._ro.observe(e))):this._error("Video element invalid!")}runBenchmark(){this.sendMessage("runBenchmark")}setTrackByUrl(e){this.sendMessage("setTrackByUrl",{url:e}),this._reAttachOffscreen(),this._ctx&&(this._ctx.filter="none")}setTrack(e){this.sendMessage("setTrack",{content:e}),this._reAttachOffscreen(),this._ctx&&(this._ctx.filter="none")}freeTrack(){this.sendMessage("freeTrack")}setIsPaused(e){this.sendMessage("video",{isPaused:e})}setRate(e){this.sendMessage("video",{rate:e})}setCurrentTime(e,t,s){this.sendMessage("video",{isPaused:e,currentTime:t,rate:s,colorSpace:this._videoColorSpace})}createEvent(e){this.sendMessage("createEvent",{event:e})}setEvent(e,t){this.sendMessage("setEvent",{event:e,index:t})}removeEvent(e){this.sendMessage("removeEvent",{index:e})}getEvents(e){this._fetchFromWorker({target:"getEvents"},(t,{events:s})=>{e(t,s)})}createStyle(e){this.sendMessage("createStyle",{style:e})}setStyle(e,t){this.sendMessage("setStyle",{style:e,index:t})}removeStyle(e){this.sendMessage("removeStyle",{index:e})}getStyles(e){this._fetchFromWorker({target:"getStyles"},(t,{styles:s})=>{e(t,s)})}addFont(e){this.sendMessage("addFont",{font:e})}_sendLocalFont(e){try{queryLocalFonts().then(t=>{const s=t?.find(r=>r.fullName.toLowerCase()===e);s&&s.blob().then(r=>{r.arrayBuffer().then(n=>{this.addFont(new Uint8Array(n))})})})}catch(t){console.warn("Local fonts API:",t)}}_getLocalFont({font:e}){try{navigator?.permissions?.query?navigator.permissions.query({name:"local-fonts"}).then(t=>{t.state==="granted"&&this._sendLocalFont(e)}):this._sendLocalFont(e)}catch(t){console.warn("Local fonts API:",t)}}_unbusy(){this._lastDemandTime?this._demandRender(this._lastDemandTime):this.busy=!1}_handleRVFC(e,{mediaTime:t,width:s,height:r}){if(this._destroyed)return null;this.busy?this._lastDemandTime={mediaTime:t,width:s,height:r}:(this.busy=!0,this._demandRender({mediaTime:t,width:s,height:r})),this._video.requestVideoFrameCallback(this._handleRVFC.bind(this))}_demandRender({mediaTime:e,width:t,height:s}){this._lastDemandTime=null,(t!==this._videoWidth||s!==this._videoHeight)&&(this._videoWidth=t,this._videoHeight=s,this.resize()),this.sendMessage("demand",{time:e+this.timeOffset})}_detachOffscreen(){if(!this._offscreenRender||this._ctx)return null;this._canvas.remove(),this._createCanvas(),this._canvasctrl=this._canvas,this._ctx=this._canvasctrl.getContext("2d"),this.sendMessage("detachOffscreen"),this.busy=!1,this.resize(0,0,0,0,!0)}_reAttachOffscreen(){if(!this._offscreenRender||!this._ctx)return null;this._canvas.remove(),this._createCanvas(),this._canvasctrl=this._canvas.transferControlToOffscreen(),this._ctx=!1,this.sendMessage("offscreenCanvas",null,[this._canvasctrl]),this.resize(0,0,0,0,!0)}_updateColorSpace(){this._video.requestVideoFrameCallback(()=>{try{const e=new VideoFrame(this._video);this._videoColorSpace=c[e.colorSpace.matrix],e.close(),this.sendMessage("getColorSpace")}catch(e){console.warn(e)}})}_verifyColorSpace({subtitleColorSpace:e,videoColorSpace:t=this._videoColorSpace}){!e||!t||e!==t&&(this._detachOffscreen(),this._ctx.filter=`url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg'><filter id='f'><feColorMatrix type='matrix' values='${m[e][t]} 0 0 0 0 0 1 0'/></filter></svg>#f")`)}_render({images:e,asyncRender:t,times:s,width:r,height:n,colorSpace:a}){this._unbusy(),this.debug&&(s.IPCTime=Date.now()-s.JSRenderTime),(this._canvasctrl.width!==r||this._canvasctrl.height!==n)&&(this._canvasctrl.width=r,this._canvasctrl.height=n,this._verifyColorSpace({subtitleColorSpace:a})),this._ctx.clearRect(0,0,this._canvasctrl.width,this._canvasctrl.height);for(const i of e)i.image&&(t?(this._ctx.drawImage(i.image,i.x,i.y),i.image.close()):(this._bufferCanvas.width=i.w,this._bufferCanvas.height=i.h,this._bufferCtx.putImageData(new ImageData(this._fixAlpha(new Uint8ClampedArray(i.image)),i.w,i.h),0,0),this._ctx.drawImage(this._bufferCanvas,i.x,i.y)));if(this.debug){s.JSRenderTime=Date.now()-s.JSRenderTime-s.IPCTime;let i=0;const h=s.bitmaps||e.length;delete s.bitmaps;for(const d in s)i+=s[d];console.log("Bitmaps: "+h+" Total: "+(i|0)+"ms",s)}}_fixAlpha(e){if(o._hasAlphaBug)for(let t=3;t<e.length;t+=4)e[t]=e[t]>1?e[t]:1;return e}_ready(){this._init(),this.dispatchEvent(new CustomEvent("ready"))}async sendMessage(e,t={},s){await this._loaded,s?this._worker.postMessage({target:e,transferable:s,...t},[...s]):this._worker.postMessage({target:e,...t})}_fetchFromWorker(e,t){try{const s=e.target,r=setTimeout(()=>{a(new Error("Error: Timeout while try to fetch "+s))},5e3),n=({data:i})=>{i.target===s&&(t(null,i),this._worker.removeEventListener("message",n),this._worker.removeEventListener("error",a),clearTimeout(r))},a=i=>{t(i),this._worker.removeEventListener("message",n),this._worker.removeEventListener("error",a),clearTimeout(r)};this._worker.addEventListener("message",n),this._worker.addEventListener("error",a),this._worker.postMessage(e)}catch(s){this._error(s)}}_console({content:e,command:t}){console[t].apply(console,JSON.parse(e))}_onmessage({data:e}){this["_"+e.target]&&this["_"+e.target](e)}_error(e){const t=e instanceof Error?e:e instanceof ErrorEvent?e.error:new Error(e),s=e instanceof Event?new ErrorEvent(e.type,e):new ErrorEvent("error",{error:t});return this.dispatchEvent(s),console.error(t),t}_removeListeners(){this._video&&(this._ro&&this._ro.unobserve(this._video),this._ctx&&(this._ctx.filter="none"),this._video.removeEventListener("timeupdate",this._boundTimeUpdate),this._video.removeEventListener("progress",this._boundTimeUpdate),this._video.removeEventListener("waiting",this._boundTimeUpdate),this._video.removeEventListener("seeking",this._boundTimeUpdate),this._video.removeEventListener("playing",this._boundTimeUpdate),this._video.removeEventListener("ratechange",this._boundSetRate),this._video.removeEventListener("resize",this._boundResize),this._video.removeEventListener("loadedmetadata",this._boundUpdateColorSpace))}destroy(e){return e&&(e=this._error(e)),this._video&&this._canvasParent&&this._video.parentNode?.removeChild(this._canvasParent),this._destroyed=!0,this._removeListeners(),this.sendMessage("destroy"),this._worker?.terminate(),e}}return o});
|
package/package.json
CHANGED
package/src/jassub.js
CHANGED
|
@@ -307,8 +307,6 @@ export default class JASSUB extends EventTarget {
|
|
|
307
307
|
const scalefactor = this.prescaleFactor <= 0 ? 1.0 : this.prescaleFactor
|
|
308
308
|
const ratio = self.devicePixelRatio || 1
|
|
309
309
|
|
|
310
|
-
width = width * ratio
|
|
311
|
-
height = height * ratio
|
|
312
310
|
if (height <= 0 || width <= 0) {
|
|
313
311
|
width = 0
|
|
314
312
|
height = 0
|