jassub 1.2.4 → 1.3.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.
- package/README.md +1 -0
- package/dist/jassub-worker-legacy.js +1 -1
- package/dist/jassub-worker.js +1 -1
- package/dist/jassub.es.js +45 -44
- package/dist/jassub.js +48 -47
- package/dist/jassub.umd.js +1 -1
- package/package.json +1 -1
- package/src/jassub.js +48 -47
package/dist/jassub.es.js
CHANGED
|
@@ -53,6 +53,8 @@ const _JASSUB = class extends EventTarget {
|
|
|
53
53
|
this._onDemandRender = "requestVideoFrameCallback" in HTMLVideoElement.prototype && ((_c = options.onDemandRender) != null ? _c : true);
|
|
54
54
|
this.timeOffset = options.timeOffset || 0;
|
|
55
55
|
this._video = options.video;
|
|
56
|
+
this._videoHeight = 0;
|
|
57
|
+
this._videoWidth = 0;
|
|
56
58
|
this._canvas = options.canvas;
|
|
57
59
|
if (this._video && !this._canvas) {
|
|
58
60
|
this._canvasParent = document.createElement("div");
|
|
@@ -87,8 +89,8 @@ const _JASSUB = class extends EventTarget {
|
|
|
87
89
|
target: "init",
|
|
88
90
|
asyncRender,
|
|
89
91
|
onDemandRender: this._onDemandRender,
|
|
90
|
-
width: this.
|
|
91
|
-
height: this.
|
|
92
|
+
width: this._canvasctrl.width,
|
|
93
|
+
height: this._canvasctrl.height,
|
|
92
94
|
preMain: true,
|
|
93
95
|
blendMode,
|
|
94
96
|
subUrl: options.subUrl,
|
|
@@ -160,49 +162,36 @@ const _JASSUB = class extends EventTarget {
|
|
|
160
162
|
canvas1.remove();
|
|
161
163
|
canvas2.remove();
|
|
162
164
|
}
|
|
163
|
-
resize(width = 0, height = 0, top = 0, left = 0) {
|
|
164
|
-
let videoSize = null;
|
|
165
|
+
resize(width = 0, height = 0, top = 0, left = 0, force = ((_a) => (_a = this._video) == null ? void 0 : _a.paused)()) {
|
|
165
166
|
if ((!width || !height) && this._video) {
|
|
166
|
-
videoSize = this._getVideoPosition();
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
167
|
+
const videoSize = this._getVideoPosition();
|
|
168
|
+
let renderSize = null;
|
|
169
|
+
if (this._videoWidth) {
|
|
170
|
+
const widthRatio = this._video.videoWidth / this._videoWidth;
|
|
171
|
+
const heightRatio = this._video.videoHeight / this._videoHeight;
|
|
172
|
+
renderSize = this._computeCanvasSize((videoSize.width || 0) / widthRatio, (videoSize.height || 0) / heightRatio);
|
|
173
|
+
} else {
|
|
174
|
+
renderSize = this._computeCanvasSize(videoSize.width || 0, videoSize.height || 0);
|
|
175
|
+
}
|
|
176
|
+
width = renderSize.width;
|
|
177
|
+
height = renderSize.height;
|
|
170
178
|
if (this._canvasParent) {
|
|
171
179
|
top = videoSize.y - (this._canvasParent.getBoundingClientRect().top - this._video.getBoundingClientRect().top);
|
|
172
180
|
left = videoSize.x;
|
|
173
181
|
}
|
|
174
|
-
}
|
|
175
|
-
if (videoSize != null) {
|
|
176
|
-
this._canvas.style.top = top + "px";
|
|
177
|
-
this._canvas.style.left = left + "px";
|
|
178
182
|
this._canvas.style.width = videoSize.width + "px";
|
|
179
183
|
this._canvas.style.height = videoSize.height + "px";
|
|
180
184
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
this._resizeTimeoutBuffer = setTimeout(() => {
|
|
185
|
-
this._resizeTimeoutBuffer = void 0;
|
|
186
|
-
this._canvasctrl.width = width;
|
|
187
|
-
this._canvasctrl.height = height;
|
|
188
|
-
this.sendMessage("canvas", { width, height });
|
|
189
|
-
}, 100);
|
|
190
|
-
} else {
|
|
191
|
-
this._canvasctrl.width = width;
|
|
192
|
-
this._canvasctrl.height = height;
|
|
193
|
-
this.sendMessage("canvas", { width, height });
|
|
194
|
-
this._resizeTimeoutBuffer = setTimeout(() => {
|
|
195
|
-
this._resizeTimeoutBuffer = void 0;
|
|
196
|
-
}, 100);
|
|
197
|
-
}
|
|
198
|
-
}
|
|
185
|
+
this._canvas.style.top = top + "px";
|
|
186
|
+
this._canvas.style.left = left + "px";
|
|
187
|
+
this.sendMessage("canvas", { width, height, force: force && this.busy === false });
|
|
199
188
|
}
|
|
200
|
-
_getVideoPosition() {
|
|
201
|
-
const videoRatio =
|
|
189
|
+
_getVideoPosition(width = this._video.videoWidth, height = this._video.videoHeight) {
|
|
190
|
+
const videoRatio = width / height;
|
|
202
191
|
const { offsetWidth, offsetHeight } = this._video;
|
|
203
192
|
const elementRatio = offsetWidth / offsetHeight;
|
|
204
|
-
|
|
205
|
-
|
|
193
|
+
width = offsetWidth;
|
|
194
|
+
height = offsetHeight;
|
|
206
195
|
if (elementRatio > videoRatio) {
|
|
207
196
|
width = Math.floor(offsetHeight * videoRatio);
|
|
208
197
|
} else {
|
|
@@ -214,12 +203,13 @@ const _JASSUB = class extends EventTarget {
|
|
|
214
203
|
}
|
|
215
204
|
_computeCanvasSize(width = 0, height = 0) {
|
|
216
205
|
const scalefactor = this.prescaleFactor <= 0 ? 1 : this.prescaleFactor;
|
|
206
|
+
const ratio = self.devicePixelRatio || 1;
|
|
217
207
|
if (height <= 0 || width <= 0) {
|
|
218
208
|
width = 0;
|
|
219
209
|
height = 0;
|
|
220
210
|
} else {
|
|
221
211
|
const sgn = scalefactor < 1 ? -1 : 1;
|
|
222
|
-
let newH = height;
|
|
212
|
+
let newH = height * ratio;
|
|
223
213
|
if (sgn * newH * scalefactor <= sgn * this.prescaleHeightLimit) {
|
|
224
214
|
newH *= scalefactor;
|
|
225
215
|
} else if (sgn * newH < sgn * this.prescaleHeightLimit) {
|
|
@@ -227,7 +217,7 @@ const _JASSUB = class extends EventTarget {
|
|
|
227
217
|
}
|
|
228
218
|
if (this.maxRenderHeight > 0 && newH > this.maxRenderHeight)
|
|
229
219
|
newH = this.maxRenderHeight;
|
|
230
|
-
width *= newH / height;
|
|
220
|
+
width *= ratio * newH / height;
|
|
231
221
|
height = newH;
|
|
232
222
|
}
|
|
233
223
|
return { width, height };
|
|
@@ -257,10 +247,10 @@ const _JASSUB = class extends EventTarget {
|
|
|
257
247
|
video.addEventListener("seeking", this._boundTimeUpdate, false);
|
|
258
248
|
video.addEventListener("playing", this._boundTimeUpdate, false);
|
|
259
249
|
video.addEventListener("ratechange", this._boundSetRate, false);
|
|
250
|
+
video.addEventListener("resize", this._boundResize);
|
|
260
251
|
}
|
|
261
252
|
if (video.videoWidth > 0)
|
|
262
253
|
this.resize();
|
|
263
|
-
video.addEventListener("resize", this._boundResize);
|
|
264
254
|
if (typeof ResizeObserver !== "undefined") {
|
|
265
255
|
if (!this._ro)
|
|
266
256
|
this._ro = new ResizeObserver(() => this.resize());
|
|
@@ -365,24 +355,35 @@ const _JASSUB = class extends EventTarget {
|
|
|
365
355
|
this.busy = false;
|
|
366
356
|
}
|
|
367
357
|
}
|
|
368
|
-
_handleRVFC(now, { mediaTime }) {
|
|
358
|
+
_handleRVFC(now, { mediaTime, width, height }) {
|
|
369
359
|
if (this._destroyed)
|
|
370
360
|
return null;
|
|
371
361
|
if (this.busy) {
|
|
372
|
-
this._lastDemandTime = mediaTime;
|
|
362
|
+
this._lastDemandTime = { mediaTime, width, height };
|
|
373
363
|
} else {
|
|
374
364
|
this.busy = true;
|
|
375
|
-
this._demandRender(mediaTime);
|
|
365
|
+
this._demandRender({ mediaTime, width, height });
|
|
376
366
|
}
|
|
377
367
|
this._video.requestVideoFrameCallback(this._handleRVFC.bind(this));
|
|
378
368
|
}
|
|
379
|
-
_demandRender(
|
|
369
|
+
_demandRender({ mediaTime, width, height }) {
|
|
380
370
|
this._lastDemandTime = null;
|
|
381
|
-
this.
|
|
371
|
+
if (width !== this._videoWidth || height !== this._videoHeight) {
|
|
372
|
+
this._videoWidth = width;
|
|
373
|
+
this._videoHeight = height;
|
|
374
|
+
this.resize();
|
|
375
|
+
}
|
|
376
|
+
this.sendMessage("demand", { time: mediaTime + this.timeOffset });
|
|
382
377
|
}
|
|
383
|
-
_render({ images, async, times }) {
|
|
378
|
+
_render({ images, async, times, width, height }) {
|
|
379
|
+
this._unbusy();
|
|
384
380
|
const drawStartTime = Date.now();
|
|
385
|
-
|
|
381
|
+
if (this._canvasctrl.width !== width || this._canvasctrl.height !== height) {
|
|
382
|
+
this._canvasctrl.width = width;
|
|
383
|
+
this._canvasctrl.height = height;
|
|
384
|
+
} else {
|
|
385
|
+
this._ctx.clearRect(0, 0, this._canvasctrl.width, this._canvasctrl.height);
|
|
386
|
+
}
|
|
386
387
|
for (const image of images) {
|
|
387
388
|
if (image.image) {
|
|
388
389
|
if (async) {
|
package/dist/jassub.js
CHANGED
|
@@ -46,6 +46,8 @@ export default class JASSUB extends EventTarget {
|
|
|
46
46
|
|
|
47
47
|
this.timeOffset = options.timeOffset || 0
|
|
48
48
|
this._video = options.video
|
|
49
|
+
this._videoHeight = 0
|
|
50
|
+
this._videoWidth = 0
|
|
49
51
|
this._canvas = options.canvas
|
|
50
52
|
if (this._video && !this._canvas) {
|
|
51
53
|
this._canvasParent = document.createElement('div')
|
|
@@ -88,8 +90,8 @@ export default class JASSUB extends EventTarget {
|
|
|
88
90
|
target: 'init',
|
|
89
91
|
asyncRender,
|
|
90
92
|
onDemandRender: this._onDemandRender,
|
|
91
|
-
width: this.
|
|
92
|
-
height: this.
|
|
93
|
+
width: this._canvasctrl.width,
|
|
94
|
+
height: this._canvasctrl.height,
|
|
93
95
|
preMain: true,
|
|
94
96
|
blendMode,
|
|
95
97
|
subUrl: options.subUrl,
|
|
@@ -181,54 +183,41 @@ export default class JASSUB extends EventTarget {
|
|
|
181
183
|
* @param {Number} [height=0]
|
|
182
184
|
* @param {Number} [top=0]
|
|
183
185
|
* @param {Number} [left=0]
|
|
186
|
+
* @param {Boolean} [force=false]
|
|
184
187
|
*/
|
|
185
|
-
resize (width = 0, height = 0, top = 0, left = 0) {
|
|
186
|
-
let videoSize = null
|
|
188
|
+
resize (width = 0, height = 0, top = 0, left = 0, force = this._video?.paused) {
|
|
187
189
|
if ((!width || !height) && this._video) {
|
|
188
|
-
videoSize = this._getVideoPosition()
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
190
|
+
const videoSize = this._getVideoPosition()
|
|
191
|
+
let renderSize = null
|
|
192
|
+
// support anamorphic video
|
|
193
|
+
if (this._videoWidth) {
|
|
194
|
+
const widthRatio = this._video.videoWidth / this._videoWidth
|
|
195
|
+
const heightRatio = this._video.videoHeight / this._videoHeight
|
|
196
|
+
renderSize = this._computeCanvasSize((videoSize.width || 0) / widthRatio, (videoSize.height || 0) / heightRatio)
|
|
197
|
+
} else {
|
|
198
|
+
renderSize = this._computeCanvasSize(videoSize.width || 0, videoSize.height || 0)
|
|
199
|
+
}
|
|
200
|
+
width = renderSize.width
|
|
201
|
+
height = renderSize.height
|
|
192
202
|
if (this._canvasParent) {
|
|
193
203
|
top = videoSize.y - (this._canvasParent.getBoundingClientRect().top - this._video.getBoundingClientRect().top)
|
|
194
204
|
left = videoSize.x
|
|
195
205
|
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
if (videoSize != null) {
|
|
199
|
-
this._canvas.style.top = top + 'px'
|
|
200
|
-
this._canvas.style.left = left + 'px'
|
|
201
206
|
this._canvas.style.width = videoSize.width + 'px'
|
|
202
207
|
this._canvas.style.height = videoSize.height + 'px'
|
|
203
208
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
clearTimeout(this._resizeTimeoutBuffer)
|
|
209
|
-
this._resizeTimeoutBuffer = setTimeout(() => {
|
|
210
|
-
this._resizeTimeoutBuffer = undefined
|
|
211
|
-
this._canvasctrl.width = width
|
|
212
|
-
this._canvasctrl.height = height
|
|
213
|
-
this.sendMessage('canvas', { width, height })
|
|
214
|
-
}, 100)
|
|
215
|
-
} else {
|
|
216
|
-
this._canvasctrl.width = width
|
|
217
|
-
this._canvasctrl.height = height
|
|
218
|
-
this.sendMessage('canvas', { width, height })
|
|
219
|
-
this._resizeTimeoutBuffer = setTimeout(() => {
|
|
220
|
-
this._resizeTimeoutBuffer = undefined
|
|
221
|
-
}, 100)
|
|
222
|
-
}
|
|
223
|
-
}
|
|
209
|
+
|
|
210
|
+
this._canvas.style.top = top + 'px'
|
|
211
|
+
this._canvas.style.left = left + 'px'
|
|
212
|
+
this.sendMessage('canvas', { width, height, force: force && this.busy === false })
|
|
224
213
|
}
|
|
225
214
|
|
|
226
|
-
_getVideoPosition () {
|
|
227
|
-
const videoRatio =
|
|
215
|
+
_getVideoPosition (width = this._video.videoWidth, height = this._video.videoHeight) {
|
|
216
|
+
const videoRatio = width / height
|
|
228
217
|
const { offsetWidth, offsetHeight } = this._video
|
|
229
218
|
const elementRatio = offsetWidth / offsetHeight
|
|
230
|
-
|
|
231
|
-
|
|
219
|
+
width = offsetWidth
|
|
220
|
+
height = offsetHeight
|
|
232
221
|
if (elementRatio > videoRatio) {
|
|
233
222
|
width = Math.floor(offsetHeight * videoRatio)
|
|
234
223
|
} else {
|
|
@@ -243,13 +232,14 @@ export default class JASSUB extends EventTarget {
|
|
|
243
232
|
|
|
244
233
|
_computeCanvasSize (width = 0, height = 0) {
|
|
245
234
|
const scalefactor = this.prescaleFactor <= 0 ? 1.0 : this.prescaleFactor
|
|
235
|
+
const ratio = self.devicePixelRatio || 1
|
|
246
236
|
|
|
247
237
|
if (height <= 0 || width <= 0) {
|
|
248
238
|
width = 0
|
|
249
239
|
height = 0
|
|
250
240
|
} else {
|
|
251
241
|
const sgn = scalefactor < 1 ? -1 : 1
|
|
252
|
-
let newH = height
|
|
242
|
+
let newH = height * ratio
|
|
253
243
|
if (sgn * newH * scalefactor <= sgn * this.prescaleHeightLimit) {
|
|
254
244
|
newH *= scalefactor
|
|
255
245
|
} else if (sgn * newH < sgn * this.prescaleHeightLimit) {
|
|
@@ -258,7 +248,7 @@ export default class JASSUB extends EventTarget {
|
|
|
258
248
|
|
|
259
249
|
if (this.maxRenderHeight > 0 && newH > this.maxRenderHeight) newH = this.maxRenderHeight
|
|
260
250
|
|
|
261
|
-
width *= newH / height
|
|
251
|
+
width *= ratio * newH / height
|
|
262
252
|
height = newH
|
|
263
253
|
}
|
|
264
254
|
|
|
@@ -295,9 +285,9 @@ export default class JASSUB extends EventTarget {
|
|
|
295
285
|
video.addEventListener('seeking', this._boundTimeUpdate, false)
|
|
296
286
|
video.addEventListener('playing', this._boundTimeUpdate, false)
|
|
297
287
|
video.addEventListener('ratechange', this._boundSetRate, false)
|
|
288
|
+
video.addEventListener('resize', this._boundResize)
|
|
298
289
|
}
|
|
299
290
|
if (video.videoWidth > 0) this.resize()
|
|
300
|
-
video.addEventListener('resize', this._boundResize)
|
|
301
291
|
// Support Element Resize Observer
|
|
302
292
|
if (typeof ResizeObserver !== 'undefined') {
|
|
303
293
|
if (!this._ro) this._ro = new ResizeObserver(() => this.resize())
|
|
@@ -533,25 +523,36 @@ export default class JASSUB extends EventTarget {
|
|
|
533
523
|
}
|
|
534
524
|
}
|
|
535
525
|
|
|
536
|
-
_handleRVFC (now, { mediaTime }) {
|
|
526
|
+
_handleRVFC (now, { mediaTime, width, height }) {
|
|
537
527
|
if (this._destroyed) return null
|
|
538
528
|
if (this.busy) {
|
|
539
|
-
this._lastDemandTime = mediaTime
|
|
529
|
+
this._lastDemandTime = { mediaTime, width, height }
|
|
540
530
|
} else {
|
|
541
531
|
this.busy = true
|
|
542
|
-
this._demandRender(mediaTime)
|
|
532
|
+
this._demandRender({ mediaTime, width, height })
|
|
543
533
|
}
|
|
544
534
|
this._video.requestVideoFrameCallback(this._handleRVFC.bind(this))
|
|
545
535
|
}
|
|
546
536
|
|
|
547
|
-
_demandRender (
|
|
537
|
+
_demandRender ({ mediaTime, width, height }) {
|
|
548
538
|
this._lastDemandTime = null
|
|
549
|
-
this.
|
|
539
|
+
if (width !== this._videoWidth || height !== this._videoHeight) {
|
|
540
|
+
this._videoWidth = width
|
|
541
|
+
this._videoHeight = height
|
|
542
|
+
this.resize()
|
|
543
|
+
}
|
|
544
|
+
this.sendMessage('demand', { time: mediaTime + this.timeOffset })
|
|
550
545
|
}
|
|
551
546
|
|
|
552
|
-
_render ({ images, async, times }) {
|
|
547
|
+
_render ({ images, async, times, width, height }) {
|
|
548
|
+
this._unbusy()
|
|
553
549
|
const drawStartTime = Date.now()
|
|
554
|
-
|
|
550
|
+
if (this._canvasctrl.width !== width || this._canvasctrl.height !== height) {
|
|
551
|
+
this._canvasctrl.width = width
|
|
552
|
+
this._canvasctrl.height = height
|
|
553
|
+
} else {
|
|
554
|
+
this._ctx.clearRect(0, 0, this._canvasctrl.width, this._canvasctrl.height)
|
|
555
|
+
}
|
|
555
556
|
for (const image of images) {
|
|
556
557
|
if (image.image) {
|
|
557
558
|
if (async) {
|
package/dist/jassub.umd.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(h,n){typeof exports=="object"&&typeof module!="undefined"?module.exports=n():typeof define=="function"&&define.amd?define(n):(h=typeof globalThis!="undefined"?globalThis:h||self,h.JASSUB=n())})(this,function(){"use strict";var _=Object.defineProperty;var v=(h,n,d)=>n in h?_(h,n,{enumerable:!0,configurable:!0,writable:!0,value:d}):h[n]=d;var f=(h,n,d)=>(v(h,typeof n!="symbol"?n+"":n,d),d);!("requestVideoFrameCallback"in HTMLVideoElement.prototype)&&"getVideoPlaybackQuality"in HTMLVideoElement.prototype&&(HTMLVideoElement.prototype._rvfcpolyfillmap={},HTMLVideoElement.prototype.requestVideoFrameCallback=function(d){const e=this.getVideoPlaybackQuality(),t=this.mozPresentedFrames||this.mozPaintedFrames||e.totalVideoFrames-e.droppedVideoFrames,s=(r,o)=>{const l=this.getVideoPlaybackQuality(),m=this.mozPresentedFrames||this.mozPaintedFrames||l.totalVideoFrames-l.droppedVideoFrames;if(m>t){const c=this.mozFrameDelay||l.totalFrameDelay-e.totalFrameDelay||0,u=o-r;d(o,{presentationTime:o+c*1e3,expectedDisplayTime:o+u,width:this.videoWidth,height:this.videoHeight,mediaTime:Math.max(0,this.currentTime||0)+u/1e3,presentedFrames:m,processingDuration:c}),delete this._rvfcpolyfillmap[a]}else this._rvfcpolyfillmap[a]=requestAnimationFrame(c=>s(o,c))},a=Date.now(),i=performance.now();return this._rvfcpolyfillmap[a]=requestAnimationFrame(r=>s(i,r)),a},HTMLVideoElement.prototype.cancelVideoFrameCallback=function(d){cancelAnimationFrame(this._rvfcpolyfillmap[d]),delete this._rvfcpolyfillmap[d]});const n=class extends EventTarget{constructor(e={}){var i,r,o,l,m;super(),globalThis.Worker||this.destroy("Worker not supported"),n._test();const t=e.blendMode||"js",s=typeof createImageBitmap!="undefined"&&((i=e.asyncRender)!=null?i:!0),a=typeof OffscreenCanvas!="undefined"&&((r=e.offscreenRender)!=null?r:!0);this._onDemandRender="requestVideoFrameCallback"in HTMLVideoElement.prototype&&((o=e.onDemandRender)!=null?o:!0),this.timeOffset=e.timeOffset||0,this._video=e.video,this._canvas=e.canvas,this._video&&!this._canvas?(this._canvasParent=document.createElement("div"),this._canvasParent.className="JASSUB",this._canvasParent.style.position="relative",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._video.nextSibling?this._video.parentNode.insertBefore(this._canvasParent,this._video.nextSibling):this._video.parentNode.appendChild(this._canvasParent)):this._canvas||this.destroy("Don't know where to render: you should give video or canvas in options."),this._bufferCanvas=document.createElement("canvas"),this._bufferCtx=this._bufferCanvas.getContext("2d",{desynchronized:!0,willReadFrequently:!0}),this._canvasctrl=a?this._canvas.transferControlToOffscreen():this._canvas,this._ctx=!a&&this._canvasctrl.getContext("2d",{desynchronized:!0}),this._lastRenderTime=0,this.debug=!!e.debug,this.prescaleFactor=e.prescaleFactor||1,this.prescaleHeightLimit=e.prescaleHeightLimit||1080,this.maxRenderHeight=e.maxRenderHeight||0,this._worker=new Worker(n._supportsWebAssembly?e.workerUrl||"jassub-worker.js":e.legacyWorkerUrl||"jassub-worker-legacy.js"),this._worker.onmessage=c=>this._onmessage(c),this._worker.onerror=c=>this._error(c),this._worker.postMessage({target:"init",asyncRender:s,onDemandRender:this._onDemandRender,width:this._canvas.width,height:this._canvas.height,preMain:!0,blendMode:t,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,libassMemoryLimit:e.libassMemoryLimit||0,libassGlyphLimit:e.libassGlyphLimit||0,hasAlphaBug:n._hasAlphaBug,useLocalFonts:"queryLocalFonts"in self&&((l=e.useLocalFonts)!=null?l:!0)}),a===!0&&this.sendMessage("offscreenCanvas",null,[this._canvasctrl]),this._boundResize=this.resize.bind(this),this._boundTimeUpdate=this._timeupdate.bind(this),this._boundSetRate=this.setRate.bind(this),this._video&&this.setVideo(e.video),this._onDemandRender&&(this.busy=!1,this._lastDemandTime=null,(m=this._video)==null||m.requestVideoFrameCallback(this._handleRVFC.bind(this)))}static _test(){if(n._supportsWebAssembly!==null)return null;const e=document.createElement("canvas"),t=e.getContext("2d",{willReadFrequently:!0});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(l,m,c){const u=t.createImageData(m,c);return l&&u.data.set(l),u}}try{if(typeof WebAssembly=="object"&&typeof WebAssembly.instantiate=="function"){const o=new WebAssembly.Module(Uint8Array.of(0,97,115,109,1,0,0,0));o instanceof WebAssembly.Module&&(n._supportsWebAssembly=new WebAssembly.Instance(o)instanceof WebAssembly.Instance)}}catch{n._supportsWebAssembly=!1}const s=document.createElement("canvas"),a=s.getContext("2d",{willReadFrequently:!0});e.width=s.width=1,e.height=s.height=1,t.clearRect(0,0,1,1),a.clearRect(0,0,1,1);const i=a.getImageData(0,0,1,1).data;t.putImageData(new ImageData(new Uint8ClampedArray([0,255,0,0]),1,1),0,0),a.drawImage(e,0,0);const r=a.getImageData(0,0,1,1).data;n._hasAlphaBug=i[1]!==r[1],n._hasAlphaBug&&console.log("Detected a browser having issue with transparent pixels, applying workaround"),e.remove(),s.remove()}resize(e=0,t=0,s=0,a=0){let i=null;if((!e||!t)&&this._video){i=this._getVideoPosition();const r=this._computeCanvasSize((i.width||0)*(self.devicePixelRatio||1),(i.height||0)*(self.devicePixelRatio||1));e=r.width,t=r.height,this._canvasParent&&(s=i.y-(this._canvasParent.getBoundingClientRect().top-this._video.getBoundingClientRect().top),a=i.x)}i!=null&&(this._canvas.style.top=s+"px",this._canvas.style.left=a+"px",this._canvas.style.width=i.width+"px",this._canvas.style.height=i.height+"px"),this._canvasctrl.width===e&&this._canvasctrl.height===t||(this._resizeTimeoutBuffer?(clearTimeout(this._resizeTimeoutBuffer),this._resizeTimeoutBuffer=setTimeout(()=>{this._resizeTimeoutBuffer=void 0,this._canvasctrl.width=e,this._canvasctrl.height=t,this.sendMessage("canvas",{width:e,height:t})},100)):(this._canvasctrl.width=e,this._canvasctrl.height=t,this.sendMessage("canvas",{width:e,height:t}),this._resizeTimeoutBuffer=setTimeout(()=>{this._resizeTimeoutBuffer=void 0},100)))}_getVideoPosition(){const e=this._video.videoWidth/this._video.videoHeight,{offsetWidth:t,offsetHeight:s}=this._video,a=t/s;let i=t,r=s;a>e?i=Math.floor(s*e):r=Math.floor(t/e);const o=(t-i)/2,l=(s-r)/2;return{width:i,height:r,x:o,y:l}}_computeCanvasSize(e=0,t=0){const s=this.prescaleFactor<=0?1:this.prescaleFactor;if(t<=0||e<=0)e=0,t=0;else{const a=s<1?-1:1;let i=t;a*i*s<=a*this.prescaleHeightLimit?i*=s:a*i<a*this.prescaleHeightLimit&&(i=this.prescaleHeightLimit),this.maxRenderHeight>0&&i>this.maxRenderHeight&&(i=this.maxRenderHeight),e*=i/t,t=i}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.videoWidth>0&&this.resize(),e.addEventListener("resize",this._boundResize),typeof ResizeObserver!="undefined"&&(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})}setTrack(e){this.sendMessage("setTrack",{content:e})}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})}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",{event: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==null?void 0:t.find(a=>a.fullName.toLowerCase()===e);s&&s.blob().then(a=>{a.arrayBuffer().then(i=>{this.addFont(new Uint8Array(i))})})})}catch(t){console.warn("Local fonts API:",t)}}_getLocalFont({font:e}){var t;try{(t=navigator==null?void 0:navigator.permissions)!=null&&t.query?navigator.permissions.query({name:"local-fonts"}).then(s=>{s.state==="granted"&&this._sendLocalFont(e)}):this._sendLocalFont(e)}catch(s){console.warn("Local fonts API:",s)}}_unbusy(){this._lastDemandTime?this._demandRender(this._lastDemandTime):this.busy=!1}_handleRVFC(e,{mediaTime:t}){if(this._destroyed)return null;this.busy?this._lastDemandTime=t:(this.busy=!0,this._demandRender(t)),this._video.requestVideoFrameCallback(this._handleRVFC.bind(this))}_demandRender(e){this._lastDemandTime=null,this.sendMessage("demand",{time:e+this.timeOffset})}_render({images:e,async:t,times:s}){const a=Date.now();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.drawTime=Date.now()-a;let i=0;for(const r in s)i+=s[r];console.log("Bitmaps: "+e.length+" Total: "+Math.round(i)+"ms",s)}}_fixAlpha(e){if(n._hasAlphaBug)for(let t=3;t<e.length;t+=4)e[t]=e[t]>1?e[t]:1;return e}_ready(){this.dispatchEvent(new CustomEvent("ready"))}sendMessage(e,t={},s){s?this._worker.postMessage({target:e,transferable:s,...t},[...s]):this._worker.postMessage({target:e,...t})}_fetchFromWorker(e,t){try{const s=e.target,a=setTimeout(()=>{r(new Error("Error: Timeout while try to fetch "+s))},5e3),i=({data:o})=>{o.target===s&&(t(null,o),this._worker.removeEventListener("message",i),this._worker.removeEventListener("error",r),clearTimeout(a))},r=o=>{t(o),this._worker.removeEventListener("message",i),this._worker.removeEventListener("error",r),clearTimeout(a)};this._worker.addEventListener("message",i),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){this.dispatchEvent(e instanceof ErrorEvent?e:new ErrorEvent("error",{cause:e instanceof Error?e.cause:e})),e instanceof Error||(e instanceof ErrorEvent?e=e.error:e=new Error("error",{cause:e})),console.error(e)}_removeListeners(){this._video&&(this._ro&&this._ro.unobserve(this._video),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))}destroy(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()}};let h=n;return f(h,"_supportsWebAssembly",null),f(h,"_hasAlphaBug",null),h});
|
|
1
|
+
(function(d,o){typeof exports=="object"&&typeof module!="undefined"?module.exports=o():typeof define=="function"&&define.amd?define(o):(d=typeof globalThis!="undefined"?globalThis:d||self,d.JASSUB=o())})(this,function(){"use strict";var v=Object.defineProperty;var f=(d,o,c)=>o in d?v(d,o,{enumerable:!0,configurable:!0,writable:!0,value:c}):d[o]=c;var u=(d,o,c)=>(f(d,typeof o!="symbol"?o+"":o,c),c);!("requestVideoFrameCallback"in HTMLVideoElement.prototype)&&"getVideoPlaybackQuality"in HTMLVideoElement.prototype&&(HTMLVideoElement.prototype._rvfcpolyfillmap={},HTMLVideoElement.prototype.requestVideoFrameCallback=function(c){const e=this.getVideoPlaybackQuality(),t=this.mozPresentedFrames||this.mozPaintedFrames||e.totalVideoFrames-e.droppedVideoFrames,s=(n,i)=>{const h=this.getVideoPlaybackQuality(),m=this.mozPresentedFrames||this.mozPaintedFrames||h.totalVideoFrames-h.droppedVideoFrames;if(m>t){const l=this.mozFrameDelay||h.totalFrameDelay-e.totalFrameDelay||0,_=i-n;c(i,{presentationTime:i+l*1e3,expectedDisplayTime:i+_,width:this.videoWidth,height:this.videoHeight,mediaTime:Math.max(0,this.currentTime||0)+_/1e3,presentedFrames:m,processingDuration:l}),delete this._rvfcpolyfillmap[a]}else this._rvfcpolyfillmap[a]=requestAnimationFrame(l=>s(i,l))},a=Date.now(),r=performance.now();return this._rvfcpolyfillmap[a]=requestAnimationFrame(n=>s(r,n)),a},HTMLVideoElement.prototype.cancelVideoFrameCallback=function(c){cancelAnimationFrame(this._rvfcpolyfillmap[c]),delete this._rvfcpolyfillmap[c]});const o=class extends EventTarget{constructor(e={}){var r,n,i,h,m;super(),globalThis.Worker||this.destroy("Worker not supported"),o._test();const t=e.blendMode||"js",s=typeof createImageBitmap!="undefined"&&((r=e.asyncRender)!=null?r:!0),a=typeof OffscreenCanvas!="undefined"&&((n=e.offscreenRender)!=null?n:!0);this._onDemandRender="requestVideoFrameCallback"in HTMLVideoElement.prototype&&((i=e.onDemandRender)!=null?i:!0),this.timeOffset=e.timeOffset||0,this._video=e.video,this._videoHeight=0,this._videoWidth=0,this._canvas=e.canvas,this._video&&!this._canvas?(this._canvasParent=document.createElement("div"),this._canvasParent.className="JASSUB",this._canvasParent.style.position="relative",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._video.nextSibling?this._video.parentNode.insertBefore(this._canvasParent,this._video.nextSibling):this._video.parentNode.appendChild(this._canvasParent)):this._canvas||this.destroy("Don't know where to render: you should give video or canvas in options."),this._bufferCanvas=document.createElement("canvas"),this._bufferCtx=this._bufferCanvas.getContext("2d",{desynchronized:!0,willReadFrequently:!0}),this._canvasctrl=a?this._canvas.transferControlToOffscreen():this._canvas,this._ctx=!a&&this._canvasctrl.getContext("2d",{desynchronized:!0}),this._lastRenderTime=0,this.debug=!!e.debug,this.prescaleFactor=e.prescaleFactor||1,this.prescaleHeightLimit=e.prescaleHeightLimit||1080,this.maxRenderHeight=e.maxRenderHeight||0,this._worker=new Worker(o._supportsWebAssembly?e.workerUrl||"jassub-worker.js":e.legacyWorkerUrl||"jassub-worker-legacy.js"),this._worker.onmessage=l=>this._onmessage(l),this._worker.onerror=l=>this._error(l),this._worker.postMessage({target:"init",asyncRender:s,onDemandRender:this._onDemandRender,width:this._canvasctrl.width,height:this._canvasctrl.height,preMain:!0,blendMode:t,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,libassMemoryLimit:e.libassMemoryLimit||0,libassGlyphLimit:e.libassGlyphLimit||0,hasAlphaBug:o._hasAlphaBug,useLocalFonts:"queryLocalFonts"in self&&((h=e.useLocalFonts)!=null?h:!0)}),a===!0&&this.sendMessage("offscreenCanvas",null,[this._canvasctrl]),this._boundResize=this.resize.bind(this),this._boundTimeUpdate=this._timeupdate.bind(this),this._boundSetRate=this.setRate.bind(this),this._video&&this.setVideo(e.video),this._onDemandRender&&(this.busy=!1,this._lastDemandTime=null,(m=this._video)==null||m.requestVideoFrameCallback(this._handleRVFC.bind(this)))}static _test(){if(o._supportsWebAssembly!==null)return null;const e=document.createElement("canvas"),t=e.getContext("2d",{willReadFrequently:!0});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,m,l){const _=t.createImageData(m,l);return h&&_.data.set(h),_}}try{if(typeof WebAssembly=="object"&&typeof WebAssembly.instantiate=="function"){const i=new WebAssembly.Module(Uint8Array.of(0,97,115,109,1,0,0,0));i instanceof WebAssembly.Module&&(o._supportsWebAssembly=new WebAssembly.Instance(i)instanceof WebAssembly.Instance)}}catch{o._supportsWebAssembly=!1}const s=document.createElement("canvas"),a=s.getContext("2d",{willReadFrequently:!0});e.width=s.width=1,e.height=s.height=1,t.clearRect(0,0,1,1),a.clearRect(0,0,1,1);const r=a.getImageData(0,0,1,1).data;t.putImageData(new ImageData(new Uint8ClampedArray([0,255,0,0]),1,1),0,0),a.drawImage(e,0,0);const n=a.getImageData(0,0,1,1).data;o._hasAlphaBug=r[1]!==n[1],o._hasAlphaBug&&console.log("Detected a browser having issue with transparent pixels, applying workaround"),e.remove(),s.remove()}resize(e=0,t=0,s=0,a=0,r=(n=>(n=this._video)==null?void 0:n.paused)()){if((!e||!t)&&this._video){const i=this._getVideoPosition();let h=null;if(this._videoWidth){const m=this._video.videoWidth/this._videoWidth,l=this._video.videoHeight/this._videoHeight;h=this._computeCanvasSize((i.width||0)/m,(i.height||0)/l)}else h=this._computeCanvasSize(i.width||0,i.height||0);e=h.width,t=h.height,this._canvasParent&&(s=i.y-(this._canvasParent.getBoundingClientRect().top-this._video.getBoundingClientRect().top),a=i.x),this._canvas.style.width=i.width+"px",this._canvas.style.height=i.height+"px"}this._canvas.style.top=s+"px",this._canvas.style.left=a+"px",this.sendMessage("canvas",{width:e,height:t,force:r&&this.busy===!1})}_getVideoPosition(e=this._video.videoWidth,t=this._video.videoHeight){const s=e/t,{offsetWidth:a,offsetHeight:r}=this._video,n=a/r;e=a,t=r,n>s?e=Math.floor(r*s):t=Math.floor(a/s);const i=(a-e)/2,h=(r-t)/2;return{width:e,height:t,x:i,y:h}}_computeCanvasSize(e=0,t=0){const s=this.prescaleFactor<=0?1:this.prescaleFactor,a=self.devicePixelRatio||1;if(t<=0||e<=0)e=0,t=0;else{const r=s<1?-1:1;let n=t*a;r*n*s<=r*this.prescaleHeightLimit?n*=s:r*n<r*this.prescaleHeightLimit&&(n=this.prescaleHeightLimit),this.maxRenderHeight>0&&n>this.maxRenderHeight&&(n=this.maxRenderHeight),e*=a*n/t,t=n}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)),e.videoWidth>0&&this.resize(),typeof ResizeObserver!="undefined"&&(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})}setTrack(e){this.sendMessage("setTrack",{content:e})}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})}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",{event: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==null?void 0:t.find(a=>a.fullName.toLowerCase()===e);s&&s.blob().then(a=>{a.arrayBuffer().then(r=>{this.addFont(new Uint8Array(r))})})})}catch(t){console.warn("Local fonts API:",t)}}_getLocalFont({font:e}){var t;try{(t=navigator==null?void 0:navigator.permissions)!=null&&t.query?navigator.permissions.query({name:"local-fonts"}).then(s=>{s.state==="granted"&&this._sendLocalFont(e)}):this._sendLocalFont(e)}catch(s){console.warn("Local fonts API:",s)}}_unbusy(){this._lastDemandTime?this._demandRender(this._lastDemandTime):this.busy=!1}_handleRVFC(e,{mediaTime:t,width:s,height:a}){if(this._destroyed)return null;this.busy?this._lastDemandTime={mediaTime:t,width:s,height:a}:(this.busy=!0,this._demandRender({mediaTime:t,width:s,height:a})),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})}_render({images:e,async:t,times:s,width:a,height:r}){this._unbusy();const n=Date.now();this._canvasctrl.width!==a||this._canvasctrl.height!==r?(this._canvasctrl.width=a,this._canvasctrl.height=r):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.drawTime=Date.now()-n;let i=0;for(const h in s)i+=s[h];console.log("Bitmaps: "+e.length+" Total: "+Math.round(i)+"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.dispatchEvent(new CustomEvent("ready"))}sendMessage(e,t={},s){s?this._worker.postMessage({target:e,transferable:s,...t},[...s]):this._worker.postMessage({target:e,...t})}_fetchFromWorker(e,t){try{const s=e.target,a=setTimeout(()=>{n(new Error("Error: Timeout while try to fetch "+s))},5e3),r=({data:i})=>{i.target===s&&(t(null,i),this._worker.removeEventListener("message",r),this._worker.removeEventListener("error",n),clearTimeout(a))},n=i=>{t(i),this._worker.removeEventListener("message",r),this._worker.removeEventListener("error",n),clearTimeout(a)};this._worker.addEventListener("message",r),this._worker.addEventListener("error",n),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){this.dispatchEvent(e instanceof ErrorEvent?e:new ErrorEvent("error",{cause:e instanceof Error?e.cause:e})),e instanceof Error||(e instanceof ErrorEvent?e=e.error:e=new Error("error",{cause:e})),console.error(e)}_removeListeners(){this._video&&(this._ro&&this._ro.unobserve(this._video),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))}destroy(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()}};let d=o;return u(d,"_supportsWebAssembly",null),u(d,"_hasAlphaBug",null),d});
|
package/package.json
CHANGED
package/src/jassub.js
CHANGED
|
@@ -44,6 +44,8 @@ export default class JASSUB extends EventTarget {
|
|
|
44
44
|
|
|
45
45
|
this.timeOffset = options.timeOffset || 0
|
|
46
46
|
this._video = options.video
|
|
47
|
+
this._videoHeight = 0
|
|
48
|
+
this._videoWidth = 0
|
|
47
49
|
this._canvas = options.canvas
|
|
48
50
|
if (this._video && !this._canvas) {
|
|
49
51
|
this._canvasParent = document.createElement('div')
|
|
@@ -86,8 +88,8 @@ export default class JASSUB extends EventTarget {
|
|
|
86
88
|
target: 'init',
|
|
87
89
|
asyncRender,
|
|
88
90
|
onDemandRender: this._onDemandRender,
|
|
89
|
-
width: this.
|
|
90
|
-
height: this.
|
|
91
|
+
width: this._canvasctrl.width,
|
|
92
|
+
height: this._canvasctrl.height,
|
|
91
93
|
preMain: true,
|
|
92
94
|
blendMode,
|
|
93
95
|
subUrl: options.subUrl,
|
|
@@ -179,54 +181,41 @@ export default class JASSUB extends EventTarget {
|
|
|
179
181
|
* @param {Number} [height=0]
|
|
180
182
|
* @param {Number} [top=0]
|
|
181
183
|
* @param {Number} [left=0]
|
|
184
|
+
* @param {Boolean} [force=false]
|
|
182
185
|
*/
|
|
183
|
-
resize (width = 0, height = 0, top = 0, left = 0) {
|
|
184
|
-
let videoSize = null
|
|
186
|
+
resize (width = 0, height = 0, top = 0, left = 0, force = this._video?.paused) {
|
|
185
187
|
if ((!width || !height) && this._video) {
|
|
186
|
-
videoSize = this._getVideoPosition()
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
188
|
+
const videoSize = this._getVideoPosition()
|
|
189
|
+
let renderSize = null
|
|
190
|
+
// support anamorphic video
|
|
191
|
+
if (this._videoWidth) {
|
|
192
|
+
const widthRatio = this._video.videoWidth / this._videoWidth
|
|
193
|
+
const heightRatio = this._video.videoHeight / this._videoHeight
|
|
194
|
+
renderSize = this._computeCanvasSize((videoSize.width || 0) / widthRatio, (videoSize.height || 0) / heightRatio)
|
|
195
|
+
} else {
|
|
196
|
+
renderSize = this._computeCanvasSize(videoSize.width || 0, videoSize.height || 0)
|
|
197
|
+
}
|
|
198
|
+
width = renderSize.width
|
|
199
|
+
height = renderSize.height
|
|
190
200
|
if (this._canvasParent) {
|
|
191
201
|
top = videoSize.y - (this._canvasParent.getBoundingClientRect().top - this._video.getBoundingClientRect().top)
|
|
192
202
|
left = videoSize.x
|
|
193
203
|
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
if (videoSize != null) {
|
|
197
|
-
this._canvas.style.top = top + 'px'
|
|
198
|
-
this._canvas.style.left = left + 'px'
|
|
199
204
|
this._canvas.style.width = videoSize.width + 'px'
|
|
200
205
|
this._canvas.style.height = videoSize.height + 'px'
|
|
201
206
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
clearTimeout(this._resizeTimeoutBuffer)
|
|
207
|
-
this._resizeTimeoutBuffer = setTimeout(() => {
|
|
208
|
-
this._resizeTimeoutBuffer = undefined
|
|
209
|
-
this._canvasctrl.width = width
|
|
210
|
-
this._canvasctrl.height = height
|
|
211
|
-
this.sendMessage('canvas', { width, height })
|
|
212
|
-
}, 100)
|
|
213
|
-
} else {
|
|
214
|
-
this._canvasctrl.width = width
|
|
215
|
-
this._canvasctrl.height = height
|
|
216
|
-
this.sendMessage('canvas', { width, height })
|
|
217
|
-
this._resizeTimeoutBuffer = setTimeout(() => {
|
|
218
|
-
this._resizeTimeoutBuffer = undefined
|
|
219
|
-
}, 100)
|
|
220
|
-
}
|
|
221
|
-
}
|
|
207
|
+
|
|
208
|
+
this._canvas.style.top = top + 'px'
|
|
209
|
+
this._canvas.style.left = left + 'px'
|
|
210
|
+
this.sendMessage('canvas', { width, height, force: force && this.busy === false })
|
|
222
211
|
}
|
|
223
212
|
|
|
224
|
-
_getVideoPosition () {
|
|
225
|
-
const videoRatio =
|
|
213
|
+
_getVideoPosition (width = this._video.videoWidth, height = this._video.videoHeight) {
|
|
214
|
+
const videoRatio = width / height
|
|
226
215
|
const { offsetWidth, offsetHeight } = this._video
|
|
227
216
|
const elementRatio = offsetWidth / offsetHeight
|
|
228
|
-
|
|
229
|
-
|
|
217
|
+
width = offsetWidth
|
|
218
|
+
height = offsetHeight
|
|
230
219
|
if (elementRatio > videoRatio) {
|
|
231
220
|
width = Math.floor(offsetHeight * videoRatio)
|
|
232
221
|
} else {
|
|
@@ -241,13 +230,14 @@ export default class JASSUB extends EventTarget {
|
|
|
241
230
|
|
|
242
231
|
_computeCanvasSize (width = 0, height = 0) {
|
|
243
232
|
const scalefactor = this.prescaleFactor <= 0 ? 1.0 : this.prescaleFactor
|
|
233
|
+
const ratio = self.devicePixelRatio || 1
|
|
244
234
|
|
|
245
235
|
if (height <= 0 || width <= 0) {
|
|
246
236
|
width = 0
|
|
247
237
|
height = 0
|
|
248
238
|
} else {
|
|
249
239
|
const sgn = scalefactor < 1 ? -1 : 1
|
|
250
|
-
let newH = height
|
|
240
|
+
let newH = height * ratio
|
|
251
241
|
if (sgn * newH * scalefactor <= sgn * this.prescaleHeightLimit) {
|
|
252
242
|
newH *= scalefactor
|
|
253
243
|
} else if (sgn * newH < sgn * this.prescaleHeightLimit) {
|
|
@@ -256,7 +246,7 @@ export default class JASSUB extends EventTarget {
|
|
|
256
246
|
|
|
257
247
|
if (this.maxRenderHeight > 0 && newH > this.maxRenderHeight) newH = this.maxRenderHeight
|
|
258
248
|
|
|
259
|
-
width *= newH / height
|
|
249
|
+
width *= ratio * newH / height
|
|
260
250
|
height = newH
|
|
261
251
|
}
|
|
262
252
|
|
|
@@ -293,9 +283,9 @@ export default class JASSUB extends EventTarget {
|
|
|
293
283
|
video.addEventListener('seeking', this._boundTimeUpdate, false)
|
|
294
284
|
video.addEventListener('playing', this._boundTimeUpdate, false)
|
|
295
285
|
video.addEventListener('ratechange', this._boundSetRate, false)
|
|
286
|
+
video.addEventListener('resize', this._boundResize)
|
|
296
287
|
}
|
|
297
288
|
if (video.videoWidth > 0) this.resize()
|
|
298
|
-
video.addEventListener('resize', this._boundResize)
|
|
299
289
|
// Support Element Resize Observer
|
|
300
290
|
if (typeof ResizeObserver !== 'undefined') {
|
|
301
291
|
if (!this._ro) this._ro = new ResizeObserver(() => this.resize())
|
|
@@ -531,25 +521,36 @@ export default class JASSUB extends EventTarget {
|
|
|
531
521
|
}
|
|
532
522
|
}
|
|
533
523
|
|
|
534
|
-
_handleRVFC (now, { mediaTime }) {
|
|
524
|
+
_handleRVFC (now, { mediaTime, width, height }) {
|
|
535
525
|
if (this._destroyed) return null
|
|
536
526
|
if (this.busy) {
|
|
537
|
-
this._lastDemandTime = mediaTime
|
|
527
|
+
this._lastDemandTime = { mediaTime, width, height }
|
|
538
528
|
} else {
|
|
539
529
|
this.busy = true
|
|
540
|
-
this._demandRender(mediaTime)
|
|
530
|
+
this._demandRender({ mediaTime, width, height })
|
|
541
531
|
}
|
|
542
532
|
this._video.requestVideoFrameCallback(this._handleRVFC.bind(this))
|
|
543
533
|
}
|
|
544
534
|
|
|
545
|
-
_demandRender (
|
|
535
|
+
_demandRender ({ mediaTime, width, height }) {
|
|
546
536
|
this._lastDemandTime = null
|
|
547
|
-
this.
|
|
537
|
+
if (width !== this._videoWidth || height !== this._videoHeight) {
|
|
538
|
+
this._videoWidth = width
|
|
539
|
+
this._videoHeight = height
|
|
540
|
+
this.resize()
|
|
541
|
+
}
|
|
542
|
+
this.sendMessage('demand', { time: mediaTime + this.timeOffset })
|
|
548
543
|
}
|
|
549
544
|
|
|
550
|
-
_render ({ images, async, times }) {
|
|
545
|
+
_render ({ images, async, times, width, height }) {
|
|
546
|
+
this._unbusy()
|
|
551
547
|
const drawStartTime = Date.now()
|
|
552
|
-
|
|
548
|
+
if (this._canvasctrl.width !== width || this._canvasctrl.height !== height) {
|
|
549
|
+
this._canvasctrl.width = width
|
|
550
|
+
this._canvasctrl.height = height
|
|
551
|
+
} else {
|
|
552
|
+
this._ctx.clearRect(0, 0, this._canvasctrl.width, this._canvasctrl.height)
|
|
553
|
+
}
|
|
553
554
|
for (const image of images) {
|
|
554
555
|
if (image.image) {
|
|
555
556
|
if (async) {
|