jassub 1.4.1 → 1.4.2
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.es.js +44 -40
- package/dist/jassub.umd.js +1 -1
- package/package.json +1 -1
- package/src/jassub.js +38 -34
package/dist/jassub.es.js
CHANGED
|
@@ -85,44 +85,47 @@ const _JASSUB = class extends EventTarget {
|
|
|
85
85
|
this._worker = new Worker(_JASSUB._supportsWebAssembly ? options.workerUrl || "jassub-worker.js" : options.legacyWorkerUrl || "jassub-worker-legacy.js");
|
|
86
86
|
this._worker.onmessage = (e) => this._onmessage(e);
|
|
87
87
|
this._worker.onerror = (e) => this._error(e);
|
|
88
|
-
this.
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
this.
|
|
120
|
-
|
|
121
|
-
this.
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
88
|
+
this._ready = new Promise((resolve) => {
|
|
89
|
+
this._init = () => {
|
|
90
|
+
var _a2, _b2;
|
|
91
|
+
if (this._destroyed)
|
|
92
|
+
return;
|
|
93
|
+
this._worker.postMessage({
|
|
94
|
+
target: "init",
|
|
95
|
+
asyncRender,
|
|
96
|
+
onDemandRender: this._onDemandRender,
|
|
97
|
+
width: this._canvasctrl.width,
|
|
98
|
+
height: this._canvasctrl.height,
|
|
99
|
+
preMain: true,
|
|
100
|
+
blendMode,
|
|
101
|
+
subUrl: options.subUrl,
|
|
102
|
+
subContent: options.subContent || null,
|
|
103
|
+
fonts: options.fonts || [],
|
|
104
|
+
availableFonts: options.availableFonts || { "liberation sans": "./default.woff2" },
|
|
105
|
+
fallbackFont: options.fallbackFont || "liberation sans",
|
|
106
|
+
debug: this.debug,
|
|
107
|
+
targetFps: options.targetFps || 24,
|
|
108
|
+
dropAllAnimations: options.dropAllAnimations,
|
|
109
|
+
libassMemoryLimit: options.libassMemoryLimit || 0,
|
|
110
|
+
libassGlyphLimit: options.libassGlyphLimit || 0,
|
|
111
|
+
hasAlphaBug: _JASSUB._hasAlphaBug,
|
|
112
|
+
useLocalFonts: "queryLocalFonts" in self && ((_a2 = options.useLocalFonts) != null ? _a2 : true)
|
|
113
|
+
});
|
|
114
|
+
if (offscreenRender === true)
|
|
115
|
+
this.sendMessage("offscreenCanvas", null, [this._canvasctrl]);
|
|
116
|
+
this._boundResize = this.resize.bind(this);
|
|
117
|
+
this._boundTimeUpdate = this._timeupdate.bind(this);
|
|
118
|
+
this._boundSetRate = this.setRate.bind(this);
|
|
119
|
+
if (this._video)
|
|
120
|
+
this.setVideo(options.video);
|
|
121
|
+
if (this._onDemandRender) {
|
|
122
|
+
this.busy = false;
|
|
123
|
+
this._lastDemandTime = null;
|
|
124
|
+
(_b2 = this._video) == null ? void 0 : _b2.requestVideoFrameCallback(this._handleRVFC.bind(this));
|
|
125
|
+
}
|
|
126
|
+
resolve();
|
|
127
|
+
};
|
|
128
|
+
});
|
|
126
129
|
}
|
|
127
130
|
static _test() {
|
|
128
131
|
if (_JASSUB._supportsWebAssembly !== null)
|
|
@@ -422,7 +425,8 @@ const _JASSUB = class extends EventTarget {
|
|
|
422
425
|
this._init();
|
|
423
426
|
this.dispatchEvent(new CustomEvent("ready"));
|
|
424
427
|
}
|
|
425
|
-
sendMessage(target, data = {}, transferable) {
|
|
428
|
+
async sendMessage(target, data = {}, transferable) {
|
|
429
|
+
await this._ready;
|
|
426
430
|
if (transferable) {
|
|
427
431
|
this._worker.postMessage({
|
|
428
432
|
target,
|
|
@@ -471,7 +475,7 @@ const _JASSUB = class extends EventTarget {
|
|
|
471
475
|
this["_" + data.target](data);
|
|
472
476
|
}
|
|
473
477
|
_error(err) {
|
|
474
|
-
this.dispatchEvent(err instanceof ErrorEvent ? err : new ErrorEvent("error", { cause: err instanceof Error ? err.cause : err }));
|
|
478
|
+
this.dispatchEvent(err instanceof ErrorEvent ? new ErrorEvent(err.type, err) : new ErrorEvent("error", { cause: err instanceof Error ? err.cause : err }));
|
|
475
479
|
if (!(err instanceof Error)) {
|
|
476
480
|
if (err instanceof ErrorEvent) {
|
|
477
481
|
err = err.error;
|
package/dist/jassub.umd.js
CHANGED
|
@@ -1 +1 @@
|
|
|
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,l)=>o in d?v(d,o,{enumerable:!0,configurable:!0,writable:!0,value:l}):d[o]=l;var u=(d,o,l)=>(f(d,typeof o!="symbol"?o+"":o,l),l);!("requestVideoFrameCallback"in HTMLVideoElement.prototype)&&"getVideoPlaybackQuality"in HTMLVideoElement.prototype&&(HTMLVideoElement.prototype._rvfcpolyfillmap={},HTMLVideoElement.prototype.requestVideoFrameCallback=function(l){const e=this.getVideoPlaybackQuality(),t=this.mozPresentedFrames||this.mozPaintedFrames||e.totalVideoFrames-e.droppedVideoFrames,s=(n,i)=>{const h=this.getVideoPlaybackQuality(),c=this.mozPresentedFrames||this.mozPaintedFrames||h.totalVideoFrames-h.droppedVideoFrames;if(c>t){const m=this.mozFrameDelay||h.totalFrameDelay-e.totalFrameDelay||0,_=i-n;l(i,{presentationTime:i+m*1e3,expectedDisplayTime:i+_,width:this.videoWidth,height:this.videoHeight,mediaTime:Math.max(0,this.currentTime||0)+_/1e3,presentedFrames:c,processingDuration:m}),delete this._rvfcpolyfillmap[a]}else this._rvfcpolyfillmap[a]=requestAnimationFrame(m=>s(i,m))},a=Date.now(),r=performance.now();return this._rvfcpolyfillmap[a]=requestAnimationFrame(n=>s(r,n)),a},HTMLVideoElement.prototype.cancelVideoFrameCallback=function(l){cancelAnimationFrame(this._rvfcpolyfillmap[l]),delete this._rvfcpolyfillmap[l]});const o=class extends EventTarget{constructor(e={}){var r,n,i;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=h=>this._onmessage(h),this._worker.onerror=h=>this._error(h),this._init=()=>{var h,c;this._destroyed||(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,(c=this._video)==null||c.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,c,m){const _=t.createImageData(c,m);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 c=this._video.videoWidth/this._videoWidth,m=this._video.videoHeight/this._videoHeight;h=this._computeCanvasSize((i.width||0)/c,(i.height||0)/m)}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._init(),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});
|
|
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;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=h=>this._onmessage(h),this._worker.onerror=h=>this._error(h),this._ready=new Promise(h=>{this._init=()=>{var m,l;this._destroyed||(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&&((m=e.useLocalFonts)!=null?m:!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,(l=this._video)==null||l.requestVideoFrameCallback(this._handleRVFC.bind(this))),h())}})}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._init(),this.dispatchEvent(new CustomEvent("ready"))}async sendMessage(e,t={},s){await this._ready,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?new ErrorEvent(e.type,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
|
@@ -84,42 +84,45 @@ export default class JASSUB extends EventTarget {
|
|
|
84
84
|
this._worker.onmessage = e => this._onmessage(e)
|
|
85
85
|
this._worker.onerror = e => this._error(e)
|
|
86
86
|
|
|
87
|
-
this.
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
87
|
+
this._ready = new Promise(resolve => {
|
|
88
|
+
this._init = () => {
|
|
89
|
+
if (this._destroyed) return
|
|
90
|
+
this._worker.postMessage({
|
|
91
|
+
target: 'init',
|
|
92
|
+
asyncRender,
|
|
93
|
+
onDemandRender: this._onDemandRender,
|
|
94
|
+
width: this._canvasctrl.width,
|
|
95
|
+
height: this._canvasctrl.height,
|
|
96
|
+
preMain: true,
|
|
97
|
+
blendMode,
|
|
98
|
+
subUrl: options.subUrl,
|
|
99
|
+
subContent: options.subContent || null,
|
|
100
|
+
fonts: options.fonts || [],
|
|
101
|
+
availableFonts: options.availableFonts || { 'liberation sans': './default.woff2' },
|
|
102
|
+
fallbackFont: options.fallbackFont || 'liberation sans',
|
|
103
|
+
debug: this.debug,
|
|
104
|
+
targetFps: options.targetFps || 24,
|
|
105
|
+
dropAllAnimations: options.dropAllAnimations,
|
|
106
|
+
libassMemoryLimit: options.libassMemoryLimit || 0,
|
|
107
|
+
libassGlyphLimit: options.libassGlyphLimit || 0,
|
|
108
|
+
hasAlphaBug: JASSUB._hasAlphaBug,
|
|
109
|
+
useLocalFonts: ('queryLocalFonts' in self) && (options.useLocalFonts ?? true)
|
|
110
|
+
})
|
|
111
|
+
if (offscreenRender === true) this.sendMessage('offscreenCanvas', null, [this._canvasctrl])
|
|
111
112
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
113
|
+
this._boundResize = this.resize.bind(this)
|
|
114
|
+
this._boundTimeUpdate = this._timeupdate.bind(this)
|
|
115
|
+
this._boundSetRate = this.setRate.bind(this)
|
|
116
|
+
if (this._video) this.setVideo(options.video)
|
|
116
117
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
118
|
+
if (this._onDemandRender) {
|
|
119
|
+
this.busy = false
|
|
120
|
+
this._lastDemandTime = null
|
|
121
|
+
this._video?.requestVideoFrameCallback(this._handleRVFC.bind(this))
|
|
122
|
+
}
|
|
123
|
+
resolve()
|
|
121
124
|
}
|
|
122
|
-
}
|
|
125
|
+
})
|
|
123
126
|
}
|
|
124
127
|
|
|
125
128
|
// test support for WASM, ImageData, alphaBug, but only once, on init so it doesn't run when first running the page
|
|
@@ -595,7 +598,8 @@ export default class JASSUB extends EventTarget {
|
|
|
595
598
|
* @param {Object} [data] Data for function.
|
|
596
599
|
* @param {Transferable[]} [transferable] Array of transferables.
|
|
597
600
|
*/
|
|
598
|
-
sendMessage (target, data = {}, transferable) {
|
|
601
|
+
async sendMessage (target, data = {}, transferable) {
|
|
602
|
+
await this._ready
|
|
599
603
|
if (transferable) {
|
|
600
604
|
this._worker.postMessage({
|
|
601
605
|
target,
|