From 03f3c97721fa5cce42a96ca7f10fd6d9e57368f6 Mon Sep 17 00:00:00 2001 From: Alex Kanunnikov Date: Sun, 6 Aug 2023 13:38:19 +0300 Subject: [PATCH] support audio spectrogramm (#17) * support audio spectrogramm --- demo/index.js | 6 +- demo/index.ts | 13 +- dist/index.js | 6 +- dist/types/core.d.ts | 2 + dist/types/plugins/audio-peaks.d.ts | 45 ++++++ dist/types/plugins/base.d.ts | 1 + dist/types/plugins/index.d.ts | 8 +- package.json | 3 +- src/core.ts | 15 +- src/plugins/audio-peaks.ts | 213 ++++++++++++++++++++++++++++ src/plugins/base.ts | 3 + src/plugins/index.ts | 8 +- src/ui/mute-unmute-button.ts | 5 +- yarn.lock | 5 + 14 files changed, 309 insertions(+), 24 deletions(-) create mode 100644 dist/types/plugins/audio-peaks.d.ts create mode 100644 src/plugins/audio-peaks.ts diff --git a/demo/index.js b/demo/index.js index afddf93..07fa21d 100644 --- a/demo/index.js +++ b/demo/index.js @@ -1,4 +1,4 @@ -"use strict";(()=>{var Wt=Object.defineProperty,zt=Object.defineProperties;var Nt=Object.getOwnPropertyDescriptors;var ct=Object.getOwnPropertySymbols;var Ot=Object.prototype.hasOwnProperty,Ut=Object.prototype.propertyIsEnumerable;var dt=(o,n,t)=>n in o?Wt(o,n,{enumerable:!0,configurable:!0,writable:!0,value:t}):o[n]=t,x=(o,n)=>{for(var t in n||(n={}))Ot.call(n,t)&&dt(o,t,n[t]);if(ct)for(var t of ct(n))Ut.call(n,t)&&dt(o,t,n[t]);return o},w=(o,n)=>zt(o,Nt(n));var C=(o,n,t)=>new Promise((e,i)=>{var s=a=>{try{l(t.next(a))}catch(h){i(h)}},r=a=>{try{l(t.throw(a))}catch(h){i(h)}},l=a=>a.done?e(a.value):Promise.resolve(a.value).then(s,r);l((t=t.apply(o,n)).next())});var E=(o,n)=>{let t=o.target===document.body,e=n.uiContainer.contains(o.target),i=n.playerControlsContainer.contains(o.target),s=n.videoElement.contains(o.target),r=n.canvas.contains(o.target);return e||i||s||r||t};function A(o){return o.pointerType==="touch"&&o.isPrimary===!1}function mt(o,n){if(!E(o,n))return;let t=n.uiContainer.contains(o.target),e=n.playerControlsContainer.contains(o.target);if(t||e)return;let i=n.videoElement;i.tagName==="VIDEO"&&(i.paused||(n.currentTool=null,i.pause(),n.raf(()=>C(this,null,function*(){n.redrawFullCanvas()}))))}function ut(o,n){var t;E(o,n)&&(o.preventDefault(),o.stopPropagation(),o.stopImmediatePropagation(),(t=o.clipboardData)==null||t.setData("application/json",JSON.stringify(n.saveCurrentFrame())))}function pt(o,n){var e;if(!E(o,n))return;o.preventDefault(),o.stopPropagation(),o.stopImmediatePropagation();let t=n.saveCurrentFrame();n.replaceFrame(n.playbackFrame,[]),n.redrawFullCanvas(),(e=o.clipboardData)==null||e.setData("application/json",JSON.stringify(t))}function vt(o,n){if(!E(o,n))return;let t=n.videoElement;t.tagName==="VIDEO"&&(o.key==="ArrowLeft"||o.key==="ArrowRight"?(o.preventDefault(),o.stopPropagation(),o.stopImmediatePropagation(),o.key==="ArrowLeft"?n.prevFrame():o.key==="ArrowRight"&&n.nextFrame()):o.code==="Space"&&(o.preventDefault(),o.stopPropagation(),o.stopImmediatePropagation(),t.paused?t.play().then(()=>{n.redrawFullCanvas()}):(t.pause(),n.raf(()=>{n.redrawFullCanvas()}))))}function ft(o,n){var s,r,l,a,h;if(!E(o,n))return;let t=(r=(s=o.clipboardData)==null?void 0:s.types)!=null?r:[];if(t.includes("application/json"))o.preventDefault(),o.stopPropagation(),o.stopImmediatePropagation();else if(t.includes("Files")){let c=(l=o.clipboardData)==null?void 0:l.files;if(c&&c.length>0){let f=c[0];if(f.type.startsWith("image/")){o.preventDefault(),o.stopPropagation(),o.stopImmediatePropagation();let d=new Image;d.addEventListener("load",()=>{let p=d.naturalWidth/d.naturalHeight,u=.25,m=u/p*n.aspectRatio;n.addShapesToFrame(n.playbackFrame,[{type:"image",image:d,x:0,y:0,width:u,height:m,strokeStyle:"red",fillStyle:"red",lineWidth:2}]),n.redrawFullCanvas(),n.raf(()=>{n.show()}),n.currentTool="move"},{once:!0}),d.src=URL.createObjectURL(f),n.redrawFullCanvas()}}}else if(t.includes("text/plain")){let c=(a=o.clipboardData)==null?void 0:a.getData("text/plain");c&&(o.preventDefault(),o.stopPropagation(),o.stopImmediatePropagation(),n.addShapesToFrame(n.playbackFrame,[{type:"text",text:c,x:.4,y:.4,strokeStyle:n.ctx.strokeStyle,fillStyle:n.ctx.fillStyle,lineWidth:n.ctx.lineWidth}]),n.show(),n.currentTool="move",n.redrawFullCanvas())}else return;let e=(h=o.clipboardData)==null?void 0:h.getData("application/json");if(!e)return;let i=JSON.parse(e);i&&i.shapes&&i.version===1&&(n.addShapesToFrame(n.playbackFrame,i.shapes),n.redrawFullCanvas())}function gt(o,n){let t=document.createElement("button");t.type="button",t.style.margin="5px",t.style.float="right",t.title="Download current frame",t.innerHTML='',n.addEvent(t,"click",()=>{let e=n.frameToDataUrl();if(!e)return;let i=document.createElement("a");i.download=`frame_${String(n.activeTimeFrame).padStart(3,"0")}.png`,i.href=e,i.click()}),n.buttons.push(t),n.playerControlsContainer.appendChild(t)}var yt='',xt='';function wt(o,n){let t=document.createElement("button");t.type="button",t.style.margin="5px",o.muted||o.volume===0?t.innerHTML=xt:t.innerHTML=yt,n.addEvent(o,"volumechange",()=>{o.muted||o.volume===0?t.innerHTML=yt:t.innerHTML=xt}),n.addEvent(t,"click",()=>{o.muted&&(o.muted=!1),o.volume===0?o.volume=1:o.volume=0}),n.buttons.push(t),n.playerControlsContainer.appendChild(t)}var bt='',Yt='';function Tt(o,n){let t=document.createElement("button");t.type="button",t.innerHTML=bt,t.style.margin="5px",n.addEvent(o,"play",()=>{t.innerHTML=Yt}),n.addEvent(o,"pause",()=>{t.innerHTML=bt}),n.addEvent(t,"click",()=>{n.withRefVideo(e=>{e.paused&&e.play().then(()=>{n.showButton("compare")})}),o.paused?o.play().then(()=>{n.redrawFullCanvas()}):(o.pause(),n.raf(()=>{n.redrawFullCanvas()}))}),n.buttons.push(t),n.playerControlsContainer.appendChild(t)}function Ct(o){return` +"use strict";(()=>{var Kt=Object.create;var Z=Object.defineProperty,$t=Object.defineProperties,Gt=Object.getOwnPropertyDescriptor,Jt=Object.getOwnPropertyDescriptors,Qt=Object.getOwnPropertyNames,ut=Object.getOwnPropertySymbols,Zt=Object.getPrototypeOf,vt=Object.prototype.hasOwnProperty,te=Object.prototype.propertyIsEnumerable;var ft=Math.pow,pt=(o,n,t)=>n in o?Z(o,n,{enumerable:!0,configurable:!0,writable:!0,value:t}):o[n]=t,y=(o,n)=>{for(var t in n||(n={}))vt.call(n,t)&&pt(o,t,n[t]);if(ut)for(var t of ut(n))te.call(n,t)&&pt(o,t,n[t]);return o},w=(o,n)=>$t(o,Jt(n));var ee=(o,n)=>()=>(n||o((n={exports:{}}).exports,n),n.exports);var ie=(o,n,t,e)=>{if(n&&typeof n=="object"||typeof n=="function")for(let i of Qt(n))!vt.call(o,i)&&i!==t&&Z(o,i,{get:()=>n[i],enumerable:!(e=Gt(n,i))||e.enumerable});return o};var ne=(o,n,t)=>(t=o!=null?Kt(Zt(o)):{},ie(n||!o||!o.__esModule?Z(t,"default",{value:o,enumerable:!0}):t,o));var b=(o,n,t)=>new Promise((e,i)=>{var s=r=>{try{l(t.next(r))}catch(h){i(h)}},a=r=>{try{l(t.throw(r))}catch(h){i(h)}},l=r=>r.done?e(r.value):Promise.resolve(r.value).then(s,a);l((t=t.apply(o,n)).next())});var Rt=ee((Ui,Ht)=>{"use strict";function re(o){for(var n=1/0,t=-1/0,e=0,i=o.length,s;es&&(n=s),ti?i:(e+1)*n,r=o.subarray(a,l),u=re(r),d=Dt(u.min,t),h=Dt(u.max,t),c[e*2]=d,c[e*2+1]=h;return c}function Lt(o,n){return new(new Function(`return Int${o}Array`)())(n)}function le(o,n){var t=o.length,e=1/t,i=o[0].length/2,s=0,a=0,l,r,h=Lt(n,i*2);for(a=0;a1&&(l=le(l,s)),h=l[0].length/2,{length:h,data:l,bits:s}}});var E=(o,n)=>{let t=o.target===document.body,e=n.uiContainer.contains(o.target),i=n.playerControlsContainer.contains(o.target),s=n.videoElement.contains(o.target),a=n.canvas.contains(o.target);return e||i||s||a||t};function L(o){return o.pointerType==="touch"&&o.isPrimary===!1}function gt(o,n){if(!E(o,n))return;let t=n.uiContainer.contains(o.target),e=n.playerControlsContainer.contains(o.target);if(t||e)return;let i=n.videoElement;i.tagName==="VIDEO"&&(i.paused||(n.currentTool=null,i.pause(),n.raf(()=>b(this,null,function*(){n.redrawFullCanvas()}))))}function yt(o,n){var t;E(o,n)&&(o.preventDefault(),o.stopPropagation(),o.stopImmediatePropagation(),(t=o.clipboardData)==null||t.setData("application/json",JSON.stringify(n.saveCurrentFrame())))}function xt(o,n){var e;if(!E(o,n))return;o.preventDefault(),o.stopPropagation(),o.stopImmediatePropagation();let t=n.saveCurrentFrame();n.replaceFrame(n.playbackFrame,[]),n.redrawFullCanvas(),(e=o.clipboardData)==null||e.setData("application/json",JSON.stringify(t))}function wt(o,n){if(!E(o,n))return;let t=n.videoElement;t.tagName==="VIDEO"&&(o.key==="ArrowLeft"||o.key==="ArrowRight"?(o.preventDefault(),o.stopPropagation(),o.stopImmediatePropagation(),o.key==="ArrowLeft"?n.prevFrame():o.key==="ArrowRight"&&n.nextFrame()):o.code==="Space"&&(o.preventDefault(),o.stopPropagation(),o.stopImmediatePropagation(),t.paused?t.play().then(()=>{n.redrawFullCanvas()}):(t.pause(),n.raf(()=>{n.redrawFullCanvas()}))))}function bt(o,n){var s,a,l,r,h;if(!E(o,n))return;let t=(a=(s=o.clipboardData)==null?void 0:s.types)!=null?a:[];if(t.includes("application/json"))o.preventDefault(),o.stopPropagation(),o.stopImmediatePropagation();else if(t.includes("Files")){let d=(l=o.clipboardData)==null?void 0:l.files;if(d&&d.length>0){let u=d[0];if(u.type.startsWith("image/")){o.preventDefault(),o.stopPropagation(),o.stopImmediatePropagation();let c=new Image;c.addEventListener("load",()=>{let p=c.naturalWidth/c.naturalHeight,v=.25,m=v/p*n.aspectRatio;n.addShapesToFrame(n.playbackFrame,[{type:"image",image:c,x:0,y:0,width:v,height:m,strokeStyle:"red",fillStyle:"red",lineWidth:2}]),n.redrawFullCanvas(),n.raf(()=>{n.show()}),n.currentTool="move"},{once:!0}),c.src=URL.createObjectURL(u),n.redrawFullCanvas()}}}else if(t.includes("text/plain")){let d=(r=o.clipboardData)==null?void 0:r.getData("text/plain");d&&(o.preventDefault(),o.stopPropagation(),o.stopImmediatePropagation(),n.addShapesToFrame(n.playbackFrame,[{type:"text",text:d,x:.4,y:.4,strokeStyle:n.ctx.strokeStyle,fillStyle:n.ctx.fillStyle,lineWidth:n.ctx.lineWidth}]),n.show(),n.currentTool="move",n.redrawFullCanvas())}else return;let e=(h=o.clipboardData)==null?void 0:h.getData("application/json");if(!e)return;let i=JSON.parse(e);i&&i.shapes&&i.version===1&&(n.addShapesToFrame(n.playbackFrame,i.shapes),n.redrawFullCanvas())}function Tt(o,n){let t=document.createElement("button");t.type="button",t.style.margin="5px",t.style.float="right",t.title="Download current frame",t.innerHTML='',n.addEvent(t,"click",()=>{let e=n.frameToDataUrl();if(!e)return;let i=document.createElement("a");i.download=`frame_${String(n.activeTimeFrame).padStart(3,"0")}.png`,i.href=e,i.click()}),n.buttons.push(t),n.playerControlsContainer.appendChild(t)}var Ct='',St='';function Et(o,n){let t=document.createElement("button");t.type="button",t.style.margin="5px",o.muted||o.volume===0?t.innerHTML=Ct:t.innerHTML=St,n.addEvent(o,"volumechange",()=>{o.muted||o.volume===0?t.innerHTML=Ct:t.innerHTML=St}),n.addEvent(t,"click",()=>{if(o.muted){o.muted=!1;return}o.volume===0?o.volume=1:o.volume=0}),n.buttons.push(t),n.playerControlsContainer.appendChild(t)}var It='',oe='';function kt(o,n){let t=document.createElement("button");t.type="button",t.innerHTML=It,t.style.margin="5px",n.addEvent(o,"play",()=>{t.innerHTML=oe}),n.addEvent(o,"pause",()=>{t.innerHTML=It}),n.addEvent(t,"click",()=>{n.withRefVideo(e=>{e.paused&&e.play().then(()=>{n.showButton("compare")})}),o.paused?o.play().then(()=>{n.redrawFullCanvas()}):(o.pause(),n.raf(()=>{n.redrawFullCanvas()}))}),n.buttons.push(t),n.playerControlsContainer.appendChild(t)}function Ft(o){return` ${{"0.25":"\xBC","0.5":"\xBD","0.75":"\xBE",1:"1\xD7"}[String(o)]} - `}function St(o,n){let t=[.25,.5,.75,1],e=document.createElement("button"),i=t[t.length-1];e.type="button",o.playbackRate=i,e.innerHTML=Ct(i),e.style.margin="5px",n.addEvent(e,"click",()=>{let s=t.indexOf(o.playbackRate),r=s+1>=t.length?0:s+1;o.playbackRate=t[r],e.innerHTML=Ct(t[r])}),n.buttons.push(e),n.playerControlsContainer.appendChild(e)}var Xt="#F3CE32";function Et(){var c,f;let o=document.createElement("div");o.style.position="absolute",o.style.top="-40px",o.style.left="0",o.style.zIndex="2",(c=this.canvas.parentNode)==null||c.insertBefore(o,this.canvas);let n=document.createElement("div");n.style.position="relative",n.style.top="0",n.style.left="0",n.style.zIndex="2",(f=this.canvas.parentNode)==null||f.insertBefore(n,this.canvas.nextSibling),this.playerControlsContainer=n;let t=this.videoElement.tagName==="VIDEO"?this.videoElement:null;this.uiContainer=o;let e=(d,p,u=o)=>{let m=document.createElement("button");if(m.type="button",m.innerHTML=d,m.style.margin="5px",u.appendChild(m),this.buttons.push(m),typeof p=="function")this.addEvent(m,"click",p);else{m.dataset.tool=p;let v=()=>{this.currentTool===p?this.currentTool=null:this.currentTool=p};this.addEvent(m,"click",v)}return m},i=()=>{let d=document.createElement("div");return d.style.display="inline-flex",d.style.alignItems="center",d.style.margin="5px",o.appendChild(d),d};e('',"rectangle"),e('',"circle"),e('',"line"),e('',"curve"),e('',"arrow"),e('',"text"),e('',"eraser"),this.isMobile&&(this.hideButton("line"),this.hideButton("circle"),this.hideButton("rectangle"),this.hideButton("eraser")),e('',"move"),e('',"compare"),e('',()=>{this.handleUndo()}),t&&(e('',()=>{this.prevFrame()},this.playerControlsContainer),Tt(t,this),e('',()=>{this.nextFrame()},this.playerControlsContainer),wt(t,this),St(t,this),gt(t,this));let s=document.createElement("input");s.type="color",s.value=Xt,s.style.margin="5px",this.colorPicker=s,o.appendChild(s);let r=i(),l=document.createElement("input");l.type="number",l.step="1",l.min="1",l.max="10",l.value="5",l.style.margin="5px",r.appendChild(l);let a=d=>{this.ctx.lineWidth=d.target.valueAsNumber,this.focusOnMediaNode()};this.addEvent(l,"input",a);let h=d=>{this.ctx.strokeStyle=d.target.value,this.ctx.fillStyle=d.target.value,this.focusOnMediaNode()};this.addEvent(s,"input",h),this.colorPicker=s,this.strokeSizePicker=l,this.hideButton("compare"),t&&(this.hide(),this.addEvent(t,"pause",()=>{this.show()}),this.addEvent(t,"seek",()=>{t.paused&&this.show()}),this.addEvent(t,"timeupdate",()=>{t.currentTime<2e-4&&!t.paused&&this.startAnnotationsAsVideo()}),this.addEvent(t,"error",()=>{this.hide()}),this.addEvent(t,"stalled",()=>{this.hide()}),this.addEvent(t,"play",()=>{this.hideControls(),this.startAnnotationsAsVideo()}),this.addEvent(document,"copy",d=>{ut(d,this)}),this.addEvent(document,"cut",d=>{pt(d,this)}),this.addEvent(document,"paste",d=>{ft(d,this)}),this.addEvent(document,"click",d=>{mt(d,this)}),this.addEvent(document,"keydown",d=>{vt(d,this)}))}function It(){var o;this.canvas=document.createElement("canvas"),this.ctx=this.canvas.getContext("2d"),(o=this.videoElement.parentNode)==null||o.insertBefore(this.canvas,this.videoElement.nextSibling),this.canvas.style.position="absolute",this.canvas.style.backgroundColor="transparent",this.canvas.style.top="0",this.canvas.style.left="0",this.canvas.style.zIndex="1",this.addEvent(this.canvas,"pointerdown",this.handleMouseDown),this.addEvent(this.canvas,"pointermove",this.handleMouseMove),this.addEvent(this.canvas,"pointerup",this.handleMouseUp),this.addEvent(this.canvas,"pointercancel",this.handleMouseUp),this.addEvent(window,"resize",this.setCanvasSize),this.addEvent(document,"keydown",this.onKeyDown)}var H=class{constructor(){this.destructors=[];this.isDestroyed=!1;this.activeTimeFrame=1;this.globalShapes=[];this.timeStack=new Map;this.undoTimeStack=new Map}cleanFrameStacks(){this.timeStack.clear(),this.undoTimeStack.clear()}destroy(){this.destructors.forEach(n=>n()),this.destructors=[],this.globalShapes=[],this.cleanFrameStacks()}raf(n){return requestAnimationFrame(n)}addEvent(n,t,e){let i=s=>{this.isDestroyed||e(s)};n.addEventListener(t,i),this.destructors.push(()=>{n.removeEventListener(t,i)})}addProgressBarOverlay(){throw new Error("Method not implemented.")}initUI(){throw new Error("Method not implemented.")}initCanvas(){throw new Error("Method not implemented.")}addFrameSquareOverlay(n=this.activeTimeFrame){throw new Error("Method not implemented.")}addVideoOverlay(){throw new Error("Method not implemented.")}withRefVideo(n){this.isDestroyed||this.referenceVideoElement&&n(this.referenceVideoElement)}withVideo(n){if(this.isDestroyed)return;let t=this.videoElement;!t||t.tagName!=="VIDEO"||n(t)}};var g=class{constructor(n){this.startX=0;this.startY=0;this.isDrawing=!1;this.annotationTool=n}get ctx(){return this.annotationTool.ctx}onDeactivate(){}onActivate(){}reset(){this.startX=0,this.startY=0,this.isDrawing=!1}save(n){this.annotationTool.addShape(n)}};var R=class extends g{constructor(){super(...arguments);this.name="rectangle"}move(t,e,i){return t.x+=e,t.y+=i,t}normalize(t,e,i){return w(x({},t),{x:t.x/e,y:t.y/i,width:t.width/e,height:t.height/i})}onPointerDown(t){let{x:e,y:i}=this.annotationTool.getRelativeCoords(t);this.startX=e,this.startY=i,this.isDrawing=!0}onPointerMove(t){if(!this.isDrawing)return;let{x:e,y:i}=this.annotationTool.getRelativeCoords(t);this.drawRectangle(this.startX,this.startY,e-this.startX,i-this.startY)}onPointerUp(t){if(!this.isDrawing)return;let{x:e,y:i}=this.annotationTool.getRelativeCoords(t);this.save({type:"rectangle",x:this.startX,y:this.startY,width:e-this.startX,height:i-this.startY,strokeStyle:this.ctx.strokeStyle,fillStyle:this.ctx.fillStyle,lineWidth:this.ctx.lineWidth}),this.drawRectangle(this.startX,this.startY,e-this.startX,i-this.startY),this.isDrawing=!1}drawRectangle(t,e,i,s){this.ctx.beginPath(),this.ctx.rect(t,e,i,s),this.ctx.stroke()}draw(t){this.drawRectangle(t.x,t.y,t.width,t.height)}};var V=class extends g{constructor(){super(...arguments);this.name="circle"}move(t,e,i){return t.x+=e,t.y+=i,t}normalize(t,e,i){return w(x({},t),{x:t.x/e,y:t.y/i,radius:t.radius/e})}onPointerDown(t){let{x:e,y:i}=this.annotationTool.getRelativeCoords(t);this.startX=e,this.startY=i,this.isDrawing=!0}onPointerMove(t){if(!this.isDrawing)return;let{x:e,y:i}=this.annotationTool.getRelativeCoords(t),s=Math.sqrt(Math.pow(e-this.startX,2)+Math.pow(i-this.startY,2));this.drawCircle(this.startX,this.startY,s)}onPointerUp(t){if(!this.isDrawing)return;let{x:e,y:i}=this.annotationTool.getRelativeCoords(t),s=Math.sqrt(Math.pow(e-this.startX,2)+Math.pow(i-this.startY,2));this.save({type:"circle",x:this.startX,y:this.startY,radius:s,strokeStyle:this.ctx.strokeStyle,fillStyle:this.ctx.fillStyle,lineWidth:this.ctx.lineWidth}),this.drawCircle(this.startX,this.startY,s),this.isDrawing=!1}drawCircle(t,e,i){this.ctx.beginPath(),this.ctx.arc(t,e,i,0,2*Math.PI),this.ctx.stroke()}draw(t){this.drawCircle(t.x,t.y,t.radius)}};var W=class{constructor(n,t){this.x=n;this.y=t}distanceToLine(n,t){let e=t.x-n.x,i=t.y-n.y,s=Math.abs(i*this.x-e*this.y+t.x*n.y-t.y*n.x),r=Math.sqrt(i*i+e*e);return s/r}};function z(o,n){if(o.length<=2)return o;let t=o[0],e=o[o.length-1],i=-1,s=0;for(let r=1;rs&&(i=r,s=l)}if(s>n){let r=z(o.slice(0,i+1),n),l=z(o.slice(i),n);return r.slice(0,r.length-1).concat(l)}else return[t,e]}var N=class extends g{constructor(){super(...arguments);this.name="curve";this.curvePoints=[]}move(t,e,i){return t.points=t.points.map(s=>({x:s.x+e,y:s.y+i})),t}normalize(t,e,i){return w(x({},t),{points:t.points.map(s=>({x:s.x/e,y:s.y/i}))})}draw(t){this.drawCurve(t)}reset(){super.reset(),this.curvePoints=[]}onPointerDown(t){if(this.isDrawing)return;let{x:e,y:i}=this.annotationTool.getRelativeCoords(t);this.curvePoints=[],this.startX=e,this.startY=i,this.isDrawing=!0,this.curvePoints.push({x:e,y:i})}onPointerMove(t){if(!this.isDrawing)return;let{x:e,y:i}=this.annotationTool.getRelativeCoords(t);this.curvePoints.push({x:e,y:i}),this.drawCurve({points:this.curvePoints,lineWidth:this.ctx.lineWidth})}onPointerUp(t){if(!this.isDrawing)return;let{x:e,y:i}=this.annotationTool.getRelativeCoords(t);this.curvePoints.push({x:e,y:i});let s=this.curvePoints.map(c=>new W(c.x,c.y)),h={type:"curve",points:z(s,2).map(c=>({x:c.x,y:c.y})),strokeStyle:this.ctx.strokeStyle,fillStyle:this.ctx.fillStyle,lineWidth:this.ctx.lineWidth};this.save(h),this.curvePoints=[],this.isDrawing=!1}drawCurve(t){if(t.points.length===2&&t.points[0].x===t.points[1].x&&t.points[0].y===t.points[1].y){let e=t.lineWidth/4,i=0,s=2*Math.PI;this.ctx.beginPath(),this.ctx.arc(t.points[0].x,t.points[0].y,e,i,s),this.ctx.stroke()}else{this.ctx.beginPath(),this.ctx.moveTo(t.points[0].x,t.points[0].y);for(let e=1;e0){let s=this.annotationTool.globalShapes[0];if(s.type==="compare"){let r=this.annotationTool.deserialize([s])[0];this.draw(r),this.annotationTool.addFrameSquareOverlay()}}return}let{x:e}=this.annotationTool.getRelativeCoords(t);this.comparisonLine=e;let i={type:"compare",strokeStyle:this.ctx.strokeStyle,fillStyle:this.ctx.fillStyle,lineWidth:this.ctx.lineWidth,x:e};this.draw(i),this.drawDelimiter(i)}onPointerUp(){this.isDrawing&&(this.save({type:"compare",strokeStyle:this.ctx.strokeStyle,fillStyle:this.ctx.fillStyle,lineWidth:this.ctx.lineWidth,disabled:!1,x:this.comparisonLine}),this.isDrawing=!1)}removePreviousCompare(){this.annotationTool.globalShapes=this.annotationTool.globalShapes.filter(t=>t.type!=="compare")}disablePreviousCompare(){this.annotationTool.globalShapes=this.annotationTool.globalShapes.map(t=>t.type==="compare"?w(x({},t),{disabled:!0}):t)}save(t){this.removePreviousCompare();let e=this.annotationTool.serialize([t])[0];e.x<.05||e.x>.95||this.annotationTool.addGlobalShape(e)}drawDelimiter(t){this.ctx.beginPath(),this.ctx.moveTo(t.x,0),this.ctx.lineTo(t.x,this.annotationTool.canvasWidth),this.ctx.stroke()}drawShape(t){var it,nt,ot,st,rt,at,lt,ht;let e=this.annotationTool.videoElement,i=this.annotationTool.referenceVideoElement;if(!e||!i)return;let s=this.ctx.globalAlpha,r=this.annotationTool.canvasWidth,l=this.annotationTool.canvasHeight,a=t.x,h=i.videoHeight-e.videoHeight,c=i.videoWidth-e.videoWidth,f=this.annotationTool.isMobile;this.ctx.globalAlpha=this.leftOpacity;let d=(nt=(it=this.annotationTool.referenceVideoFrameBuffer)==null?void 0:it.frameNumberFromTime(e.currentTime))!=null?nt:1,p=d;if(c>e.videoWidth&&h>e.videoHeight&&!this.annotationTool.isMobile){let S=(at=(rt=this.annotationTool.referenceVideoFrameBuffer)==null?void 0:rt.getFrameNumberBySignature((st=(ot=this.annotationTool.videoFrameBuffer)==null?void 0:ot.getHistogram(d))!=null?st:null,d))!=null?at:d,B=Math.abs(d-S);B>=1&&B<=3&&(p=S)}let m=(lt=this.annotationTool.referenceVideoFrameBuffer)==null?void 0:lt.getFrame(p),v=(ht=this.annotationTool.videoFrameBuffer)==null?void 0:ht.getFrame(d);if(f){this.ctx.imageSmoothingQuality="low";let S=a/r,B=a;this.ctx.drawImage(v!=null?v:e,0,0,S*e.videoWidth,e.videoHeight,0,0,B,l)}else{let S=v?v.width:e.videoWidth,B=v?v.height:e.videoHeight;this.ctx.drawImage(v!=null?v:e,0,0,S,B,0,0,r,l)}this.ctx.globalAlpha=this.rightOpacity;let y=0,b=0,P=e.videoWidth/e.videoHeight,Z=i.videoWidth/i.videoHeight,_=Math.abs(P-Z)>.1,M=10,tt=Math.abs(h)>M,L=e.videoWidth,$=e.videoHeight,F=0;if(c<-M)if(_){let S=e.videoWidth/r;F=Math.abs(c/2),F=F/S,F<=M&&(F=0)}else L=i.videoWidth;else c>M&&(L=i.videoWidth);if(h===0)y=0;else if(h>0)_?(y=h/2,y<=M&&(y=0)):$=tt?i.videoHeight:e.videoHeight;else if(!_)$=tt?i.videoHeight:e.videoHeight;else{b=Math.abs(h/2);let S=e.videoHeight/l;b=b/S,b<=M&&(b=0)}let G=a-F,et=r-G,Vt=et/r*L;m?(f&&(this.ctx.imageSmoothingQuality="low"),this.ctx.drawImage(m,G/r*L,y,Vt,$,G+F,b,et,l)):console.log("no video data",d),this.ctx.globalAlpha=s}draw(t){if(t.disabled)return;let e=this.annotationTool.videoElement,i=this.annotationTool.referenceVideoElement;!e||!i||this.drawShape(t)}};var Ft=[R,V,O,U,Y,X,N,j,q,K];function kt(o,n){let t,e,i,s=[],r=!0;function l(c,f){let d=Math.abs(f.mediaTime-t),p=Math.abs(f.presentedFrames-e),u=d/p;u&&u<1&&r&&s.length<50&&o.playbackRate===1&&document.hasFocus()&&(s.push(u),i=Math.round(1/h()),n(i,s.length*2)),r=!0,t=f.mediaTime,e=f.presentedFrames,o.requestVideoFrameCallback(l)}o.requestVideoFrameCallback(l);let a=()=>{s.pop(),r=!1};o.addEventListener("seeked",a);function h(){return s.reduce((c,f)=>c+f)/s.length}return()=>{o.removeEventListener("seeked",a)}}function Pt(o,n,t){return .299*o+.587*n+.114*t}var qt=0,Q=class extends Array{constructor(){super(...arguments);this.id=qt++}};function Mt(o){let n=o.width,t=o.height,e=new Array(n*t),i=new Q,s=0;for(let r=0;rMath.max(o.id,n.id)+"-"+Math.min(o.id,n.id);function Bt(o,n){let t=Kt(o,n);if(J.has(t))return J.get(t);let e=0;for(let s=0;sn.close()),this.frames.clear()}tick(n,t){if(this.setCanvasSize(),t.expectedDisplayTime-performance.now()>10&&console.log("looks like frame is not yet rendered"),this.isDestroyed)return!1;if(this.seenFrames>=this.totalFrames){if(this.autoHide)try{this.video.paused||this.video.pause(),this.video.style.display="none"}catch(l){}return!1}if(this.video.videoWidth===0||this.video.videoHeight===0)return!0;let i=this.video,s=this.frameNumberFromTime(t.mediaTime);if(!Math.max(1,t.presentedFrames>this.totalFrames?t.presentedFrames%this.totalFrames:t.presentedFrames))throw new Error("expectedFrame is 0");if(this.hasFrame(s))this.seenFrames++;else{this.ctx.drawImage(i,0,0,this.width,this.height,0,0,this.width,this.height);let l=this.ctx.getImageData(0,0,this.canvas.width,this.canvas.height);createImageBitmap(l,0,0,this.width,this.height).then(a=>C(this,null,function*(){this.setFrame(s,a),this.isMobile||this.setHistogram(s,this.toHistogram(a))}))}return!0}addRequestFrameCallback(){this.isDestroyed||this.video.requestVideoFrameCallback((n,t)=>{this.tick(n,t)&&this.addRequestFrameCallback()})}createCanvas(){this.canvas=document.createElement("canvas"),this.ctx=this.canvas.getContext("2d",{willReadFrequently:!0,alpha:!1})}setCanvasSize(){this.isCanvasSizeSet||(this.canvas.width=this.video.videoWidth,this.canvas.height=this.video.videoHeight,this.isCanvasSizeSet=!0)}get width(){return this.video.videoWidth}get height(){return this.video.videoHeight}hasFrame(n){return this.frames.has(n)}getFrame(n){return this.frames.has(n)?this.frames.get(n):null}getFrameNumberBySignature(n,t){if(!n)return t;let e=0,i=t;return[t-3,t-2,t-1,t,t+1,t+2,t+3].filter(r=>r>0&&r<=this.totalFrames).forEach(r=>{let l=this.getHistogram(r);if(l){let a=Bt(n,l);a>e&&(e=a,i=r)}}),i}setFrame(n,t){this.frames.set(n,t)}setHistogram(n,t){this.histograms.set(n,t)}getHistogram(n){var t;return(t=this.histograms.get(n))!=null?t:null}get totalFrames(){return Math.round(this.video.duration*this.fps)}frameNumberFromTime(n){return Math.max(1,Math.round(n*this.fps))}};var _t=window.devicePixelRatio||1,Dt=25,I=class extends H{constructor(t){super();this.referenceVideoFrameBuffer=null;this.videoFrameBuffer=null;this.isMouseDown=!1;this.buttons=[];this.plugins=[];this.annotatedFrameCoordinates=[];this.fps=Dt;this.plannedFn=null;this.ct=0;this.isCanvasInitialized=!1;this.enforcedCanvasSize=null;this.lastNavigatedFrame=0;this.isProgressBarNavigation=!1;this.isAnnotationsAsVideoActive=!1;this.plugins=Ft.map(e=>new e(this)),this.init(t)}prevFrame(){let t=this.playbackFrame,e=Math.max(1,t-1);e===this.playbackFrame?this.playbackFrame=this.totalFrames-1:this.playbackFrame=e}nextFrame(){let t=this.playbackFrame,e=Math.min(this.totalFrames,t+1);e===this.totalFrames?this.playbackFrame=1:this.playbackFrame=e}addGlobalShape(t){this.globalShapes.push(t)}get selectedColor(){return this.colorPicker.value}get selectedStrokeSize(){return this.strokeSizePicker.valueAsNumber}get currentTool(){return this._currentTool}set currentTool(t){let e=this._currentTool;e&&(this.getButtonForTool(e).classList.remove("active"),this.pluginForTool(e).onDeactivate()),this._currentTool=t,this.canvas.style.cursor=t?"pointer":"default",t&&(this.getButtonForTool(t).classList.add("active"),this.pluginForTool(t).onActivate())}enableFrameRateDetection(){if(this.destructors.find(i=>i.name==="frameRateDetector"))return;let t=this.videoElement;if(t.tagName==="IMG")return;let e=kt(t,i=>{this.fps=i});Object.defineProperty(e,"name",{value:"frameRateDetector"}),this.destructors.push(e)}timeToFrame(t){return Math.max(1,Math.round(t*this.fps))}get playbackFrame(){return this.videoElement instanceof HTMLImageElement?1:this.timeToFrame(this.videoElement.currentTime)}set playbackFrame(t){if(this.videoElement instanceof HTMLImageElement)return;let e=t/this.fps;this.videoElement.currentTime=e,this.rvf(()=>{this.show()})}rvf(t){this.plannedFn=t}get canvasWidth(){var t,e;return(e=(t=this.enforcedCanvasSize)==null?void 0:t.width)!=null?e:0}get canvasHeight(){var t,e;return(e=(t=this.enforcedCanvasSize)==null?void 0:t.height)!=null?e:0}get aspectRatio(){return this.canvasWidth/this.canvasHeight}get isMobile(){return window.innerWidth<960}get progressBarCoordinates(){let t=this.isMobile?30:10,e=5,i=55,s=this.canvasWidth-e-i,r=e,l=this.canvasHeight-t;return{x:r,y:l,width:s,height:t}}get shapes(){return this.timeStack.has(this.activeTimeFrame)||this.timeStack.set(this.activeTimeFrame,[]),this.timeStack.get(this.activeTimeFrame)}set shapes(t){this.timeStack.set(this.activeTimeFrame,t)}get undoStack(){return this.undoTimeStack.has(this.activeTimeFrame)||this.undoTimeStack.set(this.activeTimeFrame,[]),this.undoTimeStack.get(this.activeTimeFrame)}set undoStack(t){this.undoTimeStack.set(this.activeTimeFrame,t)}get pixelRatio(){return _t}setVideoUrl(i){return C(this,arguments,function*(t,e=this.fps){if(this.videoElement instanceof HTMLImageElement)return;let s=this.videoElement;s.src=t,yield this.videoElement.load(),this.setFrameRate(e),this.videoFrameBuffer&&(this.videoFrameBuffer.destroy(),this.videoFrameBuffer=new k(s,e,!1),this.videoFrameBuffer.isMobile=this.isMobile),this.setCanvasSize()})}enableVideoFrameBuffer(){this.videoElement instanceof HTMLImageElement||(this.videoFrameBuffer=new k(this.videoElement,this.fps,!1),this.videoFrameBuffer.isMobile=this.isMobile)}hide(){this.stopAnnotationsAsVideo(),this.hideControls(),this.hideCanvas()}showControls(){this.uiContainer.style.display="block"}hideControls(){this.uiContainer.style.display="none"}showCanvas(){this.canvas.style.display="block"}hideCanvas(){this.canvas.style.display="none"}updateActiveTimeFrame(t=void 0){this.activeTimeFrame=t?this.timeToFrame(t):this.playbackFrame}show(){this.stopAnnotationsAsVideo(),this.updateActiveTimeFrame(),this.showCanvas(),this.showControls(),this.redrawFullCanvas()}setCanvasSettings(){this.ctx.strokeStyle=this.selectedColor,this.ctx.fillStyle=this.selectedColor,this.ctx.lineWidth=this.selectedStrokeSize}pluginForTool(t){if(this.isDestroyed)throw new Error("AnnotationTool is destroyed");let e=this.plugins.find(i=>i.name===t);if(!e)throw new Error(`No plugin found for tool ${t}`);return e}getButtonForTool(t){return this.buttons.find(e=>e.dataset.tool===t)}bindContext(){this.handleMouseDown=this.handleMouseDown.bind(this),this.handleMouseMove=this.handleMouseMove.bind(this),this.handleMouseUp=this.handleMouseUp.bind(this),this.setCanvasSize=this.setCanvasSize.bind(this),this.onKeyDown=this.onKeyDown.bind(this)}initProperties(){this.isDestroyed=!1,this.isProgressBarNavigation=!1,this.shapes=[],this.globalShapes=[],this.currentTool=this.isMobile?null:"curve"}setVideoStyles(){this.videoElement.style.objectFit="cover",this.videoElement.style.objectPosition="left top"}get frameCallbackSupported(){return"requestVideoFrameCallback"in HTMLVideoElement.prototype}initFrameCounter(){if(!this.frameCallbackSupported){setTimeout(()=>{var t;(t=this.plannedFn)==null||t.call(this),this.plannedFn=null,this.initFrameCounter(),this.updateActiveTimeFrame(),this.playAnnotationsAsVideo()},1e3/this.fps);return}this.withVideo(t=>{t.requestVideoFrameCallback((e,i)=>{var s,r;this.isCanvasInitialized||this._setCanvasSize(),(s=this.videoFrameBuffer)==null||s.tick(e,i),(r=this.plannedFn)==null||r.call(this),this.plannedFn=null,this.raf(()=>{this.initFrameCounter(),this.updateActiveTimeFrame(i.mediaTime),this.playAnnotationsAsVideo()})})})}init(t){this.videoElement=t,this.setVideoStyles(),this.initFrameCounter(),this.bindContext(),this.initCanvas(),this.initUI(),this.initProperties(),this.setCanvasSize()}onKeyDown(t){(t.ctrlKey||t.metaKey)&&t.key.toLowerCase()==="z"&&this.handleUndo()}removeLastShape(){this.shapes.pop(),this.redrawFullCanvas()}handleUndo(){this.undoStack.length>0&&(this.shapes=this.undoStack.pop(),this.redrawFullCanvas())}destroy(){var s,r,l,a,h,c,f,d;if(this.isDestroyed)return;super.destroy(),this.stopAnnotationsAsVideo(),this._currentTool=null,this.plugins.forEach(p=>p.reset()),this.annotatedFrameCoordinates=[],this.setFrameRate(Dt);let t=this.strokeSizePicker.parentElement;if((s=t==null?void 0:t.parentNode)==null||s.removeChild(t),this.referenceVideoElement){let p=this.referenceVideoElement.parentElement;(r=p==null?void 0:p.parentNode)==null||r.removeChild(p),this.referenceVideoElement=null}let e=this.colorPicker.parentElement;(l=e==null?void 0:e.parentNode)==null||l.removeChild(e),this.buttons.forEach(p=>{var u;(u=p.parentNode)==null||u.removeChild(p)}),this.buttons=[],(a=this.uiContainer.parentNode)==null||a.removeChild(this.uiContainer),(h=this.canvas.parentNode)==null||h.removeChild(this.canvas),(c=this.playerControlsContainer.parentElement)==null||c.removeChild(this.playerControlsContainer),["strokeSizePicker","colorPicker","uiContainer","playerControlsContainer","canvas","ctx","videoElement"].forEach(p=>{delete this[p]}),this.activeTimeFrame=0,this.isDestroyed=!0,(f=this.referenceVideoFrameBuffer)==null||f.destroy(),this.referenceVideoFrameBuffer=null,(d=this.videoFrameBuffer)==null||d.destroy(),this.videoFrameBuffer=null}_setCanvasSize(){let t=getComputedStyle(this.videoElement),e=parseInt(t.width,10),i=this.videoElement,s=i.videoWidth/i.videoHeight;if(isNaN(e)||!i.videoWidth||!i.videoHeight)return this.isCanvasInitialized=!1,this.setCanvasSettings(),!1;let r=Math.min(e,i.videoWidth),l=Math.floor(r/s);return i.style.width=`${r}px`,i.style.height=`${l}px`,this.isCanvasInitialized=i.videoWidth>0&&i.videoHeight>0,this.canvas.width=r*this.pixelRatio,this.canvas.height=l*this.pixelRatio,this.canvas.style.width=`${r}px`,this.canvas.style.height=`${l}px`,this.enforcedCanvasSize={width:r,height:l},this.ctx.scale(this.pixelRatio,this.pixelRatio),this.setCanvasSettings(),!0}setCanvasSize(){this._setCanvasSize()&&(this.syncVideoSizes(),this.redrawFullCanvas())}addShape(t){let e=this.serialize([t])[0];this.undoStack.push([...this.shapes]),this.shapes.push(e)}get msPerFrame(){return this.fps/1e3}syncVideoSizes(){this.withRefVideo(t=>{let i=this.videoElement.getBoundingClientRect();t.style.position="fixed",t.style.top=`${i.top}px`,t.style.left=`${i.left}px`})}addReferenceVideoByURL(s){return C(this,arguments,function*(t,e=this.fps,i="video/mp4"){var h;let r=yield fetch(t).then(c=>c.blob()),l=new Blob([r],{type:i}),a=window.URL.createObjectURL(l);this.referenceVideoElement?((h=this.referenceVideoFrameBuffer)==null||h.destroy(),this.referenceVideoFrameBuffer=new k(this.referenceVideoElement,e),this.referenceVideoFrameBuffer.isMobile=this.isMobile,this.referenceVideoFrameBuffer.start()):(this.referenceVideoElement=document.createElement("video"),this.withRefVideo(c=>{this.isMobile?(c.style.zIndex="2",c.style.display="block",c.style.top="0",c.style.left="0",c.style.opacity="0.25",c.style.width="20px",c.style.height="15px"):(c.style.zIndex="-1",c.style.display="none",c.style.width="100px",c.style.height="70px"),c.style.objectFit="cover",c.style.objectPosition="left top",c.muted=!0,c.volume=0,c.playsInline=!0,c.autoplay=!1,c.controls=!1,c.loop=!0,this.videoElement.after(c),this.referenceVideoFrameBuffer=new k(c,e),this.referenceVideoFrameBuffer.isMobile=this.isMobile,this.referenceVideoFrameBuffer.start()}),this.syncVideoSizes()),this.referenceVideoElement.src=a,this.referenceVideoElement.play().then(()=>{this.showButton("compare")}).catch(()=>{this.hideButton("compare")})})}hideButton(t){let e=this.getButtonForTool(t);e.style.display="none"}showButton(t){let e=this.getButtonForTool(t);e.style.display=""}addSingletonShape(t){let e=this.serialize([t])[0],i=this.shapes.filter(s=>s.type!==t.type);this.replaceFrame(this.playbackFrame,[...i,e])}serialize(t=this.shapes){let e=this.canvasWidth,i=this.canvasHeight;return t.map(s=>this.pluginForTool(s.type).normalize(s,e,i))}deserialize(t){let e=1/this.canvasWidth,i=1/this.canvasHeight;return t.map(s=>this.pluginForTool(s.type).normalize(s,e,i))}getRelativeCoords(t){let e=this.canvas.getBoundingClientRect();return{x:this.getEventX(t)-e.left,y:this.getEventY(t)-e.top}}handleMouseDown(t){if(t.preventDefault(),this.isMouseDown=!0,A(t))return;let e=this.frameFromProgressBar(t,!0);if(e){this.isProgressBarNavigation=!0;let i=this.getAnnotationFrame(t);this.isVideoPaused&&(i!==null?this.playbackFrame=i:this.playbackFrame=e);return}this.currentTool&&this.pluginForTool(this.currentTool).onPointerDown(t)}get isDrawing(){return this.currentTool?this.pluginForTool(this.currentTool).isDrawing:!1}get isVideoPaused(){return this.videoElement.tagName==="VIDEO"?this.videoElement.paused:!0}get hasGlobalOverlays(){return this.globalShapes.length>0}handleMouseMove(t){if(t.preventDefault(),!A(t)){if(this.isMouseDown){let e=this.isProgressBarNavigation?this.frameFromProgressBar(t,!1):null;if(e!==null&&!this.isDrawing){if(e===this.lastNavigatedFrame)return;this.lastNavigatedFrame=e,this.isVideoPaused&&(this.playbackFrame=e);return}else this.hideControls(),this.clearCanvas(),this.hasGlobalOverlays||this.addVideoOverlay(),this.drawShapesOverlay()}else this.redrawFullCanvas();this.currentTool&&this.pluginForTool(this.currentTool).onPointerMove(t)}}getEventX(t){return t.clientX}getEventY(t){return t.clientY}handleMouseUp(t){this.isMouseDown=!1,this.isProgressBarNavigation=!1,this.showControls(),!A(t)&&(this.currentTool&&this.pluginForTool(this.currentTool).onPointerUp(t),this.redrawFullCanvas())}focusOnMediaNode(){this.videoElement.focus()}drawShapesOverlay(){let t={strokeStyle:this.ctx.strokeStyle,fillStyle:this.ctx.fillStyle,lineWidth:this.ctx.lineWidth};for(let e of this.deserialize(this.globalShapes)){this.ctx.strokeStyle=e.strokeStyle,this.ctx.fillStyle=e.fillStyle,this.ctx.lineWidth=e.lineWidth;try{this.pluginForTool(e.type).draw(e)}catch(i){console.error(i)}}for(let e of this.deserialize(this.shapes)){this.ctx.strokeStyle=e.strokeStyle,this.ctx.fillStyle=e.fillStyle,this.ctx.lineWidth=e.lineWidth;try{this.pluginForTool(e.type).draw(e)}catch(i){console.error(i)}}this.ctx.strokeStyle=t.strokeStyle,this.ctx.fillStyle=t.fillStyle,this.ctx.lineWidth=t.lineWidth}clearCanvas(){this.ctx.clearRect(0,0,this.canvasWidth,this.canvasHeight)}frameToDataUrl(){try{this.clearCanvas(),this.addVideoOverlay(),this.addFrameSquareOverlay(),this.drawShapesOverlay();let t=this.canvas.toDataURL("image/png");return this.redrawFullCanvas(),t}catch(t){return console.error(t),null}}redrawFullCanvas(){this.hasGlobalOverlays||(this.clearCanvas(),this.addVideoOverlay()),this.drawShapesOverlay(),this.addFrameSquareOverlay(),this.addProgressBarOverlay()}replaceFrame(t,e){this.timeStack.set(t,this.parseShapes(this.stringifyShapes(e)))}addShapesToFrame(t,e){let i=this.timeStack.get(t)||[];this.timeStack.set(t,[...i,...this.parseShapes(this.stringifyShapes(e))])}setFrameRate(t){var e;(e=this.destructors.find(i=>i.name==="frameRateDetector"))==null||e(),this.fps=t}stringifyShapes(t){return JSON.stringify(t,(e,i)=>e==="image"?i.src:i)}parseShapes(t){return JSON.parse(t,(e,i)=>{if(e==="image"){let s=new Image;return s.src=i,s}return i})}filterNonSerializableShapes(t){return t.filter(e=>e.type!=="image")}saveCurrentFrame(){return{frame:this.playbackFrame,version:1,fps:this.fps,shapes:this.parseShapes(this.stringifyShapes(this.filterNonSerializableShapes(this.shapes)))}}loadAllFrames(t){this.cleanFrameStacks(),t.forEach(e=>{this.timeStack.set(e.frame,e.shapes)})}appendFrames(t){t.forEach(e=>{this.addShapesToFrame(e.frame,e.shapes)})}saveAllFrames(){return Array.from(this.timeStack.keys()).filter(s=>{var r;return(r=this.timeStack.get(s))==null?void 0:r.length}).map(s=>{var r;return{frame:s,fps:this.fps,version:1,shapes:this.filterNonSerializableShapes((r=this.timeStack.get(s))!=null?r:[])}})}getAnnotationFrame(t){var l,a;let e=t.offsetX,i=t.offsetY,s=this.isMobile?10:5;return(a=(l=this.annotatedFrameCoordinates.find(h=>e>=h.x-s&&e<=h.x+s&&i>=h.y-s&&i<=h.y+s))==null?void 0:l.frame)!=null?a:null}get totalFrames(){let t=this.videoElement;return t.tagName!=="VIDEO"?1:Math.ceil(t.duration*this.fps)}frameFromProgressBar(t,e=!0){let i=this.videoElement;if(i.tagName!=="VIDEO")return null;let{x:s,width:r,height:l,y:a}=this.progressBarCoordinates,h=t.offsetX,c=t.offsetY;return e?h>=s&&h<=s+r&&c>=a&&c<=a+l?Math.ceil((h-s)/r*(i.duration*this.fps)):null:h>=s&&h<=s+r?Math.ceil((h-s)/r*(i.duration*this.fps)):null}hasAnnotationsForFrame(t){if(this.globalShapes.length>0)return!0;if(this.timeStack.has(t)){let e=this.timeStack.get(t);return e&&e.length>0}return!1}stopAnnotationsAsVideo(){this.isAnnotationsAsVideoActive=!1}startAnnotationsAsVideo(){this.isAnnotationsAsVideoActive=!0,this.playAnnotationsAsVideo()}playAnnotationsAsVideo(){this.isAnnotationsAsVideoActive&&(this.hasGlobalOverlays||this.clearCanvas(),this.isMobile?this.hasGlobalOverlays||this.addVideoOverlay():this.addVideoOverlay(),this.drawShapesOverlay(),this.addFrameSquareOverlay(),this.addProgressBarOverlay())}};function Lt(o=this.activeTimeFrame){this.ctx.save(),this.ctx.fillStyle="rgba(0, 0, 0, 0.5)";let n=50,t=30,e=20;this.ctx.fillRect(this.canvasWidth-n,this.canvasHeight-t,n,t),this.ctx.fillStyle="white",this.ctx.font=`${e}px sans-serif`,this.ctx.fillText(`${o}`.padStart(3,"0"),this.canvasWidth-40,this.canvasHeight-7),this.ctx.restore()}function At(){var s,r,l;let o=this.videoElement;if(o.tagName!=="VIDEO")return;let n=(s=this.videoFrameBuffer)==null?void 0:s.frameNumberFromTime(o.currentTime),t=(l=(r=this.videoFrameBuffer)==null?void 0:r.getFrame(n||0))!=null?l:o,e=t?t.width:o.videoWidth,i=t?t.height:o.videoHeight;this.ctx.drawImage(t,0,0,e,i,0,0,this.canvasWidth,this.canvasHeight)}function Ht(){let o=this.videoElement;if(o.tagName!=="VIDEO")return;this.annotatedFrameCoordinates=[];let t=Array.from(this.timeStack.keys()).filter(u=>{var m;return(m=this.timeStack.get(u))==null?void 0:m.length}),e=o.duration*this.fps,{x:i,width:s,height:r,y:l}=this.progressBarCoordinates,a=t.map(u=>Math.ceil(u/e*s));this.ctx.save(),this.ctx.fillStyle="rgba(0, 0, 0, 0.5)",this.ctx.fillRect(i,l,s,r),this.ctx.fillStyle="#F3CE32";let h=this.isMobile?16:8;a.forEach((u,m)=>{this.ctx.beginPath();let v=i+u,y=this.canvasHeight-r/2;this.ctx.fillRect(v-h/2,y-h/2,h,h),this.annotatedFrameCoordinates.push({x:v,y,frame:t[m]})});let c=this.playbackFrame,f=Math.ceil(c/e*s)+i;this.ctx.fillStyle="white",this.ctx.beginPath();let d=f,p=this.canvasHeight-r/2;this.ctx.beginPath(),this.ctx.fillRect(d-h/2,p-h/2,h,h),this.ctx.fill(),this.ctx.restore()}I.prototype.initUI=Et;I.prototype.initCanvas=It;I.prototype.addFrameSquareOverlay=Lt;I.prototype.addVideoOverlay=At;I.prototype.addProgressBarOverlay=Ht;new EventSource("/esbuild").addEventListener("change",()=>location.reload());var T=document.querySelector("video");function Rt(){return C(this,null,function*(){let o=window.getComputedStyle(T),n=parseFloat(o.width),t=parseFloat(o.height),e=window.innerHeight-80;if(t>e){let u=n/t,m=e,v=m*u;T.style.width=`${v}px`,T.style.height=`${m}px`}let i=yield fetch(T.currentSrc).then(u=>u.blob()),s=new Promise(u=>{setTimeout(()=>{u(!0)},250),T.addEventListener("loadeddata",()=>{u(!0)},{once:!0})}),r=yield fetch("./frame_29.png").then(u=>C(this,null,function*(){let m=yield u.blob(),v=new Blob([m],{type:"image/png"}),y=new Image,b=new Promise(P=>{y.addEventListener("load",()=>{P(!0)},{once:!0})});return y.src=window.URL.createObjectURL(v),yield b,y}));T.paused||T.pause();let l=new Blob([i],{type:"video/mp4"});T.src=window.URL.createObjectURL(l),yield s;let a=new I(T);a.setFrameRate(30),yield a.addReferenceVideoByURL("./mov_bbb_g.mp4"),requestAnimationFrame(()=>{a.setCanvasSize()}),a.enableVideoFrameBuffer(),console.log({tool:a}),a.addShapesToFrame(29,[{type:"image",image:r,x:0,y:0,width:1,height:1,strokeStyle:"red",lineWidth:2,fillStyle:"red"}]),T.paused||T.pause(),setInterval(()=>{a.destroy(),a.init(T)},1e8),setInterval(()=>{console.log(a.saveAllFrames())},1e5);let h=document.getElementById("file"),c=document.getElementById("download"),f=document.getElementById("sample"),d=document.getElementById("video"),p=document.getElementById("ref-video");d.addEventListener("change",u=>C(this,null,function*(){if(!d.files||d.files.length===0)return;let m=prompt("Enter FPS","30");if(!m)return;let v=d.files[0],y=new Blob([v],{type:v.type}),b=window.URL.createObjectURL(y);yield a.setVideoUrl(b,parseInt(m,10))})),p.addEventListener("change",u=>C(this,null,function*(){if(!p.files||p.files.length===0)return;let m=prompt("Enter FPS","30");if(!m)return;let v=p.files[0],y=new Blob([v],{type:v.type}),b=window.URL.createObjectURL(y);yield a.addReferenceVideoByURL(b,parseInt(m,10),v.type)})),f.addEventListener("click",u=>{u.stopPropagation(),u.preventDefault(),fetch("./annotations-sample.json").then(m=>m.json()).then(m=>{a.loadAllFrames(m),a.redrawFullCanvas()})}),h.addEventListener("change",u=>{if(!h.files||h.files.length===0)return;let m=h.files[0],v=new FileReader;v.onload=y=>{if(!y.target)return;let b=y.target.result,P=JSON.parse(b);confirm("Append to existing annotations?")?a.appendFrames(P):a.loadAllFrames(P),a.redrawFullCanvas()},v.readAsText(m)}),c.addEventListener("click",u=>{u.stopPropagation(),u.preventDefault();let m=a.saveAllFrames(),v=document.createElement("a");v.href=URL.createObjectURL(new Blob([JSON.stringify(m)],{type:"application/json"}));let y=new Date().toISOString().replace(/:/g,"-");v.download=`annotations-${y}.json`,v.click()})})}T.readyState===0?T.addEventListener("loadedmetadata",()=>{requestAnimationFrame(()=>{Rt()})},{once:!0}):Rt();})(); + `}function Pt(o,n){let t=[.25,.5,.75,1],e=document.createElement("button"),i=t[t.length-1];e.type="button",o.playbackRate=i,e.innerHTML=Ft(i),e.style.margin="5px",n.addEvent(e,"click",()=>{let s=t.indexOf(o.playbackRate),a=s+1>=t.length?0:s+1;o.playbackRate=t[a],e.innerHTML=Ft(t[a])}),n.buttons.push(e),n.playerControlsContainer.appendChild(e)}var se="#F3CE32";function Mt(){var d,u;let o=document.createElement("div");o.style.position="absolute",o.style.top="-40px",o.style.left="0",o.style.zIndex="2",(d=this.canvas.parentNode)==null||d.insertBefore(o,this.canvas);let n=document.createElement("div");n.style.position="relative",n.style.top="0",n.style.left="0",n.style.zIndex="2",(u=this.canvas.parentNode)==null||u.insertBefore(n,this.canvas.nextSibling),this.playerControlsContainer=n;let t=this.videoElement.tagName==="VIDEO"?this.videoElement:null;this.uiContainer=o;let e=(c,p,v=o)=>{let m=document.createElement("button");if(m.type="button",m.innerHTML=c,m.style.margin="5px",v.appendChild(m),this.buttons.push(m),typeof p=="function")this.addEvent(m,"click",p);else{m.dataset.tool=p;let f=()=>{this.currentTool===p?this.currentTool=null:this.currentTool=p};this.addEvent(m,"click",f)}return m},i=()=>{let c=document.createElement("div");return c.style.display="inline-flex",c.style.alignItems="center",c.style.margin="5px",o.appendChild(c),c};e('',"rectangle"),e('',"circle"),e('',"line"),e('',"curve"),e('',"arrow"),e('',"text"),e('',"eraser"),this.isMobile&&(this.hideButton("line"),this.hideButton("circle"),this.hideButton("rectangle"),this.hideButton("eraser")),e('',"move"),e('',"compare"),e('',()=>{this.handleUndo()}),t&&(e('',()=>{this.prevFrame()},this.playerControlsContainer),kt(t,this),e('',()=>{this.nextFrame()},this.playerControlsContainer),Et(t,this),Pt(t,this),Tt(t,this));let s=document.createElement("input");s.type="color",s.value=se,s.style.margin="5px",this.colorPicker=s,o.appendChild(s);let a=i(),l=document.createElement("input");l.type="number",l.step="1",l.min="1",l.max="10",l.value="5",l.style.margin="5px",a.appendChild(l);let r=c=>{this.ctx.lineWidth=c.target.valueAsNumber,this.focusOnMediaNode()};this.addEvent(l,"input",r);let h=c=>{this.ctx.strokeStyle=c.target.value,this.ctx.fillStyle=c.target.value,this.focusOnMediaNode()};this.addEvent(s,"input",h),this.colorPicker=s,this.strokeSizePicker=l,this.hideButton("compare"),t&&(this.hide(),this.addEvent(t,"pause",()=>{this.show()}),this.addEvent(t,"seek",()=>{t.paused&&this.show()}),this.addEvent(t,"timeupdate",()=>{t.currentTime<2e-4&&!t.paused&&this.startAnnotationsAsVideo()}),this.addEvent(t,"error",()=>{this.hide()}),this.addEvent(t,"stalled",()=>{this.hide()}),this.addEvent(t,"play",()=>{this.hideControls(),this.startAnnotationsAsVideo()}),this.addEvent(document,"copy",c=>{yt(c,this)}),this.addEvent(document,"cut",c=>{xt(c,this)}),this.addEvent(document,"paste",c=>{bt(c,this)}),this.addEvent(document,"click",c=>{gt(c,this)}),this.addEvent(document,"keydown",c=>{wt(c,this)}))}function Bt(){var o;this.canvas=document.createElement("canvas"),this.ctx=this.canvas.getContext("2d"),(o=this.videoElement.parentNode)==null||o.insertBefore(this.canvas,this.videoElement.nextSibling),this.canvas.style.position="absolute",this.canvas.style.backgroundColor="transparent",this.canvas.style.top="0",this.canvas.style.left="0",this.canvas.style.zIndex="1",this.addEvent(this.canvas,"pointerdown",this.handleMouseDown),this.addEvent(this.canvas,"pointermove",this.handleMouseMove),this.addEvent(this.canvas,"pointerup",this.handleMouseUp),this.addEvent(this.canvas,"pointercancel",this.handleMouseUp),this.addEvent(window,"resize",this.setCanvasSize),this.addEvent(document,"keydown",this.onKeyDown)}var H=class{constructor(){this.destructors=[];this.isDestroyed=!1;this.activeTimeFrame=1;this.globalShapes=[];this.timeStack=new Map;this.undoTimeStack=new Map}cleanFrameStacks(){this.timeStack.clear(),this.undoTimeStack.clear()}destroy(){this.destructors.forEach(n=>n()),this.destructors=[],this.globalShapes=[],this.cleanFrameStacks()}raf(n){return requestAnimationFrame(n)}addEvent(n,t,e){let i=s=>{this.isDestroyed||e(s)};n.addEventListener(t,i),this.destructors.push(()=>{n.removeEventListener(t,i)})}addProgressBarOverlay(){throw new Error("Method not implemented.")}initUI(){throw new Error("Method not implemented.")}initCanvas(){throw new Error("Method not implemented.")}addFrameSquareOverlay(n=this.activeTimeFrame){throw new Error("Method not implemented.")}addVideoOverlay(){throw new Error("Method not implemented.")}withRefVideo(n){this.isDestroyed||this.referenceVideoElement&&n(this.referenceVideoElement)}withVideo(n){if(this.isDestroyed)return;let t=this.videoElement;!t||t.tagName!=="VIDEO"||n(t)}};var g=class{constructor(n){this.startX=0;this.startY=0;this.isDrawing=!1;this.annotationTool=n}on(n,t){}get ctx(){return this.annotationTool.ctx}onDeactivate(){}onActivate(){}reset(){this.startX=0,this.startY=0,this.isDrawing=!1}save(n){this.annotationTool.addShape(n)}};var R=class extends g{constructor(){super(...arguments);this.name="rectangle"}move(t,e,i){return t.x+=e,t.y+=i,t}normalize(t,e,i){return w(y({},t),{x:t.x/e,y:t.y/i,width:t.width/e,height:t.height/i})}onPointerDown(t){let{x:e,y:i}=this.annotationTool.getRelativeCoords(t);this.startX=e,this.startY=i,this.isDrawing=!0}onPointerMove(t){if(!this.isDrawing)return;let{x:e,y:i}=this.annotationTool.getRelativeCoords(t);this.drawRectangle(this.startX,this.startY,e-this.startX,i-this.startY)}onPointerUp(t){if(!this.isDrawing)return;let{x:e,y:i}=this.annotationTool.getRelativeCoords(t);this.save({type:"rectangle",x:this.startX,y:this.startY,width:e-this.startX,height:i-this.startY,strokeStyle:this.ctx.strokeStyle,fillStyle:this.ctx.fillStyle,lineWidth:this.ctx.lineWidth}),this.drawRectangle(this.startX,this.startY,e-this.startX,i-this.startY),this.isDrawing=!1}drawRectangle(t,e,i,s){this.ctx.beginPath(),this.ctx.rect(t,e,i,s),this.ctx.stroke()}draw(t){this.drawRectangle(t.x,t.y,t.width,t.height)}};var V=class extends g{constructor(){super(...arguments);this.name="circle"}move(t,e,i){return t.x+=e,t.y+=i,t}normalize(t,e,i){return w(y({},t),{x:t.x/e,y:t.y/i,radius:t.radius/e})}onPointerDown(t){let{x:e,y:i}=this.annotationTool.getRelativeCoords(t);this.startX=e,this.startY=i,this.isDrawing=!0}onPointerMove(t){if(!this.isDrawing)return;let{x:e,y:i}=this.annotationTool.getRelativeCoords(t),s=Math.sqrt(Math.pow(e-this.startX,2)+Math.pow(i-this.startY,2));this.drawCircle(this.startX,this.startY,s)}onPointerUp(t){if(!this.isDrawing)return;let{x:e,y:i}=this.annotationTool.getRelativeCoords(t),s=Math.sqrt(Math.pow(e-this.startX,2)+Math.pow(i-this.startY,2));this.save({type:"circle",x:this.startX,y:this.startY,radius:s,strokeStyle:this.ctx.strokeStyle,fillStyle:this.ctx.fillStyle,lineWidth:this.ctx.lineWidth}),this.drawCircle(this.startX,this.startY,s),this.isDrawing=!1}drawCircle(t,e,i){this.ctx.beginPath(),this.ctx.arc(t,e,i,0,2*Math.PI),this.ctx.stroke()}draw(t){this.drawCircle(t.x,t.y,t.radius)}};var W=class{constructor(n,t){this.x=n;this.y=t}distanceToLine(n,t){let e=t.x-n.x,i=t.y-n.y,s=Math.abs(i*this.x-e*this.y+t.x*n.y-t.y*n.x),a=Math.sqrt(i*i+e*e);return s/a}};function N(o,n){if(o.length<=2)return o;let t=o[0],e=o[o.length-1],i=-1,s=0;for(let a=1;as&&(i=a,s=l)}if(s>n){let a=N(o.slice(0,i+1),n),l=N(o.slice(i),n);return a.slice(0,a.length-1).concat(l)}else return[t,e]}var z=class extends g{constructor(){super(...arguments);this.name="curve";this.curvePoints=[]}move(t,e,i){return t.points=t.points.map(s=>({x:s.x+e,y:s.y+i})),t}normalize(t,e,i){return w(y({},t),{points:t.points.map(s=>({x:s.x/e,y:s.y/i}))})}draw(t){this.drawCurve(t)}reset(){super.reset(),this.curvePoints=[]}onPointerDown(t){if(this.isDrawing)return;let{x:e,y:i}=this.annotationTool.getRelativeCoords(t);this.curvePoints=[],this.startX=e,this.startY=i,this.isDrawing=!0,this.curvePoints.push({x:e,y:i})}onPointerMove(t){if(!this.isDrawing)return;let{x:e,y:i}=this.annotationTool.getRelativeCoords(t);this.curvePoints.push({x:e,y:i}),this.drawCurve({points:this.curvePoints,lineWidth:this.ctx.lineWidth})}onPointerUp(t){if(!this.isDrawing)return;let{x:e,y:i}=this.annotationTool.getRelativeCoords(t);this.curvePoints.push({x:e,y:i});let s=this.curvePoints.map(d=>new W(d.x,d.y)),h={type:"curve",points:N(s,2).map(d=>({x:d.x,y:d.y})),strokeStyle:this.ctx.strokeStyle,fillStyle:this.ctx.fillStyle,lineWidth:this.ctx.lineWidth};this.save(h),this.curvePoints=[],this.isDrawing=!1}drawCurve(t){if(t.points.length===2&&t.points[0].x===t.points[1].x&&t.points[0].y===t.points[1].y){let e=t.lineWidth/4,i=0,s=2*Math.PI;this.ctx.beginPath(),this.ctx.arc(t.points[0].x,t.points[0].y,e,i,s),this.ctx.stroke()}else{this.ctx.beginPath(),this.ctx.moveTo(t.points[0].x,t.points[0].y);for(let e=1;e0){let s=this.annotationTool.globalShapes[0];if(s.type==="compare"){let a=this.annotationTool.deserialize([s])[0];this.draw(a),this.annotationTool.addFrameSquareOverlay()}}return}let{x:e}=this.annotationTool.getRelativeCoords(t);this.comparisonLine=e;let i={type:"compare",strokeStyle:this.ctx.strokeStyle,fillStyle:this.ctx.fillStyle,lineWidth:this.ctx.lineWidth,x:e};this.draw(i),this.drawDelimiter(i)}onPointerUp(){this.isDrawing&&(this.save({type:"compare",strokeStyle:this.ctx.strokeStyle,fillStyle:this.ctx.fillStyle,lineWidth:this.ctx.lineWidth,disabled:!1,x:this.comparisonLine}),this.isDrawing=!1)}removePreviousCompare(){this.annotationTool.globalShapes=this.annotationTool.globalShapes.filter(t=>t.type!=="compare")}disablePreviousCompare(){this.annotationTool.globalShapes=this.annotationTool.globalShapes.map(t=>t.type==="compare"?w(y({},t),{disabled:!0}):t)}save(t){this.removePreviousCompare();let e=this.annotationTool.serialize([t])[0];e.x<.05||e.x>.95||this.annotationTool.addGlobalShape(e)}drawDelimiter(t){this.ctx.beginPath(),this.ctx.moveTo(t.x,0),this.ctx.lineTo(t.x,this.annotationTool.canvasWidth),this.ctx.stroke()}drawShape(t){var st,at,rt,lt,ht,dt,ct,mt;let e=this.annotationTool.videoElement,i=this.annotationTool.referenceVideoElement;if(!e||!i)return;let s=this.ctx.globalAlpha,a=this.annotationTool.canvasWidth,l=this.annotationTool.canvasHeight,r=t.x,h=i.videoHeight-e.videoHeight,d=i.videoWidth-e.videoWidth,u=this.annotationTool.isMobile;this.ctx.globalAlpha=this.leftOpacity;let c=(at=(st=this.annotationTool.referenceVideoFrameBuffer)==null?void 0:st.frameNumberFromTime(e.currentTime))!=null?at:1,p=c;if(d>e.videoWidth&&h>e.videoHeight&&!this.annotationTool.isMobile){let S=(dt=(ht=this.annotationTool.referenceVideoFrameBuffer)==null?void 0:ht.getFrameNumberBySignature((lt=(rt=this.annotationTool.videoFrameBuffer)==null?void 0:rt.getHistogram(c))!=null?lt:null,c))!=null?dt:c,B=Math.abs(c-S);B>=1&&B<=3&&(p=S)}let m=(ct=this.annotationTool.referenceVideoFrameBuffer)==null?void 0:ct.getFrame(p),f=(mt=this.annotationTool.videoFrameBuffer)==null?void 0:mt.getFrame(c);if(u){this.ctx.imageSmoothingQuality="low";let S=r/a,B=r;this.ctx.drawImage(f!=null?f:e,0,0,S*e.videoWidth,e.videoHeight,0,0,B,l)}else{let S=f?f.width:e.videoWidth,B=f?f.height:e.videoHeight;this.ctx.drawImage(f!=null?f:e,0,0,S,B,0,0,a,l)}this.ctx.globalAlpha=this.rightOpacity;let x=0,C=0,P=e.videoWidth/e.videoHeight,it=i.videoWidth/i.videoHeight,G=Math.abs(P-it)>.1,M=10,nt=Math.abs(h)>M,A=e.videoWidth,J=e.videoHeight,k=0;if(d<-M)if(G){let S=e.videoWidth/a;k=Math.abs(d/2),k=k/S,k<=M&&(k=0)}else A=i.videoWidth;else d>M&&(A=i.videoWidth);if(h===0)x=0;else if(h>0)G?(x=h/2,x<=M&&(x=0)):J=nt?i.videoHeight:e.videoHeight;else if(!G)J=nt?i.videoHeight:e.videoHeight;else{C=Math.abs(h/2);let S=e.videoHeight/l;C=C/S,C<=M&&(C=0)}let Q=r-k,ot=a-Q,_t=ot/a*A;m?(u&&(this.ctx.imageSmoothingQuality="low"),this.ctx.drawImage(m,Q/a*A,x,_t,J,Q+k,C,ot,l)):console.log("no video data",c),this.ctx.globalAlpha=s}draw(t){if(t.disabled)return;let e=this.annotationTool.videoElement,i=this.annotationTool.referenceVideoElement;!e||!i||this.drawShape(t)}};function he(o){let n=o[0],t=o[0];for(let e=1;et&&(t=o[e]);return[n,t]}var $=class extends g{constructor(t){super(t);this.name="audio-peaks";this.canvas=document.createElement("canvas");this.props={peaks:new Int8Array,theme:{waveOutlineColor:"rgba(255,192,203,0.7)",waveFillColor:"grey",waveProgressColor:"orange"},waveHeight:40,bits:16};this.drawCtx=this.canvas.getContext("2d")}onVideoBlobSet(t){return b(this,null,function*(){let e=yield t.arrayBuffer();this.init(e)})}on(t,e){t==="videoBlobSet"&&this.onVideoBlobSet(e)}extractPeaks(t){return b(this,null,function*(){let{default:e}=yield Promise.resolve().then(()=>ne(Rt(),1)),i=this.progressBarCoordinates.width,s=Math.ceil(t.length/i);return e(t,s,!0)})}setProps(t){let[e,i]=he(t.data[0]),s=Math.pow(2,t.bits-1)-1,a=-Math.pow(2,t.bits-1);this.props.peaks=t.data[0].map(l=>l<0?Math.round(l/e*a):Math.round(l/i*s)),this.props.bits=t.bits}init(t){return b(this,null,function*(){try{let i=yield new AudioContext().decodeAudioData(t),s=yield this.extractPeaks(i);this.initCanvas(),this.setProps(s),this.annotationTool.removeGlobalShape("audio-peaks"),this.annotationTool.addGlobalShape({x:0,y:0,strokeStyle:"red",fillStyle:"red",lineWidth:1,type:"audio-peaks"}),this.clearLocalCanvas(),this.drawOnCanvas()}catch(e){this.initCanvas(),this.props.peaks=new Int8Array,this.annotationTool.removeGlobalShape("audio-peaks"),this.clearLocalCanvas(),console.error(e)}})}initCanvas(){this.canvas.width=this.progressBarCoordinates.width*this.pixelRatio,this.canvas.height=this.props.waveHeight*this.pixelRatio,this.drawCtx.scale(this.pixelRatio,this.pixelRatio)}move(t,e,i){return t.x+=e,t.y+=i,t}normalize(t,e,i){return w(y({},t),{x:t.x/e,y:t.y/i})}onPointerDown(t){}onPointerMove(t){}onPointerUp(t){}reset(){this.clearLocalCanvas(),this.props.peaks=new Int8Array,this.annotationTool.removeGlobalShape("audio-peaks")}draw(t){let e=this.annotationTool.videoElement;if(!e||e.tagName!=="VIDEO"||e.muted||e.volume===0)return;this.ctx.clearRect(0,0,this.annotationTool.canvasWidth,this.annotationTool.canvasHeight);let{waveHeight:s,theme:a}=this.props,l=this.ctx,r=s/2,h=this.progressBarCoordinates.y-20,{x:d,width:u}=this.progressBarCoordinates,c=this.annotationTool.playbackFrame,p=e.duration*this.annotationTool.fps,v=Math.ceil(c/p*u)+d;this.ctx.drawImage(this.canvas,d,h,u,s),l.fillStyle=a.waveProgressColor,l.fillRect(v,h+0,1,r*2)}get pixelRatio(){return this.annotationTool.pixelRatio}get progressBarCoordinates(){return this.annotationTool.progressBarCoordinates}clearLocalCanvas(){this.drawCtx.clearRect(0,0,this.canvas.width,this.canvas.height)}drawOnCanvas(){let{peaks:t,bits:e,waveHeight:i,theme:s}=this.props,a=this.drawCtx,l=0,r=0,h=i/2,d=ft(2,e-1),u=0,c=t.length;a.fillStyle=s.waveOutlineColor;for(let p=0;p{s.pop(),a=!1};o.addEventListener("seeked",r);function h(){return s.reduce((d,u)=>d+u)/s.length}return()=>{o.removeEventListener("seeked",r)}}function Nt(o,n,t){return .299*o+.587*n+.114*t}var de=0,et=class extends Array{constructor(){super(...arguments);this.id=de++}};function zt(o){let n=o.width,t=o.height,e=new Array(n*t),i=new et,s=0;for(let a=0;aMath.max(o.id,n.id)+"-"+Math.min(o.id,n.id);function Ot(o,n){let t=ce(o,n);if(tt.has(t))return tt.get(t);let e=0;for(let s=0;sn.close()),this.frames.clear()}tick(n,t){if(this.setCanvasSize(),t.expectedDisplayTime-performance.now()>10&&console.log("looks like frame is not yet rendered"),this.isDestroyed)return!1;if(this.seenFrames>=this.totalFrames){if(this.autoHide)try{this.video.paused||this.video.pause(),this.video.style.display="none"}catch(l){}return!1}if(this.video.videoWidth===0||this.video.videoHeight===0)return!0;let i=this.video,s=this.frameNumberFromTime(t.mediaTime);if(!Math.max(1,t.presentedFrames>this.totalFrames?t.presentedFrames%this.totalFrames:t.presentedFrames))throw new Error("expectedFrame is 0");if(this.hasFrame(s))this.seenFrames++;else{this.ctx.drawImage(i,0,0,this.width,this.height,0,0,this.width,this.height);let l=this.ctx.getImageData(0,0,this.canvas.width,this.canvas.height);createImageBitmap(l,0,0,this.width,this.height).then(r=>b(this,null,function*(){this.setFrame(s,r),this.isMobile||this.setHistogram(s,this.toHistogram(r))}))}return!0}addRequestFrameCallback(){this.isDestroyed||this.video.requestVideoFrameCallback((n,t)=>{this.tick(n,t)&&this.addRequestFrameCallback()})}createCanvas(){this.canvas=document.createElement("canvas"),this.ctx=this.canvas.getContext("2d",{willReadFrequently:!0,alpha:!1})}setCanvasSize(){this.isCanvasSizeSet||(this.canvas.width=this.video.videoWidth,this.canvas.height=this.video.videoHeight,this.isCanvasSizeSet=!0)}get width(){return this.video.videoWidth}get height(){return this.video.videoHeight}hasFrame(n){return this.frames.has(n)}getFrame(n){return this.frames.has(n)?this.frames.get(n):null}getFrameNumberBySignature(n,t){if(!n)return t;let e=0,i=t;return[t-3,t-2,t-1,t,t+1,t+2,t+3].filter(a=>a>0&&a<=this.totalFrames).forEach(a=>{let l=this.getHistogram(a);if(l){let r=Ot(n,l);r>e&&(e=r,i=a)}}),i}setFrame(n,t){this.frames.set(n,t)}setHistogram(n,t){this.histograms.set(n,t)}getHistogram(n){var t;return(t=this.histograms.get(n))!=null?t:null}get totalFrames(){return Math.round(this.video.duration*this.fps)}frameNumberFromTime(n){return Math.max(1,Math.round(n*this.fps))}};var me=window.devicePixelRatio||1,Ut=25,I=class extends H{constructor(t){super();this.referenceVideoFrameBuffer=null;this.videoFrameBuffer=null;this.isMouseDown=!1;this.buttons=[];this.plugins=[];this.annotatedFrameCoordinates=[];this.fps=Ut;this.plannedFn=null;this.ct=0;this.isCanvasInitialized=!1;this.enforcedCanvasSize=null;this.lastNavigatedFrame=0;this.isProgressBarNavigation=!1;this.isAnnotationsAsVideoActive=!1;this.plugins=Vt.map(e=>new e(this)),this.init(t)}prevFrame(){let t=this.playbackFrame,e=Math.max(1,t-1);e===this.playbackFrame?this.playbackFrame=this.totalFrames-1:this.playbackFrame=e}nextFrame(){let t=this.playbackFrame,e=Math.min(this.totalFrames,t+1);e===this.totalFrames?this.playbackFrame=1:this.playbackFrame=e}removeGlobalShape(t){this.globalShapes=this.globalShapes.filter(e=>e.type!==t)}addGlobalShape(t){this.globalShapes.push(t)}get selectedColor(){return this.colorPicker.value}get selectedStrokeSize(){return this.strokeSizePicker.valueAsNumber}get currentTool(){return this._currentTool}set currentTool(t){let e=this._currentTool;e&&(this.getButtonForTool(e).classList.remove("active"),this.pluginForTool(e).onDeactivate()),this._currentTool=t,this.canvas.style.cursor=t?"pointer":"default",t&&(this.getButtonForTool(t).classList.add("active"),this.pluginForTool(t).onActivate())}enableFrameRateDetection(){if(this.destructors.find(i=>i.name==="frameRateDetector"))return;let t=this.videoElement;if(t.tagName==="IMG")return;let e=Wt(t,i=>{this.fps=i});Object.defineProperty(e,"name",{value:"frameRateDetector"}),this.destructors.push(e)}timeToFrame(t){return Math.max(1,Math.round(t*this.fps))}get playbackFrame(){return this.videoElement instanceof HTMLImageElement?1:this.timeToFrame(this.videoElement.currentTime)}set playbackFrame(t){if(this.videoElement instanceof HTMLImageElement)return;let e=t/this.fps;this.videoElement.currentTime=e,this.rvf(()=>{this.show()})}rvf(t){this.plannedFn=t}get canvasWidth(){var t,e;return(e=(t=this.enforcedCanvasSize)==null?void 0:t.width)!=null?e:0}get canvasHeight(){var t,e;return(e=(t=this.enforcedCanvasSize)==null?void 0:t.height)!=null?e:0}get aspectRatio(){return this.canvasWidth/this.canvasHeight}get isMobile(){return window.innerWidth<960}get progressBarCoordinates(){let t=this.isMobile?30:10,e=5,i=55,s=this.canvasWidth-e-i,a=e,l=this.canvasHeight-t;return{x:a,y:l,width:s,height:t}}get shapes(){return this.timeStack.has(this.activeTimeFrame)||this.timeStack.set(this.activeTimeFrame,[]),this.timeStack.get(this.activeTimeFrame)}set shapes(t){this.timeStack.set(this.activeTimeFrame,t)}get undoStack(){return this.undoTimeStack.has(this.activeTimeFrame)||this.undoTimeStack.set(this.activeTimeFrame,[]),this.undoTimeStack.get(this.activeTimeFrame)}set undoStack(t){this.undoTimeStack.set(this.activeTimeFrame,t)}get pixelRatio(){return me}setVideoBlob(i){return b(this,arguments,function*(t,e=this.fps){let s=URL.createObjectURL(t);yield this.setVideoUrl(s,e),this.plugins.forEach(a=>{a.on("videoBlobSet",t)})})}setVideoUrl(i){return b(this,arguments,function*(t,e=this.fps){if(this.videoElement instanceof HTMLImageElement)return;let s=this.videoElement;s.src=t.toString(),yield this.videoElement.load(),this.setFrameRate(e),this.videoFrameBuffer&&(this.videoFrameBuffer.destroy(),this.videoFrameBuffer=new F(s,e,!1),this.videoFrameBuffer.isMobile=this.isMobile),this.setCanvasSize()})}enableVideoFrameBuffer(){this.videoElement instanceof HTMLImageElement||(this.videoFrameBuffer=new F(this.videoElement,this.fps,!1),this.videoFrameBuffer.isMobile=this.isMobile)}hide(){this.stopAnnotationsAsVideo(),this.hideControls(),this.hideCanvas()}showControls(){this.uiContainer.style.display="block"}hideControls(){this.uiContainer.style.display="none"}showCanvas(){this.canvas.style.display="block"}hideCanvas(){this.canvas.style.display="none"}updateActiveTimeFrame(t=void 0){this.activeTimeFrame=t?this.timeToFrame(t):this.playbackFrame}show(){this.stopAnnotationsAsVideo(),this.updateActiveTimeFrame(),this.showCanvas(),this.showControls(),this.redrawFullCanvas()}setCanvasSettings(){this.ctx.strokeStyle=this.selectedColor,this.ctx.fillStyle=this.selectedColor,this.ctx.lineWidth=this.selectedStrokeSize}pluginForTool(t){if(this.isDestroyed)throw new Error("AnnotationTool is destroyed");let e=this.plugins.find(i=>i.name===t);if(!e)throw new Error(`No plugin found for tool ${t}`);return e}getButtonForTool(t){return this.buttons.find(e=>e.dataset.tool===t)}bindContext(){this.handleMouseDown=this.handleMouseDown.bind(this),this.handleMouseMove=this.handleMouseMove.bind(this),this.handleMouseUp=this.handleMouseUp.bind(this),this.setCanvasSize=this.setCanvasSize.bind(this),this.onKeyDown=this.onKeyDown.bind(this)}initProperties(){this.isDestroyed=!1,this.isProgressBarNavigation=!1,this.shapes=[],this.globalShapes=[],this.currentTool=this.isMobile?null:"curve"}setVideoStyles(){this.videoElement.style.objectFit="cover",this.videoElement.style.objectPosition="left top"}get frameCallbackSupported(){return"requestVideoFrameCallback"in HTMLVideoElement.prototype}initFrameCounter(){if(!this.frameCallbackSupported){setTimeout(()=>{var t;(t=this.plannedFn)==null||t.call(this),this.plannedFn=null,this.initFrameCounter(),this.updateActiveTimeFrame(),this.playAnnotationsAsVideo()},1e3/this.fps);return}this.withVideo(t=>{t.requestVideoFrameCallback((e,i)=>{var s,a;this.isCanvasInitialized||this._setCanvasSize(),(s=this.videoFrameBuffer)==null||s.tick(e,i),(a=this.plannedFn)==null||a.call(this),this.plannedFn=null,this.raf(()=>{this.initFrameCounter(),this.updateActiveTimeFrame(i.mediaTime),this.playAnnotationsAsVideo()})})})}init(t){this.videoElement=t,this.setVideoStyles(),this.initFrameCounter(),this.bindContext(),this.initCanvas(),this.initUI(),this.initProperties(),this.setCanvasSize()}onKeyDown(t){(t.ctrlKey||t.metaKey)&&t.key.toLowerCase()==="z"&&this.handleUndo()}removeLastShape(){this.shapes.pop(),this.redrawFullCanvas()}handleUndo(){this.undoStack.length>0&&(this.shapes=this.undoStack.pop(),this.redrawFullCanvas())}destroy(){var s,a,l,r,h,d,u,c;if(this.isDestroyed)return;super.destroy(),this.stopAnnotationsAsVideo(),this._currentTool=null,this.plugins.forEach(p=>p.reset()),this.annotatedFrameCoordinates=[],this.setFrameRate(Ut);let t=this.strokeSizePicker.parentElement;if((s=t==null?void 0:t.parentNode)==null||s.removeChild(t),this.referenceVideoElement){let p=this.referenceVideoElement.parentElement;(a=p==null?void 0:p.parentNode)==null||a.removeChild(p),this.referenceVideoElement=null}let e=this.colorPicker.parentElement;(l=e==null?void 0:e.parentNode)==null||l.removeChild(e),this.buttons.forEach(p=>{var v;(v=p.parentNode)==null||v.removeChild(p)}),this.buttons=[],(r=this.uiContainer.parentNode)==null||r.removeChild(this.uiContainer),(h=this.canvas.parentNode)==null||h.removeChild(this.canvas),(d=this.playerControlsContainer.parentElement)==null||d.removeChild(this.playerControlsContainer),["strokeSizePicker","colorPicker","uiContainer","playerControlsContainer","canvas","ctx","videoElement"].forEach(p=>{delete this[p]}),this.activeTimeFrame=0,this.isDestroyed=!0,(u=this.referenceVideoFrameBuffer)==null||u.destroy(),this.referenceVideoFrameBuffer=null,(c=this.videoFrameBuffer)==null||c.destroy(),this.videoFrameBuffer=null}_setCanvasSize(){let t=getComputedStyle(this.videoElement),e=parseInt(t.width,10),i=this.videoElement,s=i.videoWidth/i.videoHeight;if(isNaN(e)||!i.videoWidth||!i.videoHeight)return this.isCanvasInitialized=!1,this.setCanvasSettings(),!1;let a=Math.min(e,i.videoWidth),l=Math.floor(a/s);return i.style.width=`${a}px`,i.style.height=`${l}px`,this.isCanvasInitialized=i.videoWidth>0&&i.videoHeight>0,this.canvas.width=a*this.pixelRatio,this.canvas.height=l*this.pixelRatio,this.canvas.style.width=`${a}px`,this.canvas.style.height=`${l}px`,this.enforcedCanvasSize={width:a,height:l},this.ctx.scale(this.pixelRatio,this.pixelRatio),this.setCanvasSettings(),!0}setCanvasSize(){this._setCanvasSize()&&(this.syncVideoSizes(),this.redrawFullCanvas())}addShape(t){let e=this.serialize([t])[0];this.undoStack.push([...this.shapes]),this.shapes.push(e)}get msPerFrame(){return this.fps/1e3}syncVideoSizes(){this.withRefVideo(t=>{let i=this.videoElement.getBoundingClientRect();t.style.position="fixed",t.style.top=`${i.top}px`,t.style.left=`${i.left}px`})}addReferenceVideoByURL(s){return b(this,arguments,function*(t,e=this.fps,i="video/mp4"){var h;let a=yield fetch(t).then(d=>d.blob()),l=new Blob([a],{type:i}),r=window.URL.createObjectURL(l);this.referenceVideoElement?((h=this.referenceVideoFrameBuffer)==null||h.destroy(),this.referenceVideoFrameBuffer=new F(this.referenceVideoElement,e),this.referenceVideoFrameBuffer.isMobile=this.isMobile,this.referenceVideoFrameBuffer.start()):(this.referenceVideoElement=document.createElement("video"),this.withRefVideo(d=>{this.isMobile?(d.style.zIndex="2",d.style.display="block",d.style.top="0",d.style.left="0",d.style.opacity="0.25",d.style.width="20px",d.style.height="15px"):(d.style.zIndex="-1",d.style.display="none",d.style.width="100px",d.style.height="70px"),d.style.objectFit="cover",d.style.objectPosition="left top",d.muted=!0,d.volume=0,d.playsInline=!0,d.autoplay=!1,d.controls=!1,d.loop=!0,this.videoElement.after(d),this.referenceVideoFrameBuffer=new F(d,e),this.referenceVideoFrameBuffer.isMobile=this.isMobile,this.referenceVideoFrameBuffer.start()}),this.syncVideoSizes()),this.referenceVideoElement.src=r,this.referenceVideoElement.play().then(()=>{this.showButton("compare")}).catch(()=>{this.hideButton("compare")})})}hideButton(t){let e=this.getButtonForTool(t);e.style.display="none"}showButton(t){let e=this.getButtonForTool(t);e.style.display=""}addSingletonShape(t){let e=this.serialize([t])[0],i=this.shapes.filter(s=>s.type!==t.type);this.replaceFrame(this.playbackFrame,[...i,e])}serialize(t=this.shapes){let e=this.canvasWidth,i=this.canvasHeight;return t.map(s=>this.pluginForTool(s.type).normalize(s,e,i))}deserialize(t){let e=1/this.canvasWidth,i=1/this.canvasHeight;return t.map(s=>this.pluginForTool(s.type).normalize(s,e,i))}getRelativeCoords(t){let e=this.canvas.getBoundingClientRect();return{x:this.getEventX(t)-e.left,y:this.getEventY(t)-e.top}}handleMouseDown(t){if(t.preventDefault(),this.isMouseDown=!0,L(t))return;let e=this.frameFromProgressBar(t,!0);if(e){this.isProgressBarNavigation=!0;let i=this.getAnnotationFrame(t);this.isVideoPaused&&(i!==null?this.playbackFrame=i:this.playbackFrame=e);return}this.currentTool&&this.pluginForTool(this.currentTool).onPointerDown(t)}get isDrawing(){return this.currentTool?this.pluginForTool(this.currentTool).isDrawing:!1}get isVideoPaused(){return this.videoElement.tagName==="VIDEO"?this.videoElement.paused:!0}get hasGlobalOverlays(){return this.globalShapes.length>0}handleMouseMove(t){if(t.preventDefault(),!L(t)){if(this.isMouseDown){let e=this.isProgressBarNavigation?this.frameFromProgressBar(t,!1):null;if(e!==null&&!this.isDrawing){if(e===this.lastNavigatedFrame)return;this.lastNavigatedFrame=e,this.isVideoPaused&&(this.playbackFrame=e);return}else this.hideControls(),this.clearCanvas(),this.hasGlobalOverlays||this.addVideoOverlay(),this.drawShapesOverlay()}else this.redrawFullCanvas();this.currentTool&&this.pluginForTool(this.currentTool).onPointerMove(t)}}getEventX(t){return t.clientX}getEventY(t){return t.clientY}handleMouseUp(t){this.isMouseDown=!1,this.isProgressBarNavigation=!1,this.showControls(),!L(t)&&(this.currentTool&&this.pluginForTool(this.currentTool).onPointerUp(t),this.redrawFullCanvas())}focusOnMediaNode(){this.videoElement.focus()}drawShapesOverlay(){let t={strokeStyle:this.ctx.strokeStyle,fillStyle:this.ctx.fillStyle,lineWidth:this.ctx.lineWidth};for(let e of this.deserialize(this.globalShapes)){this.ctx.strokeStyle=e.strokeStyle,this.ctx.fillStyle=e.fillStyle,this.ctx.lineWidth=e.lineWidth;try{this.pluginForTool(e.type).draw(e)}catch(i){console.error(i)}}for(let e of this.deserialize(this.shapes)){this.ctx.strokeStyle=e.strokeStyle,this.ctx.fillStyle=e.fillStyle,this.ctx.lineWidth=e.lineWidth;try{this.pluginForTool(e.type).draw(e)}catch(i){console.error(i)}}this.ctx.strokeStyle=t.strokeStyle,this.ctx.fillStyle=t.fillStyle,this.ctx.lineWidth=t.lineWidth}clearCanvas(){this.ctx.clearRect(0,0,this.canvasWidth,this.canvasHeight)}frameToDataUrl(){try{this.clearCanvas(),this.addVideoOverlay(),this.addFrameSquareOverlay(),this.drawShapesOverlay();let t=this.canvas.toDataURL("image/png");return this.redrawFullCanvas(),t}catch(t){return console.error(t),null}}redrawFullCanvas(){this.hasGlobalOverlays||(this.clearCanvas(),this.addVideoOverlay()),this.drawShapesOverlay(),this.addFrameSquareOverlay(),this.addProgressBarOverlay()}replaceFrame(t,e){this.timeStack.set(t,this.parseShapes(this.stringifyShapes(e)))}addShapesToFrame(t,e){let i=this.timeStack.get(t)||[];this.timeStack.set(t,[...i,...this.parseShapes(this.stringifyShapes(e))])}setFrameRate(t){var e;(e=this.destructors.find(i=>i.name==="frameRateDetector"))==null||e(),this.fps=t}stringifyShapes(t){return JSON.stringify(t,(e,i)=>e==="image"?i.src:i)}parseShapes(t){return JSON.parse(t,(e,i)=>{if(e==="image"){let s=new Image;return s.src=i,s}return i})}filterNonSerializableShapes(t){return t.filter(e=>e.type!=="image")}saveCurrentFrame(){return{frame:this.playbackFrame,version:1,fps:this.fps,shapes:this.parseShapes(this.stringifyShapes(this.filterNonSerializableShapes(this.shapes)))}}loadAllFrames(t){this.cleanFrameStacks(),t.forEach(e=>{this.timeStack.set(e.frame,e.shapes)})}appendFrames(t){t.forEach(e=>{this.addShapesToFrame(e.frame,e.shapes)})}saveAllFrames(){return Array.from(this.timeStack.keys()).filter(s=>{var a;return(a=this.timeStack.get(s))==null?void 0:a.length}).map(s=>{var a;return{frame:s,fps:this.fps,version:1,shapes:this.filterNonSerializableShapes((a=this.timeStack.get(s))!=null?a:[])}})}getAnnotationFrame(t){var l,r;let e=t.offsetX,i=t.offsetY,s=this.isMobile?10:5;return(r=(l=this.annotatedFrameCoordinates.find(h=>e>=h.x-s&&e<=h.x+s&&i>=h.y-s&&i<=h.y+s))==null?void 0:l.frame)!=null?r:null}get totalFrames(){let t=this.videoElement;return t.tagName!=="VIDEO"?1:Math.ceil(t.duration*this.fps)}frameFromProgressBar(t,e=!0){let i=this.videoElement;if(i.tagName!=="VIDEO")return null;let{x:s,width:a,height:l,y:r}=this.progressBarCoordinates,h=t.offsetX,d=t.offsetY;return e?h>=s&&h<=s+a&&d>=r&&d<=r+l?Math.ceil((h-s)/a*(i.duration*this.fps)):null:h>=s&&h<=s+a?Math.ceil((h-s)/a*(i.duration*this.fps)):null}hasAnnotationsForFrame(t){if(this.globalShapes.length>0)return!0;if(this.timeStack.has(t)){let e=this.timeStack.get(t);return e&&e.length>0}return!1}stopAnnotationsAsVideo(){this.isAnnotationsAsVideoActive=!1}startAnnotationsAsVideo(){this.isAnnotationsAsVideoActive=!0,this.playAnnotationsAsVideo()}playAnnotationsAsVideo(){this.isAnnotationsAsVideoActive&&(this.hasGlobalOverlays||this.clearCanvas(),this.isMobile?this.hasGlobalOverlays||this.addVideoOverlay():this.addVideoOverlay(),this.drawShapesOverlay(),this.addFrameSquareOverlay(),this.addProgressBarOverlay())}};function Yt(o=this.activeTimeFrame){this.ctx.save(),this.ctx.fillStyle="rgba(0, 0, 0, 0.5)";let n=50,t=30,e=20;this.ctx.fillRect(this.canvasWidth-n,this.canvasHeight-t,n,t),this.ctx.fillStyle="white",this.ctx.font=`${e}px sans-serif`,this.ctx.fillText(`${o}`.padStart(3,"0"),this.canvasWidth-40,this.canvasHeight-7),this.ctx.restore()}function Xt(){var s,a,l;let o=this.videoElement;if(o.tagName!=="VIDEO")return;let n=(s=this.videoFrameBuffer)==null?void 0:s.frameNumberFromTime(o.currentTime),t=(l=(a=this.videoFrameBuffer)==null?void 0:a.getFrame(n||0))!=null?l:o,e=t?t.width:o.videoWidth,i=t?t.height:o.videoHeight;this.ctx.drawImage(t,0,0,e,i,0,0,this.canvasWidth,this.canvasHeight)}function jt(){let o=this.videoElement;if(o.tagName!=="VIDEO")return;this.annotatedFrameCoordinates=[];let t=Array.from(this.timeStack.keys()).filter(v=>{var m;return(m=this.timeStack.get(v))==null?void 0:m.length}),e=o.duration*this.fps,{x:i,width:s,height:a,y:l}=this.progressBarCoordinates,r=t.map(v=>Math.ceil(v/e*s));this.ctx.save(),this.ctx.fillStyle="rgba(0, 0, 0, 0.5)",this.ctx.fillRect(i,l,s,a),this.ctx.fillStyle="#F3CE32";let h=this.isMobile?16:8;r.forEach((v,m)=>{this.ctx.beginPath();let f=i+v,x=this.canvasHeight-a/2;this.ctx.fillRect(f-h/2,x-h/2,h,h),this.annotatedFrameCoordinates.push({x:f,y:x,frame:t[m]})});let d=this.playbackFrame,u=Math.ceil(d/e*s)+i;this.ctx.fillStyle="white",this.ctx.beginPath();let c=u,p=this.canvasHeight-a/2;this.ctx.beginPath(),this.ctx.fillRect(c-h/2,p-h/2,h,h),this.ctx.fill(),this.ctx.restore()}I.prototype.initUI=Mt;I.prototype.initCanvas=Bt;I.prototype.addFrameSquareOverlay=Yt;I.prototype.addVideoOverlay=Xt;I.prototype.addProgressBarOverlay=jt;new EventSource("/esbuild").addEventListener("change",()=>location.reload());var T=document.querySelector("video");function qt(){return b(this,null,function*(){let o=window.getComputedStyle(T),n=parseFloat(o.width),t=parseFloat(o.height),e=window.innerHeight-80;if(t>e){let v=n/t,m=e,f=m*v;T.style.width=`${f}px`,T.style.height=`${m}px`}let i=yield fetch(T.currentSrc).then(v=>v.blob()),s=new Promise(v=>{setTimeout(()=>{v(!0)},250),T.addEventListener("loadeddata",()=>{v(!0)},{once:!0})}),a=yield fetch("./frame_29.png").then(v=>b(this,null,function*(){let m=yield v.blob(),f=new Blob([m],{type:"image/png"}),x=new Image,C=new Promise(P=>{x.addEventListener("load",()=>{P(!0)},{once:!0})});return x.src=window.URL.createObjectURL(f),yield C,x}));T.paused||T.pause();let l=new Blob([i],{type:"video/mp4"}),r=new I(T);yield r.setVideoBlob(l,30),yield s,yield r.addReferenceVideoByURL("./mov_bbb_g.mp4"),requestAnimationFrame(()=>{r.setCanvasSize()}),r.enableVideoFrameBuffer(),console.log({tool:r}),r.addShapesToFrame(29,[{type:"image",image:a,x:0,y:0,width:1,height:1,strokeStyle:"red",lineWidth:2,fillStyle:"red"}]),T.paused||T.pause(),setInterval(()=>{r.destroy(),r.init(T)},1e8),setInterval(()=>{console.log(r.saveAllFrames())},1e5);let h=document.getElementById("file"),d=document.getElementById("download"),u=document.getElementById("sample"),c=document.getElementById("video"),p=document.getElementById("ref-video");c.addEventListener("change",v=>b(this,null,function*(){if(!c.files||c.files.length===0)return;let m=prompt("Enter FPS","30");if(!m)return;let f=c.files[0],x=new Blob([f],{type:f.type});yield r.setVideoBlob(x,parseInt(m,10))})),p.addEventListener("change",v=>b(this,null,function*(){if(!p.files||p.files.length===0)return;let m=prompt("Enter FPS","30");if(!m)return;let f=p.files[0],x=new Blob([f],{type:f.type}),C=window.URL.createObjectURL(x);yield r.addReferenceVideoByURL(C,parseInt(m,10),f.type)})),u.addEventListener("click",v=>{v.stopPropagation(),v.preventDefault(),fetch("./annotations-sample.json").then(m=>m.json()).then(m=>{r.loadAllFrames(m),r.redrawFullCanvas()})}),h.addEventListener("change",v=>{if(!h.files||h.files.length===0)return;let m=h.files[0],f=new FileReader;f.onload=x=>{if(!x.target)return;let C=x.target.result,P=JSON.parse(C);confirm("Append to existing annotations?")?r.appendFrames(P):r.loadAllFrames(P),r.redrawFullCanvas()},f.readAsText(m)}),d.addEventListener("click",v=>{v.stopPropagation(),v.preventDefault();let m=r.saveAllFrames(),f=document.createElement("a");f.href=URL.createObjectURL(new Blob([JSON.stringify(m)],{type:"application/json"}));let x=new Date().toISOString().replace(/:/g,"-");f.download=`annotations-${x}.json`,f.click()})})}T.readyState===0?T.addEventListener("loadedmetadata",()=>{requestAnimationFrame(()=>{qt()})},{once:!0}):qt();})(); diff --git a/demo/index.ts b/demo/index.ts index 705164f..efb7e7e 100644 --- a/demo/index.ts +++ b/demo/index.ts @@ -73,15 +73,13 @@ async function initAnnotator() { video.pause(); } - const blobs = new Blob([blob], { type: "video/mp4" }); - - video.src = window.URL.createObjectURL(blobs); - - await loadPromise; + const bl = new Blob([blob], { type: "video/mp4" }); const tool = new SmAnnotate(video); - tool.setFrameRate(30); + await tool.setVideoBlob(bl, 30); + + await loadPromise; await tool.addReferenceVideoByURL("./mov_bbb_g.mp4"); @@ -148,9 +146,8 @@ async function initAnnotator() { const file = videoInput.files[0]; const blobs = new Blob([file], { type: file.type }); - const mediaUrl = window.URL.createObjectURL(blobs); + await tool.setVideoBlob(blobs, parseInt(fps, 10)); - await tool.setVideoUrl(mediaUrl, parseInt(fps, 10)); }); refVideoInput.addEventListener("change", async (e) => { diff --git a/dist/index.js b/dist/index.js index 954bb7f..28fcbd6 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1,4 +1,4 @@ -var Rt=Object.defineProperty,Vt=Object.defineProperties;var Wt=Object.getOwnPropertyDescriptors;var at=Object.getOwnPropertySymbols;var zt=Object.prototype.hasOwnProperty,Nt=Object.prototype.propertyIsEnumerable;var lt=(o,n,t)=>n in o?Rt(o,n,{enumerable:!0,configurable:!0,writable:!0,value:t}):o[n]=t,v=(o,n)=>{for(var t in n||(n={}))zt.call(n,t)&<(o,t,n[t]);if(at)for(var t of at(n))Nt.call(n,t)&<(o,t,n[t]);return o},y=(o,n)=>Vt(o,Wt(n));var E=(o,n,t)=>new Promise((e,i)=>{var s=a=>{try{l(t.next(a))}catch(c){i(c)}},r=a=>{try{l(t.throw(a))}catch(c){i(c)}},l=a=>a.done?e(a.value):Promise.resolve(a.value).then(s,r);l((t=t.apply(o,n)).next())});var T=(o,n)=>{let t=o.target===document.body,e=n.uiContainer.contains(o.target),i=n.playerControlsContainer.contains(o.target),s=n.videoElement.contains(o.target),r=n.canvas.contains(o.target);return e||i||s||r||t};function B(o){return o.pointerType==="touch"&&o.isPrimary===!1}function ht(o,n){if(!T(o,n))return;let t=n.uiContainer.contains(o.target),e=n.playerControlsContainer.contains(o.target);if(t||e)return;let i=n.videoElement;i.tagName==="VIDEO"&&(i.paused||(n.currentTool=null,i.pause(),n.raf(()=>E(this,null,function*(){n.redrawFullCanvas()}))))}function ct(o,n){var t;T(o,n)&&(o.preventDefault(),o.stopPropagation(),o.stopImmediatePropagation(),(t=o.clipboardData)==null||t.setData("application/json",JSON.stringify(n.saveCurrentFrame())))}function dt(o,n){var e;if(!T(o,n))return;o.preventDefault(),o.stopPropagation(),o.stopImmediatePropagation();let t=n.saveCurrentFrame();n.replaceFrame(n.playbackFrame,[]),n.redrawFullCanvas(),(e=o.clipboardData)==null||e.setData("application/json",JSON.stringify(t))}function mt(o,n){if(!T(o,n))return;let t=n.videoElement;t.tagName==="VIDEO"&&(o.key==="ArrowLeft"||o.key==="ArrowRight"?(o.preventDefault(),o.stopPropagation(),o.stopImmediatePropagation(),o.key==="ArrowLeft"?n.prevFrame():o.key==="ArrowRight"&&n.nextFrame()):o.code==="Space"&&(o.preventDefault(),o.stopPropagation(),o.stopImmediatePropagation(),t.paused?t.play().then(()=>{n.redrawFullCanvas()}):(t.pause(),n.raf(()=>{n.redrawFullCanvas()}))))}function ut(o,n){var s,r,l,a,c;if(!T(o,n))return;let t=(r=(s=o.clipboardData)==null?void 0:s.types)!=null?r:[];if(t.includes("application/json"))o.preventDefault(),o.stopPropagation(),o.stopImmediatePropagation();else if(t.includes("Files")){let h=(l=o.clipboardData)==null?void 0:l.files;if(h&&h.length>0){let u=h[0];if(u.type.startsWith("image/")){o.preventDefault(),o.stopPropagation(),o.stopImmediatePropagation();let d=new Image;d.addEventListener("load",()=>{let m=d.naturalWidth/d.naturalHeight,f=.25,g=f/m*n.aspectRatio;n.addShapesToFrame(n.playbackFrame,[{type:"image",image:d,x:0,y:0,width:f,height:g,strokeStyle:"red",fillStyle:"red",lineWidth:2}]),n.redrawFullCanvas(),n.raf(()=>{n.show()}),n.currentTool="move"},{once:!0}),d.src=URL.createObjectURL(u),n.redrawFullCanvas()}}}else if(t.includes("text/plain")){let h=(a=o.clipboardData)==null?void 0:a.getData("text/plain");h&&(o.preventDefault(),o.stopPropagation(),o.stopImmediatePropagation(),n.addShapesToFrame(n.playbackFrame,[{type:"text",text:h,x:.4,y:.4,strokeStyle:n.ctx.strokeStyle,fillStyle:n.ctx.fillStyle,lineWidth:n.ctx.lineWidth}]),n.show(),n.currentTool="move",n.redrawFullCanvas())}else return;let e=(c=o.clipboardData)==null?void 0:c.getData("application/json");if(!e)return;let i=JSON.parse(e);i&&i.shapes&&i.version===1&&(n.addShapesToFrame(n.playbackFrame,i.shapes),n.redrawFullCanvas())}function pt(o,n){let t=document.createElement("button");t.type="button",t.style.margin="5px",t.style.float="right",t.title="Download current frame",t.innerHTML='',n.addEvent(t,"click",()=>{let e=n.frameToDataUrl();if(!e)return;let i=document.createElement("a");i.download=`frame_${String(n.activeTimeFrame).padStart(3,"0")}.png`,i.href=e,i.click()}),n.buttons.push(t),n.playerControlsContainer.appendChild(t)}var vt='',gt='';function ft(o,n){let t=document.createElement("button");t.type="button",t.style.margin="5px",o.muted||o.volume===0?t.innerHTML=gt:t.innerHTML=vt,n.addEvent(o,"volumechange",()=>{o.muted||o.volume===0?t.innerHTML=vt:t.innerHTML=gt}),n.addEvent(t,"click",()=>{o.muted&&(o.muted=!1),o.volume===0?o.volume=1:o.volume=0}),n.buttons.push(t),n.playerControlsContainer.appendChild(t)}var yt='',Ot='';function xt(o,n){let t=document.createElement("button");t.type="button",t.innerHTML=yt,t.style.margin="5px",n.addEvent(o,"play",()=>{t.innerHTML=Ot}),n.addEvent(o,"pause",()=>{t.innerHTML=yt}),n.addEvent(t,"click",()=>{n.withRefVideo(e=>{e.paused&&e.play().then(()=>{n.showButton("compare")})}),o.paused?o.play().then(()=>{n.redrawFullCanvas()}):(o.pause(),n.raf(()=>{n.redrawFullCanvas()}))}),n.buttons.push(t),n.playerControlsContainer.appendChild(t)}function wt(o){return` +var qt=Object.create;var J=Object.defineProperty,Kt=Object.defineProperties,Gt=Object.getOwnPropertyDescriptor,_t=Object.getOwnPropertyDescriptors,$t=Object.getOwnPropertyNames,ct=Object.getOwnPropertySymbols,Jt=Object.getPrototypeOf,mt=Object.prototype.hasOwnProperty,Qt=Object.prototype.propertyIsEnumerable;var ut=Math.pow,dt=(o,n,t)=>n in o?J(o,n,{enumerable:!0,configurable:!0,writable:!0,value:t}):o[n]=t,g=(o,n)=>{for(var t in n||(n={}))mt.call(n,t)&&dt(o,t,n[t]);if(ct)for(var t of ct(n))Qt.call(n,t)&&dt(o,t,n[t]);return o},y=(o,n)=>Kt(o,_t(n));var Zt=(o,n)=>()=>(n||o((n={exports:{}}).exports,n),n.exports);var te=(o,n,t,e)=>{if(n&&typeof n=="object"||typeof n=="function")for(let i of $t(n))!mt.call(o,i)&&i!==t&&J(o,i,{get:()=>n[i],enumerable:!(e=Gt(n,i))||e.enumerable});return o};var ee=(o,n,t)=>(t=o!=null?qt(Jt(o)):{},te(n||!o||!o.__esModule?J(t,"default",{value:o,enumerable:!0}):t,o));var w=(o,n,t)=>new Promise((e,i)=>{var s=l=>{try{a(t.next(l))}catch(h){i(h)}},r=l=>{try{a(t.throw(l))}catch(h){i(h)}},a=l=>l.done?e(l.value):Promise.resolve(l.value).then(s,r);a((t=t.apply(o,n)).next())});var At=Zt((zi,Dt)=>{"use strict";function se(o){for(var n=1/0,t=-1/0,e=0,i=o.length,s;es&&(n=s),ti?i:(e+1)*n,l=o.subarray(r,a),m=se(l),c=Ft(m.min,t),h=Ft(m.max,t),d[e*2]=c,d[e*2+1]=h;return d}function Bt(o,n){return new(new Function(`return Int${o}Array`)())(n)}function re(o,n){var t=o.length,e=1/t,i=o[0].length/2,s=0,r=0,a,l,h=Bt(n,i*2);for(r=0;r1&&(a=re(a,s)),h=a[0].length/2,{length:h,data:a,bits:s}}});var T=(o,n)=>{let t=o.target===document.body,e=n.uiContainer.contains(o.target),i=n.playerControlsContainer.contains(o.target),s=n.videoElement.contains(o.target),r=n.canvas.contains(o.target);return e||i||s||r||t};function D(o){return o.pointerType==="touch"&&o.isPrimary===!1}function pt(o,n){if(!T(o,n))return;let t=n.uiContainer.contains(o.target),e=n.playerControlsContainer.contains(o.target);if(t||e)return;let i=n.videoElement;i.tagName==="VIDEO"&&(i.paused||(n.currentTool=null,i.pause(),n.raf(()=>w(this,null,function*(){n.redrawFullCanvas()}))))}function vt(o,n){var t;T(o,n)&&(o.preventDefault(),o.stopPropagation(),o.stopImmediatePropagation(),(t=o.clipboardData)==null||t.setData("application/json",JSON.stringify(n.saveCurrentFrame())))}function ft(o,n){var e;if(!T(o,n))return;o.preventDefault(),o.stopPropagation(),o.stopImmediatePropagation();let t=n.saveCurrentFrame();n.replaceFrame(n.playbackFrame,[]),n.redrawFullCanvas(),(e=o.clipboardData)==null||e.setData("application/json",JSON.stringify(t))}function gt(o,n){if(!T(o,n))return;let t=n.videoElement;t.tagName==="VIDEO"&&(o.key==="ArrowLeft"||o.key==="ArrowRight"?(o.preventDefault(),o.stopPropagation(),o.stopImmediatePropagation(),o.key==="ArrowLeft"?n.prevFrame():o.key==="ArrowRight"&&n.nextFrame()):o.code==="Space"&&(o.preventDefault(),o.stopPropagation(),o.stopImmediatePropagation(),t.paused?t.play().then(()=>{n.redrawFullCanvas()}):(t.pause(),n.raf(()=>{n.redrawFullCanvas()}))))}function yt(o,n){var s,r,a,l,h;if(!T(o,n))return;let t=(r=(s=o.clipboardData)==null?void 0:s.types)!=null?r:[];if(t.includes("application/json"))o.preventDefault(),o.stopPropagation(),o.stopImmediatePropagation();else if(t.includes("Files")){let c=(a=o.clipboardData)==null?void 0:a.files;if(c&&c.length>0){let m=c[0];if(m.type.startsWith("image/")){o.preventDefault(),o.stopPropagation(),o.stopImmediatePropagation();let d=new Image;d.addEventListener("load",()=>{let u=d.naturalWidth/d.naturalHeight,v=.25,f=v/u*n.aspectRatio;n.addShapesToFrame(n.playbackFrame,[{type:"image",image:d,x:0,y:0,width:v,height:f,strokeStyle:"red",fillStyle:"red",lineWidth:2}]),n.redrawFullCanvas(),n.raf(()=>{n.show()}),n.currentTool="move"},{once:!0}),d.src=URL.createObjectURL(m),n.redrawFullCanvas()}}}else if(t.includes("text/plain")){let c=(l=o.clipboardData)==null?void 0:l.getData("text/plain");c&&(o.preventDefault(),o.stopPropagation(),o.stopImmediatePropagation(),n.addShapesToFrame(n.playbackFrame,[{type:"text",text:c,x:.4,y:.4,strokeStyle:n.ctx.strokeStyle,fillStyle:n.ctx.fillStyle,lineWidth:n.ctx.lineWidth}]),n.show(),n.currentTool="move",n.redrawFullCanvas())}else return;let e=(h=o.clipboardData)==null?void 0:h.getData("application/json");if(!e)return;let i=JSON.parse(e);i&&i.shapes&&i.version===1&&(n.addShapesToFrame(n.playbackFrame,i.shapes),n.redrawFullCanvas())}function xt(o,n){let t=document.createElement("button");t.type="button",t.style.margin="5px",t.style.float="right",t.title="Download current frame",t.innerHTML='',n.addEvent(t,"click",()=>{let e=n.frameToDataUrl();if(!e)return;let i=document.createElement("a");i.download=`frame_${String(n.activeTimeFrame).padStart(3,"0")}.png`,i.href=e,i.click()}),n.buttons.push(t),n.playerControlsContainer.appendChild(t)}var wt='',bt='';function Tt(o,n){let t=document.createElement("button");t.type="button",t.style.margin="5px",o.muted||o.volume===0?t.innerHTML=wt:t.innerHTML=bt,n.addEvent(o,"volumechange",()=>{o.muted||o.volume===0?t.innerHTML=wt:t.innerHTML=bt}),n.addEvent(t,"click",()=>{if(o.muted){o.muted=!1;return}o.volume===0?o.volume=1:o.volume=0}),n.buttons.push(t),n.playerControlsContainer.appendChild(t)}var Ct='',ie='';function St(o,n){let t=document.createElement("button");t.type="button",t.innerHTML=Ct,t.style.margin="5px",n.addEvent(o,"play",()=>{t.innerHTML=ie}),n.addEvent(o,"pause",()=>{t.innerHTML=Ct}),n.addEvent(t,"click",()=>{n.withRefVideo(e=>{e.paused&&e.play().then(()=>{n.showButton("compare")})}),o.paused?o.play().then(()=>{n.redrawFullCanvas()}):(o.pause(),n.raf(()=>{n.redrawFullCanvas()}))}),n.buttons.push(t),n.playerControlsContainer.appendChild(t)}function Et(o){return` ${{"0.25":"\xBC","0.5":"\xBD","0.75":"\xBE",1:"1\xD7"}[String(o)]} - `}function Tt(o,n){let t=[.25,.5,.75,1],e=document.createElement("button"),i=t[t.length-1];e.type="button",o.playbackRate=i,e.innerHTML=wt(i),e.style.margin="5px",n.addEvent(e,"click",()=>{let s=t.indexOf(o.playbackRate),r=s+1>=t.length?0:s+1;o.playbackRate=t[r],e.innerHTML=wt(t[r])}),n.buttons.push(e),n.playerControlsContainer.appendChild(e)}var Yt="#F3CE32";function bt(){var h,u;let o=document.createElement("div");o.style.position="absolute",o.style.top="-40px",o.style.left="0",o.style.zIndex="2",(h=this.canvas.parentNode)==null||h.insertBefore(o,this.canvas);let n=document.createElement("div");n.style.position="relative",n.style.top="0",n.style.left="0",n.style.zIndex="2",(u=this.canvas.parentNode)==null||u.insertBefore(n,this.canvas.nextSibling),this.playerControlsContainer=n;let t=this.videoElement.tagName==="VIDEO"?this.videoElement:null;this.uiContainer=o;let e=(d,m,f=o)=>{let g=document.createElement("button");if(g.type="button",g.innerHTML=d,g.style.margin="5px",f.appendChild(g),this.buttons.push(g),typeof m=="function")this.addEvent(g,"click",m);else{g.dataset.tool=m;let x=()=>{this.currentTool===m?this.currentTool=null:this.currentTool=m};this.addEvent(g,"click",x)}return g},i=()=>{let d=document.createElement("div");return d.style.display="inline-flex",d.style.alignItems="center",d.style.margin="5px",o.appendChild(d),d};e('',"rectangle"),e('',"circle"),e('',"line"),e('',"curve"),e('',"arrow"),e('',"text"),e('',"eraser"),this.isMobile&&(this.hideButton("line"),this.hideButton("circle"),this.hideButton("rectangle"),this.hideButton("eraser")),e('',"move"),e('',"compare"),e('',()=>{this.handleUndo()}),t&&(e('',()=>{this.prevFrame()},this.playerControlsContainer),xt(t,this),e('',()=>{this.nextFrame()},this.playerControlsContainer),ft(t,this),Tt(t,this),pt(t,this));let s=document.createElement("input");s.type="color",s.value=Yt,s.style.margin="5px",this.colorPicker=s,o.appendChild(s);let r=i(),l=document.createElement("input");l.type="number",l.step="1",l.min="1",l.max="10",l.value="5",l.style.margin="5px",r.appendChild(l);let a=d=>{this.ctx.lineWidth=d.target.valueAsNumber,this.focusOnMediaNode()};this.addEvent(l,"input",a);let c=d=>{this.ctx.strokeStyle=d.target.value,this.ctx.fillStyle=d.target.value,this.focusOnMediaNode()};this.addEvent(s,"input",c),this.colorPicker=s,this.strokeSizePicker=l,this.hideButton("compare"),t&&(this.hide(),this.addEvent(t,"pause",()=>{this.show()}),this.addEvent(t,"seek",()=>{t.paused&&this.show()}),this.addEvent(t,"timeupdate",()=>{t.currentTime<2e-4&&!t.paused&&this.startAnnotationsAsVideo()}),this.addEvent(t,"error",()=>{this.hide()}),this.addEvent(t,"stalled",()=>{this.hide()}),this.addEvent(t,"play",()=>{this.hideControls(),this.startAnnotationsAsVideo()}),this.addEvent(document,"copy",d=>{ct(d,this)}),this.addEvent(document,"cut",d=>{dt(d,this)}),this.addEvent(document,"paste",d=>{ut(d,this)}),this.addEvent(document,"click",d=>{ht(d,this)}),this.addEvent(document,"keydown",d=>{mt(d,this)}))}function Ct(){var o;this.canvas=document.createElement("canvas"),this.ctx=this.canvas.getContext("2d"),(o=this.videoElement.parentNode)==null||o.insertBefore(this.canvas,this.videoElement.nextSibling),this.canvas.style.position="absolute",this.canvas.style.backgroundColor="transparent",this.canvas.style.top="0",this.canvas.style.left="0",this.canvas.style.zIndex="1",this.addEvent(this.canvas,"pointerdown",this.handleMouseDown),this.addEvent(this.canvas,"pointermove",this.handleMouseMove),this.addEvent(this.canvas,"pointerup",this.handleMouseUp),this.addEvent(this.canvas,"pointercancel",this.handleMouseUp),this.addEvent(window,"resize",this.setCanvasSize),this.addEvent(document,"keydown",this.onKeyDown)}var A=class{constructor(){this.destructors=[];this.isDestroyed=!1;this.activeTimeFrame=1;this.globalShapes=[];this.timeStack=new Map;this.undoTimeStack=new Map}cleanFrameStacks(){this.timeStack.clear(),this.undoTimeStack.clear()}destroy(){this.destructors.forEach(n=>n()),this.destructors=[],this.globalShapes=[],this.cleanFrameStacks()}raf(n){return requestAnimationFrame(n)}addEvent(n,t,e){let i=s=>{this.isDestroyed||e(s)};n.addEventListener(t,i),this.destructors.push(()=>{n.removeEventListener(t,i)})}addProgressBarOverlay(){throw new Error("Method not implemented.")}initUI(){throw new Error("Method not implemented.")}initCanvas(){throw new Error("Method not implemented.")}addFrameSquareOverlay(n=this.activeTimeFrame){throw new Error("Method not implemented.")}addVideoOverlay(){throw new Error("Method not implemented.")}withRefVideo(n){this.isDestroyed||this.referenceVideoElement&&n(this.referenceVideoElement)}withVideo(n){if(this.isDestroyed)return;let t=this.videoElement;!t||t.tagName!=="VIDEO"||n(t)}};var p=class{constructor(n){this.startX=0;this.startY=0;this.isDrawing=!1;this.annotationTool=n}get ctx(){return this.annotationTool.ctx}onDeactivate(){}onActivate(){}reset(){this.startX=0,this.startY=0,this.isDrawing=!1}save(n){this.annotationTool.addShape(n)}};var H=class extends p{constructor(){super(...arguments);this.name="rectangle"}move(t,e,i){return t.x+=e,t.y+=i,t}normalize(t,e,i){return y(v({},t),{x:t.x/e,y:t.y/i,width:t.width/e,height:t.height/i})}onPointerDown(t){let{x:e,y:i}=this.annotationTool.getRelativeCoords(t);this.startX=e,this.startY=i,this.isDrawing=!0}onPointerMove(t){if(!this.isDrawing)return;let{x:e,y:i}=this.annotationTool.getRelativeCoords(t);this.drawRectangle(this.startX,this.startY,e-this.startX,i-this.startY)}onPointerUp(t){if(!this.isDrawing)return;let{x:e,y:i}=this.annotationTool.getRelativeCoords(t);this.save({type:"rectangle",x:this.startX,y:this.startY,width:e-this.startX,height:i-this.startY,strokeStyle:this.ctx.strokeStyle,fillStyle:this.ctx.fillStyle,lineWidth:this.ctx.lineWidth}),this.drawRectangle(this.startX,this.startY,e-this.startX,i-this.startY),this.isDrawing=!1}drawRectangle(t,e,i,s){this.ctx.beginPath(),this.ctx.rect(t,e,i,s),this.ctx.stroke()}draw(t){this.drawRectangle(t.x,t.y,t.width,t.height)}};var L=class extends p{constructor(){super(...arguments);this.name="circle"}move(t,e,i){return t.x+=e,t.y+=i,t}normalize(t,e,i){return y(v({},t),{x:t.x/e,y:t.y/i,radius:t.radius/e})}onPointerDown(t){let{x:e,y:i}=this.annotationTool.getRelativeCoords(t);this.startX=e,this.startY=i,this.isDrawing=!0}onPointerMove(t){if(!this.isDrawing)return;let{x:e,y:i}=this.annotationTool.getRelativeCoords(t),s=Math.sqrt(Math.pow(e-this.startX,2)+Math.pow(i-this.startY,2));this.drawCircle(this.startX,this.startY,s)}onPointerUp(t){if(!this.isDrawing)return;let{x:e,y:i}=this.annotationTool.getRelativeCoords(t),s=Math.sqrt(Math.pow(e-this.startX,2)+Math.pow(i-this.startY,2));this.save({type:"circle",x:this.startX,y:this.startY,radius:s,strokeStyle:this.ctx.strokeStyle,fillStyle:this.ctx.fillStyle,lineWidth:this.ctx.lineWidth}),this.drawCircle(this.startX,this.startY,s),this.isDrawing=!1}drawCircle(t,e,i){this.ctx.beginPath(),this.ctx.arc(t,e,i,0,2*Math.PI),this.ctx.stroke()}draw(t){this.drawCircle(t.x,t.y,t.radius)}};var R=class{constructor(n,t){this.x=n;this.y=t}distanceToLine(n,t){let e=t.x-n.x,i=t.y-n.y,s=Math.abs(i*this.x-e*this.y+t.x*n.y-t.y*n.x),r=Math.sqrt(i*i+e*e);return s/r}};function V(o,n){if(o.length<=2)return o;let t=o[0],e=o[o.length-1],i=-1,s=0;for(let r=1;rs&&(i=r,s=l)}if(s>n){let r=V(o.slice(0,i+1),n),l=V(o.slice(i),n);return r.slice(0,r.length-1).concat(l)}else return[t,e]}var W=class extends p{constructor(){super(...arguments);this.name="curve";this.curvePoints=[]}move(t,e,i){return t.points=t.points.map(s=>({x:s.x+e,y:s.y+i})),t}normalize(t,e,i){return y(v({},t),{points:t.points.map(s=>({x:s.x/e,y:s.y/i}))})}draw(t){this.drawCurve(t)}reset(){super.reset(),this.curvePoints=[]}onPointerDown(t){if(this.isDrawing)return;let{x:e,y:i}=this.annotationTool.getRelativeCoords(t);this.curvePoints=[],this.startX=e,this.startY=i,this.isDrawing=!0,this.curvePoints.push({x:e,y:i})}onPointerMove(t){if(!this.isDrawing)return;let{x:e,y:i}=this.annotationTool.getRelativeCoords(t);this.curvePoints.push({x:e,y:i}),this.drawCurve({points:this.curvePoints,lineWidth:this.ctx.lineWidth})}onPointerUp(t){if(!this.isDrawing)return;let{x:e,y:i}=this.annotationTool.getRelativeCoords(t);this.curvePoints.push({x:e,y:i});let s=this.curvePoints.map(h=>new R(h.x,h.y)),c={type:"curve",points:V(s,2).map(h=>({x:h.x,y:h.y})),strokeStyle:this.ctx.strokeStyle,fillStyle:this.ctx.fillStyle,lineWidth:this.ctx.lineWidth};this.save(c),this.curvePoints=[],this.isDrawing=!1}drawCurve(t){if(t.points.length===2&&t.points[0].x===t.points[1].x&&t.points[0].y===t.points[1].y){let e=t.lineWidth/4,i=0,s=2*Math.PI;this.ctx.beginPath(),this.ctx.arc(t.points[0].x,t.points[0].y,e,i,s),this.ctx.stroke()}else{this.ctx.beginPath(),this.ctx.moveTo(t.points[0].x,t.points[0].y);for(let e=1;e0){let s=this.annotationTool.globalShapes[0];if(s.type==="compare"){let r=this.annotationTool.deserialize([s])[0];this.draw(r),this.annotationTool.addFrameSquareOverlay()}}return}let{x:e}=this.annotationTool.getRelativeCoords(t);this.comparisonLine=e;let i={type:"compare",strokeStyle:this.ctx.strokeStyle,fillStyle:this.ctx.fillStyle,lineWidth:this.ctx.lineWidth,x:e};this.draw(i),this.drawDelimiter(i)}onPointerUp(){this.isDrawing&&(this.save({type:"compare",strokeStyle:this.ctx.strokeStyle,fillStyle:this.ctx.fillStyle,lineWidth:this.ctx.lineWidth,disabled:!1,x:this.comparisonLine}),this.isDrawing=!1)}removePreviousCompare(){this.annotationTool.globalShapes=this.annotationTool.globalShapes.filter(t=>t.type!=="compare")}disablePreviousCompare(){this.annotationTool.globalShapes=this.annotationTool.globalShapes.map(t=>t.type==="compare"?y(v({},t),{disabled:!0}):t)}save(t){this.removePreviousCompare();let e=this.annotationTool.serialize([t])[0];e.x<.05||e.x>.95||this.annotationTool.addGlobalShape(e)}drawDelimiter(t){this.ctx.beginPath(),this.ctx.moveTo(t.x,0),this.ctx.lineTo(t.x,this.annotationTool.canvasWidth),this.ctx.stroke()}drawShape(t){var Z,tt,et,it,nt,ot,st,rt;let e=this.annotationTool.videoElement,i=this.annotationTool.referenceVideoElement;if(!e||!i)return;let s=this.ctx.globalAlpha,r=this.annotationTool.canvasWidth,l=this.annotationTool.canvasHeight,a=t.x,c=i.videoHeight-e.videoHeight,h=i.videoWidth-e.videoWidth,u=this.annotationTool.isMobile;this.ctx.globalAlpha=this.leftOpacity;let d=(tt=(Z=this.annotationTool.referenceVideoFrameBuffer)==null?void 0:Z.frameNumberFromTime(e.currentTime))!=null?tt:1,m=d;if(h>e.videoWidth&&c>e.videoHeight&&!this.annotationTool.isMobile){let w=(ot=(nt=this.annotationTool.referenceVideoFrameBuffer)==null?void 0:nt.getFrameNumberBySignature((it=(et=this.annotationTool.videoFrameBuffer)==null?void 0:et.getHistogram(d))!=null?it:null,d))!=null?ot:d,P=Math.abs(d-w);P>=1&&P<=3&&(m=w)}let g=(st=this.annotationTool.referenceVideoFrameBuffer)==null?void 0:st.getFrame(m),x=(rt=this.annotationTool.videoFrameBuffer)==null?void 0:rt.getFrame(d);if(u){this.ctx.imageSmoothingQuality="low";let w=a/r,P=a;this.ctx.drawImage(x!=null?x:e,0,0,w*e.videoWidth,e.videoHeight,0,0,P,l)}else{let w=x?x.width:e.videoWidth,P=x?x.height:e.videoHeight;this.ctx.drawImage(x!=null?x:e,0,0,w,P,0,0,r,l)}this.ctx.globalAlpha=this.rightOpacity;let b=0,F=0,At=e.videoWidth/e.videoHeight,Ht=i.videoWidth/i.videoHeight,q=Math.abs(At-Ht)>.1,k=10,J=Math.abs(c)>k,D=e.videoWidth,K=e.videoHeight,S=0;if(h<-k)if(q){let w=e.videoWidth/r;S=Math.abs(h/2),S=S/w,S<=k&&(S=0)}else D=i.videoWidth;else h>k&&(D=i.videoWidth);if(c===0)b=0;else if(c>0)q?(b=c/2,b<=k&&(b=0)):K=J?i.videoHeight:e.videoHeight;else if(!q)K=J?i.videoHeight:e.videoHeight;else{F=Math.abs(c/2);let w=e.videoHeight/l;F=F/w,F<=k&&(F=0)}let _=a-S,Q=r-_,Lt=Q/r*D;g?(u&&(this.ctx.imageSmoothingQuality="low"),this.ctx.drawImage(g,_/r*D,b,Lt,K,_+S,F,Q,l)):console.log("no video data",d),this.ctx.globalAlpha=s}draw(t){if(t.disabled)return;let e=this.annotationTool.videoElement,i=this.annotationTool.referenceVideoElement;!e||!i||this.drawShape(t)}};var St=[H,L,z,N,O,Y,W,X,U,j];function Et(o,n){let t,e,i,s=[],r=!0;function l(h,u){let d=Math.abs(u.mediaTime-t),m=Math.abs(u.presentedFrames-e),f=d/m;f&&f<1&&r&&s.length<50&&o.playbackRate===1&&document.hasFocus()&&(s.push(f),i=Math.round(1/c()),n(i,s.length*2)),r=!0,t=u.mediaTime,e=u.presentedFrames,o.requestVideoFrameCallback(l)}o.requestVideoFrameCallback(l);let a=()=>{s.pop(),r=!1};o.addEventListener("seeked",a);function c(){return s.reduce((h,u)=>h+u)/s.length}return()=>{o.removeEventListener("seeked",a)}}function It(o,n,t){return .299*o+.587*n+.114*t}var Ut=0,G=class extends Array{constructor(){super(...arguments);this.id=Ut++}};function Ft(o){let n=o.width,t=o.height,e=new Array(n*t),i=new G,s=0;for(let r=0;rMath.max(o.id,n.id)+"-"+Math.min(o.id,n.id);function kt(o,n){let t=jt(o,n);if($.has(t))return $.get(t);let e=0;for(let s=0;sn.close()),this.frames.clear()}tick(n,t){if(this.setCanvasSize(),t.expectedDisplayTime-performance.now()>10&&console.log("looks like frame is not yet rendered"),this.isDestroyed)return!1;if(this.seenFrames>=this.totalFrames){if(this.autoHide)try{this.video.paused||this.video.pause(),this.video.style.display="none"}catch(l){}return!1}if(this.video.videoWidth===0||this.video.videoHeight===0)return!0;let i=this.video,s=this.frameNumberFromTime(t.mediaTime);if(!Math.max(1,t.presentedFrames>this.totalFrames?t.presentedFrames%this.totalFrames:t.presentedFrames))throw new Error("expectedFrame is 0");if(this.hasFrame(s))this.seenFrames++;else{this.ctx.drawImage(i,0,0,this.width,this.height,0,0,this.width,this.height);let l=this.ctx.getImageData(0,0,this.canvas.width,this.canvas.height);createImageBitmap(l,0,0,this.width,this.height).then(a=>E(this,null,function*(){this.setFrame(s,a),this.isMobile||this.setHistogram(s,this.toHistogram(a))}))}return!0}addRequestFrameCallback(){this.isDestroyed||this.video.requestVideoFrameCallback((n,t)=>{this.tick(n,t)&&this.addRequestFrameCallback()})}createCanvas(){this.canvas=document.createElement("canvas"),this.ctx=this.canvas.getContext("2d",{willReadFrequently:!0,alpha:!1})}setCanvasSize(){this.isCanvasSizeSet||(this.canvas.width=this.video.videoWidth,this.canvas.height=this.video.videoHeight,this.isCanvasSizeSet=!0)}get width(){return this.video.videoWidth}get height(){return this.video.videoHeight}hasFrame(n){return this.frames.has(n)}getFrame(n){return this.frames.has(n)?this.frames.get(n):null}getFrameNumberBySignature(n,t){if(!n)return t;let e=0,i=t;return[t-3,t-2,t-1,t,t+1,t+2,t+3].filter(r=>r>0&&r<=this.totalFrames).forEach(r=>{let l=this.getHistogram(r);if(l){let a=kt(n,l);a>e&&(e=a,i=r)}}),i}setFrame(n,t){this.frames.set(n,t)}setHistogram(n,t){this.histograms.set(n,t)}getHistogram(n){var t;return(t=this.histograms.get(n))!=null?t:null}get totalFrames(){return Math.round(this.video.duration*this.fps)}frameNumberFromTime(n){return Math.max(1,Math.round(n*this.fps))}};var qt=window.devicePixelRatio||1,Pt=25,C=class extends A{constructor(t){super();this.referenceVideoFrameBuffer=null;this.videoFrameBuffer=null;this.isMouseDown=!1;this.buttons=[];this.plugins=[];this.annotatedFrameCoordinates=[];this.fps=Pt;this.plannedFn=null;this.ct=0;this.isCanvasInitialized=!1;this.enforcedCanvasSize=null;this.lastNavigatedFrame=0;this.isProgressBarNavigation=!1;this.isAnnotationsAsVideoActive=!1;this.plugins=St.map(e=>new e(this)),this.init(t)}prevFrame(){let t=this.playbackFrame,e=Math.max(1,t-1);e===this.playbackFrame?this.playbackFrame=this.totalFrames-1:this.playbackFrame=e}nextFrame(){let t=this.playbackFrame,e=Math.min(this.totalFrames,t+1);e===this.totalFrames?this.playbackFrame=1:this.playbackFrame=e}addGlobalShape(t){this.globalShapes.push(t)}get selectedColor(){return this.colorPicker.value}get selectedStrokeSize(){return this.strokeSizePicker.valueAsNumber}get currentTool(){return this._currentTool}set currentTool(t){let e=this._currentTool;e&&(this.getButtonForTool(e).classList.remove("active"),this.pluginForTool(e).onDeactivate()),this._currentTool=t,this.canvas.style.cursor=t?"pointer":"default",t&&(this.getButtonForTool(t).classList.add("active"),this.pluginForTool(t).onActivate())}enableFrameRateDetection(){if(this.destructors.find(i=>i.name==="frameRateDetector"))return;let t=this.videoElement;if(t.tagName==="IMG")return;let e=Et(t,i=>{this.fps=i});Object.defineProperty(e,"name",{value:"frameRateDetector"}),this.destructors.push(e)}timeToFrame(t){return Math.max(1,Math.round(t*this.fps))}get playbackFrame(){return this.videoElement instanceof HTMLImageElement?1:this.timeToFrame(this.videoElement.currentTime)}set playbackFrame(t){if(this.videoElement instanceof HTMLImageElement)return;let e=t/this.fps;this.videoElement.currentTime=e,this.rvf(()=>{this.show()})}rvf(t){this.plannedFn=t}get canvasWidth(){var t,e;return(e=(t=this.enforcedCanvasSize)==null?void 0:t.width)!=null?e:0}get canvasHeight(){var t,e;return(e=(t=this.enforcedCanvasSize)==null?void 0:t.height)!=null?e:0}get aspectRatio(){return this.canvasWidth/this.canvasHeight}get isMobile(){return window.innerWidth<960}get progressBarCoordinates(){let t=this.isMobile?30:10,e=5,i=55,s=this.canvasWidth-e-i,r=e,l=this.canvasHeight-t;return{x:r,y:l,width:s,height:t}}get shapes(){return this.timeStack.has(this.activeTimeFrame)||this.timeStack.set(this.activeTimeFrame,[]),this.timeStack.get(this.activeTimeFrame)}set shapes(t){this.timeStack.set(this.activeTimeFrame,t)}get undoStack(){return this.undoTimeStack.has(this.activeTimeFrame)||this.undoTimeStack.set(this.activeTimeFrame,[]),this.undoTimeStack.get(this.activeTimeFrame)}set undoStack(t){this.undoTimeStack.set(this.activeTimeFrame,t)}get pixelRatio(){return qt}setVideoUrl(i){return E(this,arguments,function*(t,e=this.fps){if(this.videoElement instanceof HTMLImageElement)return;let s=this.videoElement;s.src=t,yield this.videoElement.load(),this.setFrameRate(e),this.videoFrameBuffer&&(this.videoFrameBuffer.destroy(),this.videoFrameBuffer=new I(s,e,!1),this.videoFrameBuffer.isMobile=this.isMobile),this.setCanvasSize()})}enableVideoFrameBuffer(){this.videoElement instanceof HTMLImageElement||(this.videoFrameBuffer=new I(this.videoElement,this.fps,!1),this.videoFrameBuffer.isMobile=this.isMobile)}hide(){this.stopAnnotationsAsVideo(),this.hideControls(),this.hideCanvas()}showControls(){this.uiContainer.style.display="block"}hideControls(){this.uiContainer.style.display="none"}showCanvas(){this.canvas.style.display="block"}hideCanvas(){this.canvas.style.display="none"}updateActiveTimeFrame(t=void 0){this.activeTimeFrame=t?this.timeToFrame(t):this.playbackFrame}show(){this.stopAnnotationsAsVideo(),this.updateActiveTimeFrame(),this.showCanvas(),this.showControls(),this.redrawFullCanvas()}setCanvasSettings(){this.ctx.strokeStyle=this.selectedColor,this.ctx.fillStyle=this.selectedColor,this.ctx.lineWidth=this.selectedStrokeSize}pluginForTool(t){if(this.isDestroyed)throw new Error("AnnotationTool is destroyed");let e=this.plugins.find(i=>i.name===t);if(!e)throw new Error(`No plugin found for tool ${t}`);return e}getButtonForTool(t){return this.buttons.find(e=>e.dataset.tool===t)}bindContext(){this.handleMouseDown=this.handleMouseDown.bind(this),this.handleMouseMove=this.handleMouseMove.bind(this),this.handleMouseUp=this.handleMouseUp.bind(this),this.setCanvasSize=this.setCanvasSize.bind(this),this.onKeyDown=this.onKeyDown.bind(this)}initProperties(){this.isDestroyed=!1,this.isProgressBarNavigation=!1,this.shapes=[],this.globalShapes=[],this.currentTool=this.isMobile?null:"curve"}setVideoStyles(){this.videoElement.style.objectFit="cover",this.videoElement.style.objectPosition="left top"}get frameCallbackSupported(){return"requestVideoFrameCallback"in HTMLVideoElement.prototype}initFrameCounter(){if(!this.frameCallbackSupported){setTimeout(()=>{var t;(t=this.plannedFn)==null||t.call(this),this.plannedFn=null,this.initFrameCounter(),this.updateActiveTimeFrame(),this.playAnnotationsAsVideo()},1e3/this.fps);return}this.withVideo(t=>{t.requestVideoFrameCallback((e,i)=>{var s,r;this.isCanvasInitialized||this._setCanvasSize(),(s=this.videoFrameBuffer)==null||s.tick(e,i),(r=this.plannedFn)==null||r.call(this),this.plannedFn=null,this.raf(()=>{this.initFrameCounter(),this.updateActiveTimeFrame(i.mediaTime),this.playAnnotationsAsVideo()})})})}init(t){this.videoElement=t,this.setVideoStyles(),this.initFrameCounter(),this.bindContext(),this.initCanvas(),this.initUI(),this.initProperties(),this.setCanvasSize()}onKeyDown(t){(t.ctrlKey||t.metaKey)&&t.key.toLowerCase()==="z"&&this.handleUndo()}removeLastShape(){this.shapes.pop(),this.redrawFullCanvas()}handleUndo(){this.undoStack.length>0&&(this.shapes=this.undoStack.pop(),this.redrawFullCanvas())}destroy(){var s,r,l,a,c,h,u,d;if(this.isDestroyed)return;super.destroy(),this.stopAnnotationsAsVideo(),this._currentTool=null,this.plugins.forEach(m=>m.reset()),this.annotatedFrameCoordinates=[],this.setFrameRate(Pt);let t=this.strokeSizePicker.parentElement;if((s=t==null?void 0:t.parentNode)==null||s.removeChild(t),this.referenceVideoElement){let m=this.referenceVideoElement.parentElement;(r=m==null?void 0:m.parentNode)==null||r.removeChild(m),this.referenceVideoElement=null}let e=this.colorPicker.parentElement;(l=e==null?void 0:e.parentNode)==null||l.removeChild(e),this.buttons.forEach(m=>{var f;(f=m.parentNode)==null||f.removeChild(m)}),this.buttons=[],(a=this.uiContainer.parentNode)==null||a.removeChild(this.uiContainer),(c=this.canvas.parentNode)==null||c.removeChild(this.canvas),(h=this.playerControlsContainer.parentElement)==null||h.removeChild(this.playerControlsContainer),["strokeSizePicker","colorPicker","uiContainer","playerControlsContainer","canvas","ctx","videoElement"].forEach(m=>{delete this[m]}),this.activeTimeFrame=0,this.isDestroyed=!0,(u=this.referenceVideoFrameBuffer)==null||u.destroy(),this.referenceVideoFrameBuffer=null,(d=this.videoFrameBuffer)==null||d.destroy(),this.videoFrameBuffer=null}_setCanvasSize(){let t=getComputedStyle(this.videoElement),e=parseInt(t.width,10),i=this.videoElement,s=i.videoWidth/i.videoHeight;if(isNaN(e)||!i.videoWidth||!i.videoHeight)return this.isCanvasInitialized=!1,this.setCanvasSettings(),!1;let r=Math.min(e,i.videoWidth),l=Math.floor(r/s);return i.style.width=`${r}px`,i.style.height=`${l}px`,this.isCanvasInitialized=i.videoWidth>0&&i.videoHeight>0,this.canvas.width=r*this.pixelRatio,this.canvas.height=l*this.pixelRatio,this.canvas.style.width=`${r}px`,this.canvas.style.height=`${l}px`,this.enforcedCanvasSize={width:r,height:l},this.ctx.scale(this.pixelRatio,this.pixelRatio),this.setCanvasSettings(),!0}setCanvasSize(){this._setCanvasSize()&&(this.syncVideoSizes(),this.redrawFullCanvas())}addShape(t){let e=this.serialize([t])[0];this.undoStack.push([...this.shapes]),this.shapes.push(e)}get msPerFrame(){return this.fps/1e3}syncVideoSizes(){this.withRefVideo(t=>{let i=this.videoElement.getBoundingClientRect();t.style.position="fixed",t.style.top=`${i.top}px`,t.style.left=`${i.left}px`})}addReferenceVideoByURL(s){return E(this,arguments,function*(t,e=this.fps,i="video/mp4"){var c;let r=yield fetch(t).then(h=>h.blob()),l=new Blob([r],{type:i}),a=window.URL.createObjectURL(l);this.referenceVideoElement?((c=this.referenceVideoFrameBuffer)==null||c.destroy(),this.referenceVideoFrameBuffer=new I(this.referenceVideoElement,e),this.referenceVideoFrameBuffer.isMobile=this.isMobile,this.referenceVideoFrameBuffer.start()):(this.referenceVideoElement=document.createElement("video"),this.withRefVideo(h=>{this.isMobile?(h.style.zIndex="2",h.style.display="block",h.style.top="0",h.style.left="0",h.style.opacity="0.25",h.style.width="20px",h.style.height="15px"):(h.style.zIndex="-1",h.style.display="none",h.style.width="100px",h.style.height="70px"),h.style.objectFit="cover",h.style.objectPosition="left top",h.muted=!0,h.volume=0,h.playsInline=!0,h.autoplay=!1,h.controls=!1,h.loop=!0,this.videoElement.after(h),this.referenceVideoFrameBuffer=new I(h,e),this.referenceVideoFrameBuffer.isMobile=this.isMobile,this.referenceVideoFrameBuffer.start()}),this.syncVideoSizes()),this.referenceVideoElement.src=a,this.referenceVideoElement.play().then(()=>{this.showButton("compare")}).catch(()=>{this.hideButton("compare")})})}hideButton(t){let e=this.getButtonForTool(t);e.style.display="none"}showButton(t){let e=this.getButtonForTool(t);e.style.display=""}addSingletonShape(t){let e=this.serialize([t])[0],i=this.shapes.filter(s=>s.type!==t.type);this.replaceFrame(this.playbackFrame,[...i,e])}serialize(t=this.shapes){let e=this.canvasWidth,i=this.canvasHeight;return t.map(s=>this.pluginForTool(s.type).normalize(s,e,i))}deserialize(t){let e=1/this.canvasWidth,i=1/this.canvasHeight;return t.map(s=>this.pluginForTool(s.type).normalize(s,e,i))}getRelativeCoords(t){let e=this.canvas.getBoundingClientRect();return{x:this.getEventX(t)-e.left,y:this.getEventY(t)-e.top}}handleMouseDown(t){if(t.preventDefault(),this.isMouseDown=!0,B(t))return;let e=this.frameFromProgressBar(t,!0);if(e){this.isProgressBarNavigation=!0;let i=this.getAnnotationFrame(t);this.isVideoPaused&&(i!==null?this.playbackFrame=i:this.playbackFrame=e);return}this.currentTool&&this.pluginForTool(this.currentTool).onPointerDown(t)}get isDrawing(){return this.currentTool?this.pluginForTool(this.currentTool).isDrawing:!1}get isVideoPaused(){return this.videoElement.tagName==="VIDEO"?this.videoElement.paused:!0}get hasGlobalOverlays(){return this.globalShapes.length>0}handleMouseMove(t){if(t.preventDefault(),!B(t)){if(this.isMouseDown){let e=this.isProgressBarNavigation?this.frameFromProgressBar(t,!1):null;if(e!==null&&!this.isDrawing){if(e===this.lastNavigatedFrame)return;this.lastNavigatedFrame=e,this.isVideoPaused&&(this.playbackFrame=e);return}else this.hideControls(),this.clearCanvas(),this.hasGlobalOverlays||this.addVideoOverlay(),this.drawShapesOverlay()}else this.redrawFullCanvas();this.currentTool&&this.pluginForTool(this.currentTool).onPointerMove(t)}}getEventX(t){return t.clientX}getEventY(t){return t.clientY}handleMouseUp(t){this.isMouseDown=!1,this.isProgressBarNavigation=!1,this.showControls(),!B(t)&&(this.currentTool&&this.pluginForTool(this.currentTool).onPointerUp(t),this.redrawFullCanvas())}focusOnMediaNode(){this.videoElement.focus()}drawShapesOverlay(){let t={strokeStyle:this.ctx.strokeStyle,fillStyle:this.ctx.fillStyle,lineWidth:this.ctx.lineWidth};for(let e of this.deserialize(this.globalShapes)){this.ctx.strokeStyle=e.strokeStyle,this.ctx.fillStyle=e.fillStyle,this.ctx.lineWidth=e.lineWidth;try{this.pluginForTool(e.type).draw(e)}catch(i){console.error(i)}}for(let e of this.deserialize(this.shapes)){this.ctx.strokeStyle=e.strokeStyle,this.ctx.fillStyle=e.fillStyle,this.ctx.lineWidth=e.lineWidth;try{this.pluginForTool(e.type).draw(e)}catch(i){console.error(i)}}this.ctx.strokeStyle=t.strokeStyle,this.ctx.fillStyle=t.fillStyle,this.ctx.lineWidth=t.lineWidth}clearCanvas(){this.ctx.clearRect(0,0,this.canvasWidth,this.canvasHeight)}frameToDataUrl(){try{this.clearCanvas(),this.addVideoOverlay(),this.addFrameSquareOverlay(),this.drawShapesOverlay();let t=this.canvas.toDataURL("image/png");return this.redrawFullCanvas(),t}catch(t){return console.error(t),null}}redrawFullCanvas(){this.hasGlobalOverlays||(this.clearCanvas(),this.addVideoOverlay()),this.drawShapesOverlay(),this.addFrameSquareOverlay(),this.addProgressBarOverlay()}replaceFrame(t,e){this.timeStack.set(t,this.parseShapes(this.stringifyShapes(e)))}addShapesToFrame(t,e){let i=this.timeStack.get(t)||[];this.timeStack.set(t,[...i,...this.parseShapes(this.stringifyShapes(e))])}setFrameRate(t){var e;(e=this.destructors.find(i=>i.name==="frameRateDetector"))==null||e(),this.fps=t}stringifyShapes(t){return JSON.stringify(t,(e,i)=>e==="image"?i.src:i)}parseShapes(t){return JSON.parse(t,(e,i)=>{if(e==="image"){let s=new Image;return s.src=i,s}return i})}filterNonSerializableShapes(t){return t.filter(e=>e.type!=="image")}saveCurrentFrame(){return{frame:this.playbackFrame,version:1,fps:this.fps,shapes:this.parseShapes(this.stringifyShapes(this.filterNonSerializableShapes(this.shapes)))}}loadAllFrames(t){this.cleanFrameStacks(),t.forEach(e=>{this.timeStack.set(e.frame,e.shapes)})}appendFrames(t){t.forEach(e=>{this.addShapesToFrame(e.frame,e.shapes)})}saveAllFrames(){return Array.from(this.timeStack.keys()).filter(s=>{var r;return(r=this.timeStack.get(s))==null?void 0:r.length}).map(s=>{var r;return{frame:s,fps:this.fps,version:1,shapes:this.filterNonSerializableShapes((r=this.timeStack.get(s))!=null?r:[])}})}getAnnotationFrame(t){var l,a;let e=t.offsetX,i=t.offsetY,s=this.isMobile?10:5;return(a=(l=this.annotatedFrameCoordinates.find(c=>e>=c.x-s&&e<=c.x+s&&i>=c.y-s&&i<=c.y+s))==null?void 0:l.frame)!=null?a:null}get totalFrames(){let t=this.videoElement;return t.tagName!=="VIDEO"?1:Math.ceil(t.duration*this.fps)}frameFromProgressBar(t,e=!0){let i=this.videoElement;if(i.tagName!=="VIDEO")return null;let{x:s,width:r,height:l,y:a}=this.progressBarCoordinates,c=t.offsetX,h=t.offsetY;return e?c>=s&&c<=s+r&&h>=a&&h<=a+l?Math.ceil((c-s)/r*(i.duration*this.fps)):null:c>=s&&c<=s+r?Math.ceil((c-s)/r*(i.duration*this.fps)):null}hasAnnotationsForFrame(t){if(this.globalShapes.length>0)return!0;if(this.timeStack.has(t)){let e=this.timeStack.get(t);return e&&e.length>0}return!1}stopAnnotationsAsVideo(){this.isAnnotationsAsVideoActive=!1}startAnnotationsAsVideo(){this.isAnnotationsAsVideoActive=!0,this.playAnnotationsAsVideo()}playAnnotationsAsVideo(){this.isAnnotationsAsVideoActive&&(this.hasGlobalOverlays||this.clearCanvas(),this.isMobile?this.hasGlobalOverlays||this.addVideoOverlay():this.addVideoOverlay(),this.drawShapesOverlay(),this.addFrameSquareOverlay(),this.addProgressBarOverlay())}};function Mt(o=this.activeTimeFrame){this.ctx.save(),this.ctx.fillStyle="rgba(0, 0, 0, 0.5)";let n=50,t=30,e=20;this.ctx.fillRect(this.canvasWidth-n,this.canvasHeight-t,n,t),this.ctx.fillStyle="white",this.ctx.font=`${e}px sans-serif`,this.ctx.fillText(`${o}`.padStart(3,"0"),this.canvasWidth-40,this.canvasHeight-7),this.ctx.restore()}function Dt(){var s,r,l;let o=this.videoElement;if(o.tagName!=="VIDEO")return;let n=(s=this.videoFrameBuffer)==null?void 0:s.frameNumberFromTime(o.currentTime),t=(l=(r=this.videoFrameBuffer)==null?void 0:r.getFrame(n||0))!=null?l:o,e=t?t.width:o.videoWidth,i=t?t.height:o.videoHeight;this.ctx.drawImage(t,0,0,e,i,0,0,this.canvasWidth,this.canvasHeight)}function Bt(){let o=this.videoElement;if(o.tagName!=="VIDEO")return;this.annotatedFrameCoordinates=[];let t=Array.from(this.timeStack.keys()).filter(f=>{var g;return(g=this.timeStack.get(f))==null?void 0:g.length}),e=o.duration*this.fps,{x:i,width:s,height:r,y:l}=this.progressBarCoordinates,a=t.map(f=>Math.ceil(f/e*s));this.ctx.save(),this.ctx.fillStyle="rgba(0, 0, 0, 0.5)",this.ctx.fillRect(i,l,s,r),this.ctx.fillStyle="#F3CE32";let c=this.isMobile?16:8;a.forEach((f,g)=>{this.ctx.beginPath();let x=i+f,b=this.canvasHeight-r/2;this.ctx.fillRect(x-c/2,b-c/2,c,c),this.annotatedFrameCoordinates.push({x,y:b,frame:t[g]})});let h=this.playbackFrame,u=Math.ceil(h/e*s)+i;this.ctx.fillStyle="white",this.ctx.beginPath();let d=u,m=this.canvasHeight-r/2;this.ctx.beginPath(),this.ctx.fillRect(d-c/2,m-c/2,c,c),this.ctx.fill(),this.ctx.restore()}C.prototype.initUI=bt;C.prototype.initCanvas=Ct;C.prototype.addFrameSquareOverlay=Mt;C.prototype.addVideoOverlay=Dt;C.prototype.addProgressBarOverlay=Bt;export{C as SmAnnotate}; + `}function kt(o,n){let t=[.25,.5,.75,1],e=document.createElement("button"),i=t[t.length-1];e.type="button",o.playbackRate=i,e.innerHTML=Et(i),e.style.margin="5px",n.addEvent(e,"click",()=>{let s=t.indexOf(o.playbackRate),r=s+1>=t.length?0:s+1;o.playbackRate=t[r],e.innerHTML=Et(t[r])}),n.buttons.push(e),n.playerControlsContainer.appendChild(e)}var ne="#F3CE32";function It(){var c,m;let o=document.createElement("div");o.style.position="absolute",o.style.top="-40px",o.style.left="0",o.style.zIndex="2",(c=this.canvas.parentNode)==null||c.insertBefore(o,this.canvas);let n=document.createElement("div");n.style.position="relative",n.style.top="0",n.style.left="0",n.style.zIndex="2",(m=this.canvas.parentNode)==null||m.insertBefore(n,this.canvas.nextSibling),this.playerControlsContainer=n;let t=this.videoElement.tagName==="VIDEO"?this.videoElement:null;this.uiContainer=o;let e=(d,u,v=o)=>{let f=document.createElement("button");if(f.type="button",f.innerHTML=d,f.style.margin="5px",v.appendChild(f),this.buttons.push(f),typeof u=="function")this.addEvent(f,"click",u);else{f.dataset.tool=u;let x=()=>{this.currentTool===u?this.currentTool=null:this.currentTool=u};this.addEvent(f,"click",x)}return f},i=()=>{let d=document.createElement("div");return d.style.display="inline-flex",d.style.alignItems="center",d.style.margin="5px",o.appendChild(d),d};e('',"rectangle"),e('',"circle"),e('',"line"),e('',"curve"),e('',"arrow"),e('',"text"),e('',"eraser"),this.isMobile&&(this.hideButton("line"),this.hideButton("circle"),this.hideButton("rectangle"),this.hideButton("eraser")),e('',"move"),e('',"compare"),e('',()=>{this.handleUndo()}),t&&(e('',()=>{this.prevFrame()},this.playerControlsContainer),St(t,this),e('',()=>{this.nextFrame()},this.playerControlsContainer),Tt(t,this),kt(t,this),xt(t,this));let s=document.createElement("input");s.type="color",s.value=ne,s.style.margin="5px",this.colorPicker=s,o.appendChild(s);let r=i(),a=document.createElement("input");a.type="number",a.step="1",a.min="1",a.max="10",a.value="5",a.style.margin="5px",r.appendChild(a);let l=d=>{this.ctx.lineWidth=d.target.valueAsNumber,this.focusOnMediaNode()};this.addEvent(a,"input",l);let h=d=>{this.ctx.strokeStyle=d.target.value,this.ctx.fillStyle=d.target.value,this.focusOnMediaNode()};this.addEvent(s,"input",h),this.colorPicker=s,this.strokeSizePicker=a,this.hideButton("compare"),t&&(this.hide(),this.addEvent(t,"pause",()=>{this.show()}),this.addEvent(t,"seek",()=>{t.paused&&this.show()}),this.addEvent(t,"timeupdate",()=>{t.currentTime<2e-4&&!t.paused&&this.startAnnotationsAsVideo()}),this.addEvent(t,"error",()=>{this.hide()}),this.addEvent(t,"stalled",()=>{this.hide()}),this.addEvent(t,"play",()=>{this.hideControls(),this.startAnnotationsAsVideo()}),this.addEvent(document,"copy",d=>{vt(d,this)}),this.addEvent(document,"cut",d=>{ft(d,this)}),this.addEvent(document,"paste",d=>{yt(d,this)}),this.addEvent(document,"click",d=>{pt(d,this)}),this.addEvent(document,"keydown",d=>{gt(d,this)}))}function Pt(){var o;this.canvas=document.createElement("canvas"),this.ctx=this.canvas.getContext("2d"),(o=this.videoElement.parentNode)==null||o.insertBefore(this.canvas,this.videoElement.nextSibling),this.canvas.style.position="absolute",this.canvas.style.backgroundColor="transparent",this.canvas.style.top="0",this.canvas.style.left="0",this.canvas.style.zIndex="1",this.addEvent(this.canvas,"pointerdown",this.handleMouseDown),this.addEvent(this.canvas,"pointermove",this.handleMouseMove),this.addEvent(this.canvas,"pointerup",this.handleMouseUp),this.addEvent(this.canvas,"pointercancel",this.handleMouseUp),this.addEvent(window,"resize",this.setCanvasSize),this.addEvent(document,"keydown",this.onKeyDown)}var A=class{constructor(){this.destructors=[];this.isDestroyed=!1;this.activeTimeFrame=1;this.globalShapes=[];this.timeStack=new Map;this.undoTimeStack=new Map}cleanFrameStacks(){this.timeStack.clear(),this.undoTimeStack.clear()}destroy(){this.destructors.forEach(n=>n()),this.destructors=[],this.globalShapes=[],this.cleanFrameStacks()}raf(n){return requestAnimationFrame(n)}addEvent(n,t,e){let i=s=>{this.isDestroyed||e(s)};n.addEventListener(t,i),this.destructors.push(()=>{n.removeEventListener(t,i)})}addProgressBarOverlay(){throw new Error("Method not implemented.")}initUI(){throw new Error("Method not implemented.")}initCanvas(){throw new Error("Method not implemented.")}addFrameSquareOverlay(n=this.activeTimeFrame){throw new Error("Method not implemented.")}addVideoOverlay(){throw new Error("Method not implemented.")}withRefVideo(n){this.isDestroyed||this.referenceVideoElement&&n(this.referenceVideoElement)}withVideo(n){if(this.isDestroyed)return;let t=this.videoElement;!t||t.tagName!=="VIDEO"||n(t)}};var p=class{constructor(n){this.startX=0;this.startY=0;this.isDrawing=!1;this.annotationTool=n}on(n,t){}get ctx(){return this.annotationTool.ctx}onDeactivate(){}onActivate(){}reset(){this.startX=0,this.startY=0,this.isDrawing=!1}save(n){this.annotationTool.addShape(n)}};var H=class extends p{constructor(){super(...arguments);this.name="rectangle"}move(t,e,i){return t.x+=e,t.y+=i,t}normalize(t,e,i){return y(g({},t),{x:t.x/e,y:t.y/i,width:t.width/e,height:t.height/i})}onPointerDown(t){let{x:e,y:i}=this.annotationTool.getRelativeCoords(t);this.startX=e,this.startY=i,this.isDrawing=!0}onPointerMove(t){if(!this.isDrawing)return;let{x:e,y:i}=this.annotationTool.getRelativeCoords(t);this.drawRectangle(this.startX,this.startY,e-this.startX,i-this.startY)}onPointerUp(t){if(!this.isDrawing)return;let{x:e,y:i}=this.annotationTool.getRelativeCoords(t);this.save({type:"rectangle",x:this.startX,y:this.startY,width:e-this.startX,height:i-this.startY,strokeStyle:this.ctx.strokeStyle,fillStyle:this.ctx.fillStyle,lineWidth:this.ctx.lineWidth}),this.drawRectangle(this.startX,this.startY,e-this.startX,i-this.startY),this.isDrawing=!1}drawRectangle(t,e,i,s){this.ctx.beginPath(),this.ctx.rect(t,e,i,s),this.ctx.stroke()}draw(t){this.drawRectangle(t.x,t.y,t.width,t.height)}};var L=class extends p{constructor(){super(...arguments);this.name="circle"}move(t,e,i){return t.x+=e,t.y+=i,t}normalize(t,e,i){return y(g({},t),{x:t.x/e,y:t.y/i,radius:t.radius/e})}onPointerDown(t){let{x:e,y:i}=this.annotationTool.getRelativeCoords(t);this.startX=e,this.startY=i,this.isDrawing=!0}onPointerMove(t){if(!this.isDrawing)return;let{x:e,y:i}=this.annotationTool.getRelativeCoords(t),s=Math.sqrt(Math.pow(e-this.startX,2)+Math.pow(i-this.startY,2));this.drawCircle(this.startX,this.startY,s)}onPointerUp(t){if(!this.isDrawing)return;let{x:e,y:i}=this.annotationTool.getRelativeCoords(t),s=Math.sqrt(Math.pow(e-this.startX,2)+Math.pow(i-this.startY,2));this.save({type:"circle",x:this.startX,y:this.startY,radius:s,strokeStyle:this.ctx.strokeStyle,fillStyle:this.ctx.fillStyle,lineWidth:this.ctx.lineWidth}),this.drawCircle(this.startX,this.startY,s),this.isDrawing=!1}drawCircle(t,e,i){this.ctx.beginPath(),this.ctx.arc(t,e,i,0,2*Math.PI),this.ctx.stroke()}draw(t){this.drawCircle(t.x,t.y,t.radius)}};var R=class{constructor(n,t){this.x=n;this.y=t}distanceToLine(n,t){let e=t.x-n.x,i=t.y-n.y,s=Math.abs(i*this.x-e*this.y+t.x*n.y-t.y*n.x),r=Math.sqrt(i*i+e*e);return s/r}};function V(o,n){if(o.length<=2)return o;let t=o[0],e=o[o.length-1],i=-1,s=0;for(let r=1;rs&&(i=r,s=a)}if(s>n){let r=V(o.slice(0,i+1),n),a=V(o.slice(i),n);return r.slice(0,r.length-1).concat(a)}else return[t,e]}var W=class extends p{constructor(){super(...arguments);this.name="curve";this.curvePoints=[]}move(t,e,i){return t.points=t.points.map(s=>({x:s.x+e,y:s.y+i})),t}normalize(t,e,i){return y(g({},t),{points:t.points.map(s=>({x:s.x/e,y:s.y/i}))})}draw(t){this.drawCurve(t)}reset(){super.reset(),this.curvePoints=[]}onPointerDown(t){if(this.isDrawing)return;let{x:e,y:i}=this.annotationTool.getRelativeCoords(t);this.curvePoints=[],this.startX=e,this.startY=i,this.isDrawing=!0,this.curvePoints.push({x:e,y:i})}onPointerMove(t){if(!this.isDrawing)return;let{x:e,y:i}=this.annotationTool.getRelativeCoords(t);this.curvePoints.push({x:e,y:i}),this.drawCurve({points:this.curvePoints,lineWidth:this.ctx.lineWidth})}onPointerUp(t){if(!this.isDrawing)return;let{x:e,y:i}=this.annotationTool.getRelativeCoords(t);this.curvePoints.push({x:e,y:i});let s=this.curvePoints.map(c=>new R(c.x,c.y)),h={type:"curve",points:V(s,2).map(c=>({x:c.x,y:c.y})),strokeStyle:this.ctx.strokeStyle,fillStyle:this.ctx.fillStyle,lineWidth:this.ctx.lineWidth};this.save(h),this.curvePoints=[],this.isDrawing=!1}drawCurve(t){if(t.points.length===2&&t.points[0].x===t.points[1].x&&t.points[0].y===t.points[1].y){let e=t.lineWidth/4,i=0,s=2*Math.PI;this.ctx.beginPath(),this.ctx.arc(t.points[0].x,t.points[0].y,e,i,s),this.ctx.stroke()}else{this.ctx.beginPath(),this.ctx.moveTo(t.points[0].x,t.points[0].y);for(let e=1;e0){let s=this.annotationTool.globalShapes[0];if(s.type==="compare"){let r=this.annotationTool.deserialize([s])[0];this.draw(r),this.annotationTool.addFrameSquareOverlay()}}return}let{x:e}=this.annotationTool.getRelativeCoords(t);this.comparisonLine=e;let i={type:"compare",strokeStyle:this.ctx.strokeStyle,fillStyle:this.ctx.fillStyle,lineWidth:this.ctx.lineWidth,x:e};this.draw(i),this.drawDelimiter(i)}onPointerUp(){this.isDrawing&&(this.save({type:"compare",strokeStyle:this.ctx.strokeStyle,fillStyle:this.ctx.fillStyle,lineWidth:this.ctx.lineWidth,disabled:!1,x:this.comparisonLine}),this.isDrawing=!1)}removePreviousCompare(){this.annotationTool.globalShapes=this.annotationTool.globalShapes.filter(t=>t.type!=="compare")}disablePreviousCompare(){this.annotationTool.globalShapes=this.annotationTool.globalShapes.map(t=>t.type==="compare"?y(g({},t),{disabled:!0}):t)}save(t){this.removePreviousCompare();let e=this.annotationTool.serialize([t])[0];e.x<.05||e.x>.95||this.annotationTool.addGlobalShape(e)}drawDelimiter(t){this.ctx.beginPath(),this.ctx.moveTo(t.x,0),this.ctx.lineTo(t.x,this.annotationTool.canvasWidth),this.ctx.stroke()}drawShape(t){var it,nt,ot,st,rt,at,lt,ht;let e=this.annotationTool.videoElement,i=this.annotationTool.referenceVideoElement;if(!e||!i)return;let s=this.ctx.globalAlpha,r=this.annotationTool.canvasWidth,a=this.annotationTool.canvasHeight,l=t.x,h=i.videoHeight-e.videoHeight,c=i.videoWidth-e.videoWidth,m=this.annotationTool.isMobile;this.ctx.globalAlpha=this.leftOpacity;let d=(nt=(it=this.annotationTool.referenceVideoFrameBuffer)==null?void 0:it.frameNumberFromTime(e.currentTime))!=null?nt:1,u=d;if(c>e.videoWidth&&h>e.videoHeight&&!this.annotationTool.isMobile){let b=(at=(rt=this.annotationTool.referenceVideoFrameBuffer)==null?void 0:rt.getFrameNumberBySignature((st=(ot=this.annotationTool.videoFrameBuffer)==null?void 0:ot.getHistogram(d))!=null?st:null,d))!=null?at:d,F=Math.abs(d-b);F>=1&&F<=3&&(u=b)}let f=(lt=this.annotationTool.referenceVideoFrameBuffer)==null?void 0:lt.getFrame(u),x=(ht=this.annotationTool.videoFrameBuffer)==null?void 0:ht.getFrame(d);if(m){this.ctx.imageSmoothingQuality="low";let b=l/r,F=l;this.ctx.drawImage(x!=null?x:e,0,0,b*e.videoWidth,e.videoHeight,0,0,F,a)}else{let b=x?x.width:e.videoWidth,F=x?x.height:e.videoHeight;this.ctx.drawImage(x!=null?x:e,0,0,b,F,0,0,r,a)}this.ctx.globalAlpha=this.rightOpacity;let C=0,I=0,Yt=e.videoWidth/e.videoHeight,Xt=i.videoWidth/i.videoHeight,G=Math.abs(Yt-Xt)>.1,P=10,tt=Math.abs(h)>P,B=e.videoWidth,_=e.videoHeight,E=0;if(c<-P)if(G){let b=e.videoWidth/r;E=Math.abs(c/2),E=E/b,E<=P&&(E=0)}else B=i.videoWidth;else c>P&&(B=i.videoWidth);if(h===0)C=0;else if(h>0)G?(C=h/2,C<=P&&(C=0)):_=tt?i.videoHeight:e.videoHeight;else if(!G)_=tt?i.videoHeight:e.videoHeight;else{I=Math.abs(h/2);let b=e.videoHeight/a;I=I/b,I<=P&&(I=0)}let $=l-E,et=r-$,jt=et/r*B;f?(m&&(this.ctx.imageSmoothingQuality="low"),this.ctx.drawImage(f,$/r*B,C,jt,_,$+E,I,et,a)):console.log("no video data",d),this.ctx.globalAlpha=s}draw(t){if(t.disabled)return;let e=this.annotationTool.videoElement,i=this.annotationTool.referenceVideoElement;!e||!i||this.drawShape(t)}};function ae(o){let n=o[0],t=o[0];for(let e=1;et&&(t=o[e]);return[n,t]}var K=class extends p{constructor(t){super(t);this.name="audio-peaks";this.canvas=document.createElement("canvas");this.props={peaks:new Int8Array,theme:{waveOutlineColor:"rgba(255,192,203,0.7)",waveFillColor:"grey",waveProgressColor:"orange"},waveHeight:40,bits:16};this.drawCtx=this.canvas.getContext("2d")}onVideoBlobSet(t){return w(this,null,function*(){let e=yield t.arrayBuffer();this.init(e)})}on(t,e){t==="videoBlobSet"&&this.onVideoBlobSet(e)}extractPeaks(t){return w(this,null,function*(){let{default:e}=yield Promise.resolve().then(()=>ee(At(),1)),i=this.progressBarCoordinates.width,s=Math.ceil(t.length/i);return e(t,s,!0)})}setProps(t){let[e,i]=ae(t.data[0]),s=Math.pow(2,t.bits-1)-1,r=-Math.pow(2,t.bits-1);this.props.peaks=t.data[0].map(a=>a<0?Math.round(a/e*r):Math.round(a/i*s)),this.props.bits=t.bits}init(t){return w(this,null,function*(){try{let i=yield new AudioContext().decodeAudioData(t),s=yield this.extractPeaks(i);this.initCanvas(),this.setProps(s),this.annotationTool.removeGlobalShape("audio-peaks"),this.annotationTool.addGlobalShape({x:0,y:0,strokeStyle:"red",fillStyle:"red",lineWidth:1,type:"audio-peaks"}),this.clearLocalCanvas(),this.drawOnCanvas()}catch(e){this.initCanvas(),this.props.peaks=new Int8Array,this.annotationTool.removeGlobalShape("audio-peaks"),this.clearLocalCanvas(),console.error(e)}})}initCanvas(){this.canvas.width=this.progressBarCoordinates.width*this.pixelRatio,this.canvas.height=this.props.waveHeight*this.pixelRatio,this.drawCtx.scale(this.pixelRatio,this.pixelRatio)}move(t,e,i){return t.x+=e,t.y+=i,t}normalize(t,e,i){return y(g({},t),{x:t.x/e,y:t.y/i})}onPointerDown(t){}onPointerMove(t){}onPointerUp(t){}reset(){this.clearLocalCanvas(),this.props.peaks=new Int8Array,this.annotationTool.removeGlobalShape("audio-peaks")}draw(t){let e=this.annotationTool.videoElement;if(!e||e.tagName!=="VIDEO"||e.muted||e.volume===0)return;this.ctx.clearRect(0,0,this.annotationTool.canvasWidth,this.annotationTool.canvasHeight);let{waveHeight:s,theme:r}=this.props,a=this.ctx,l=s/2,h=this.progressBarCoordinates.y-20,{x:c,width:m}=this.progressBarCoordinates,d=this.annotationTool.playbackFrame,u=e.duration*this.annotationTool.fps,v=Math.ceil(d/u*m)+c;this.ctx.drawImage(this.canvas,c,h,m,s),a.fillStyle=r.waveProgressColor,a.fillRect(v,h+0,1,l*2)}get pixelRatio(){return this.annotationTool.pixelRatio}get progressBarCoordinates(){return this.annotationTool.progressBarCoordinates}clearLocalCanvas(){this.drawCtx.clearRect(0,0,this.canvas.width,this.canvas.height)}drawOnCanvas(){let{peaks:t,bits:e,waveHeight:i,theme:s}=this.props,r=this.drawCtx,a=0,l=0,h=i/2,c=ut(2,e-1),m=0,d=t.length;r.fillStyle=s.waveOutlineColor;for(let u=0;u{s.pop(),r=!1};o.addEventListener("seeked",l);function h(){return s.reduce((c,m)=>c+m)/s.length}return()=>{o.removeEventListener("seeked",l)}}function Rt(o,n,t){return .299*o+.587*n+.114*t}var le=0,Z=class extends Array{constructor(){super(...arguments);this.id=le++}};function Vt(o){let n=o.width,t=o.height,e=new Array(n*t),i=new Z,s=0;for(let r=0;rMath.max(o.id,n.id)+"-"+Math.min(o.id,n.id);function Wt(o,n){let t=he(o,n);if(Q.has(t))return Q.get(t);let e=0;for(let s=0;sn.close()),this.frames.clear()}tick(n,t){if(this.setCanvasSize(),t.expectedDisplayTime-performance.now()>10&&console.log("looks like frame is not yet rendered"),this.isDestroyed)return!1;if(this.seenFrames>=this.totalFrames){if(this.autoHide)try{this.video.paused||this.video.pause(),this.video.style.display="none"}catch(a){}return!1}if(this.video.videoWidth===0||this.video.videoHeight===0)return!0;let i=this.video,s=this.frameNumberFromTime(t.mediaTime);if(!Math.max(1,t.presentedFrames>this.totalFrames?t.presentedFrames%this.totalFrames:t.presentedFrames))throw new Error("expectedFrame is 0");if(this.hasFrame(s))this.seenFrames++;else{this.ctx.drawImage(i,0,0,this.width,this.height,0,0,this.width,this.height);let a=this.ctx.getImageData(0,0,this.canvas.width,this.canvas.height);createImageBitmap(a,0,0,this.width,this.height).then(l=>w(this,null,function*(){this.setFrame(s,l),this.isMobile||this.setHistogram(s,this.toHistogram(l))}))}return!0}addRequestFrameCallback(){this.isDestroyed||this.video.requestVideoFrameCallback((n,t)=>{this.tick(n,t)&&this.addRequestFrameCallback()})}createCanvas(){this.canvas=document.createElement("canvas"),this.ctx=this.canvas.getContext("2d",{willReadFrequently:!0,alpha:!1})}setCanvasSize(){this.isCanvasSizeSet||(this.canvas.width=this.video.videoWidth,this.canvas.height=this.video.videoHeight,this.isCanvasSizeSet=!0)}get width(){return this.video.videoWidth}get height(){return this.video.videoHeight}hasFrame(n){return this.frames.has(n)}getFrame(n){return this.frames.has(n)?this.frames.get(n):null}getFrameNumberBySignature(n,t){if(!n)return t;let e=0,i=t;return[t-3,t-2,t-1,t,t+1,t+2,t+3].filter(r=>r>0&&r<=this.totalFrames).forEach(r=>{let a=this.getHistogram(r);if(a){let l=Wt(n,a);l>e&&(e=l,i=r)}}),i}setFrame(n,t){this.frames.set(n,t)}setHistogram(n,t){this.histograms.set(n,t)}getHistogram(n){var t;return(t=this.histograms.get(n))!=null?t:null}get totalFrames(){return Math.round(this.video.duration*this.fps)}frameNumberFromTime(n){return Math.max(1,Math.round(n*this.fps))}};var ce=window.devicePixelRatio||1,Nt=25,S=class extends A{constructor(t){super();this.referenceVideoFrameBuffer=null;this.videoFrameBuffer=null;this.isMouseDown=!1;this.buttons=[];this.plugins=[];this.annotatedFrameCoordinates=[];this.fps=Nt;this.plannedFn=null;this.ct=0;this.isCanvasInitialized=!1;this.enforcedCanvasSize=null;this.lastNavigatedFrame=0;this.isProgressBarNavigation=!1;this.isAnnotationsAsVideoActive=!1;this.plugins=Ht.map(e=>new e(this)),this.init(t)}prevFrame(){let t=this.playbackFrame,e=Math.max(1,t-1);e===this.playbackFrame?this.playbackFrame=this.totalFrames-1:this.playbackFrame=e}nextFrame(){let t=this.playbackFrame,e=Math.min(this.totalFrames,t+1);e===this.totalFrames?this.playbackFrame=1:this.playbackFrame=e}removeGlobalShape(t){this.globalShapes=this.globalShapes.filter(e=>e.type!==t)}addGlobalShape(t){this.globalShapes.push(t)}get selectedColor(){return this.colorPicker.value}get selectedStrokeSize(){return this.strokeSizePicker.valueAsNumber}get currentTool(){return this._currentTool}set currentTool(t){let e=this._currentTool;e&&(this.getButtonForTool(e).classList.remove("active"),this.pluginForTool(e).onDeactivate()),this._currentTool=t,this.canvas.style.cursor=t?"pointer":"default",t&&(this.getButtonForTool(t).classList.add("active"),this.pluginForTool(t).onActivate())}enableFrameRateDetection(){if(this.destructors.find(i=>i.name==="frameRateDetector"))return;let t=this.videoElement;if(t.tagName==="IMG")return;let e=Lt(t,i=>{this.fps=i});Object.defineProperty(e,"name",{value:"frameRateDetector"}),this.destructors.push(e)}timeToFrame(t){return Math.max(1,Math.round(t*this.fps))}get playbackFrame(){return this.videoElement instanceof HTMLImageElement?1:this.timeToFrame(this.videoElement.currentTime)}set playbackFrame(t){if(this.videoElement instanceof HTMLImageElement)return;let e=t/this.fps;this.videoElement.currentTime=e,this.rvf(()=>{this.show()})}rvf(t){this.plannedFn=t}get canvasWidth(){var t,e;return(e=(t=this.enforcedCanvasSize)==null?void 0:t.width)!=null?e:0}get canvasHeight(){var t,e;return(e=(t=this.enforcedCanvasSize)==null?void 0:t.height)!=null?e:0}get aspectRatio(){return this.canvasWidth/this.canvasHeight}get isMobile(){return window.innerWidth<960}get progressBarCoordinates(){let t=this.isMobile?30:10,e=5,i=55,s=this.canvasWidth-e-i,r=e,a=this.canvasHeight-t;return{x:r,y:a,width:s,height:t}}get shapes(){return this.timeStack.has(this.activeTimeFrame)||this.timeStack.set(this.activeTimeFrame,[]),this.timeStack.get(this.activeTimeFrame)}set shapes(t){this.timeStack.set(this.activeTimeFrame,t)}get undoStack(){return this.undoTimeStack.has(this.activeTimeFrame)||this.undoTimeStack.set(this.activeTimeFrame,[]),this.undoTimeStack.get(this.activeTimeFrame)}set undoStack(t){this.undoTimeStack.set(this.activeTimeFrame,t)}get pixelRatio(){return ce}setVideoBlob(i){return w(this,arguments,function*(t,e=this.fps){let s=URL.createObjectURL(t);yield this.setVideoUrl(s,e),this.plugins.forEach(r=>{r.on("videoBlobSet",t)})})}setVideoUrl(i){return w(this,arguments,function*(t,e=this.fps){if(this.videoElement instanceof HTMLImageElement)return;let s=this.videoElement;s.src=t.toString(),yield this.videoElement.load(),this.setFrameRate(e),this.videoFrameBuffer&&(this.videoFrameBuffer.destroy(),this.videoFrameBuffer=new k(s,e,!1),this.videoFrameBuffer.isMobile=this.isMobile),this.setCanvasSize()})}enableVideoFrameBuffer(){this.videoElement instanceof HTMLImageElement||(this.videoFrameBuffer=new k(this.videoElement,this.fps,!1),this.videoFrameBuffer.isMobile=this.isMobile)}hide(){this.stopAnnotationsAsVideo(),this.hideControls(),this.hideCanvas()}showControls(){this.uiContainer.style.display="block"}hideControls(){this.uiContainer.style.display="none"}showCanvas(){this.canvas.style.display="block"}hideCanvas(){this.canvas.style.display="none"}updateActiveTimeFrame(t=void 0){this.activeTimeFrame=t?this.timeToFrame(t):this.playbackFrame}show(){this.stopAnnotationsAsVideo(),this.updateActiveTimeFrame(),this.showCanvas(),this.showControls(),this.redrawFullCanvas()}setCanvasSettings(){this.ctx.strokeStyle=this.selectedColor,this.ctx.fillStyle=this.selectedColor,this.ctx.lineWidth=this.selectedStrokeSize}pluginForTool(t){if(this.isDestroyed)throw new Error("AnnotationTool is destroyed");let e=this.plugins.find(i=>i.name===t);if(!e)throw new Error(`No plugin found for tool ${t}`);return e}getButtonForTool(t){return this.buttons.find(e=>e.dataset.tool===t)}bindContext(){this.handleMouseDown=this.handleMouseDown.bind(this),this.handleMouseMove=this.handleMouseMove.bind(this),this.handleMouseUp=this.handleMouseUp.bind(this),this.setCanvasSize=this.setCanvasSize.bind(this),this.onKeyDown=this.onKeyDown.bind(this)}initProperties(){this.isDestroyed=!1,this.isProgressBarNavigation=!1,this.shapes=[],this.globalShapes=[],this.currentTool=this.isMobile?null:"curve"}setVideoStyles(){this.videoElement.style.objectFit="cover",this.videoElement.style.objectPosition="left top"}get frameCallbackSupported(){return"requestVideoFrameCallback"in HTMLVideoElement.prototype}initFrameCounter(){if(!this.frameCallbackSupported){setTimeout(()=>{var t;(t=this.plannedFn)==null||t.call(this),this.plannedFn=null,this.initFrameCounter(),this.updateActiveTimeFrame(),this.playAnnotationsAsVideo()},1e3/this.fps);return}this.withVideo(t=>{t.requestVideoFrameCallback((e,i)=>{var s,r;this.isCanvasInitialized||this._setCanvasSize(),(s=this.videoFrameBuffer)==null||s.tick(e,i),(r=this.plannedFn)==null||r.call(this),this.plannedFn=null,this.raf(()=>{this.initFrameCounter(),this.updateActiveTimeFrame(i.mediaTime),this.playAnnotationsAsVideo()})})})}init(t){this.videoElement=t,this.setVideoStyles(),this.initFrameCounter(),this.bindContext(),this.initCanvas(),this.initUI(),this.initProperties(),this.setCanvasSize()}onKeyDown(t){(t.ctrlKey||t.metaKey)&&t.key.toLowerCase()==="z"&&this.handleUndo()}removeLastShape(){this.shapes.pop(),this.redrawFullCanvas()}handleUndo(){this.undoStack.length>0&&(this.shapes=this.undoStack.pop(),this.redrawFullCanvas())}destroy(){var s,r,a,l,h,c,m,d;if(this.isDestroyed)return;super.destroy(),this.stopAnnotationsAsVideo(),this._currentTool=null,this.plugins.forEach(u=>u.reset()),this.annotatedFrameCoordinates=[],this.setFrameRate(Nt);let t=this.strokeSizePicker.parentElement;if((s=t==null?void 0:t.parentNode)==null||s.removeChild(t),this.referenceVideoElement){let u=this.referenceVideoElement.parentElement;(r=u==null?void 0:u.parentNode)==null||r.removeChild(u),this.referenceVideoElement=null}let e=this.colorPicker.parentElement;(a=e==null?void 0:e.parentNode)==null||a.removeChild(e),this.buttons.forEach(u=>{var v;(v=u.parentNode)==null||v.removeChild(u)}),this.buttons=[],(l=this.uiContainer.parentNode)==null||l.removeChild(this.uiContainer),(h=this.canvas.parentNode)==null||h.removeChild(this.canvas),(c=this.playerControlsContainer.parentElement)==null||c.removeChild(this.playerControlsContainer),["strokeSizePicker","colorPicker","uiContainer","playerControlsContainer","canvas","ctx","videoElement"].forEach(u=>{delete this[u]}),this.activeTimeFrame=0,this.isDestroyed=!0,(m=this.referenceVideoFrameBuffer)==null||m.destroy(),this.referenceVideoFrameBuffer=null,(d=this.videoFrameBuffer)==null||d.destroy(),this.videoFrameBuffer=null}_setCanvasSize(){let t=getComputedStyle(this.videoElement),e=parseInt(t.width,10),i=this.videoElement,s=i.videoWidth/i.videoHeight;if(isNaN(e)||!i.videoWidth||!i.videoHeight)return this.isCanvasInitialized=!1,this.setCanvasSettings(),!1;let r=Math.min(e,i.videoWidth),a=Math.floor(r/s);return i.style.width=`${r}px`,i.style.height=`${a}px`,this.isCanvasInitialized=i.videoWidth>0&&i.videoHeight>0,this.canvas.width=r*this.pixelRatio,this.canvas.height=a*this.pixelRatio,this.canvas.style.width=`${r}px`,this.canvas.style.height=`${a}px`,this.enforcedCanvasSize={width:r,height:a},this.ctx.scale(this.pixelRatio,this.pixelRatio),this.setCanvasSettings(),!0}setCanvasSize(){this._setCanvasSize()&&(this.syncVideoSizes(),this.redrawFullCanvas())}addShape(t){let e=this.serialize([t])[0];this.undoStack.push([...this.shapes]),this.shapes.push(e)}get msPerFrame(){return this.fps/1e3}syncVideoSizes(){this.withRefVideo(t=>{let i=this.videoElement.getBoundingClientRect();t.style.position="fixed",t.style.top=`${i.top}px`,t.style.left=`${i.left}px`})}addReferenceVideoByURL(s){return w(this,arguments,function*(t,e=this.fps,i="video/mp4"){var h;let r=yield fetch(t).then(c=>c.blob()),a=new Blob([r],{type:i}),l=window.URL.createObjectURL(a);this.referenceVideoElement?((h=this.referenceVideoFrameBuffer)==null||h.destroy(),this.referenceVideoFrameBuffer=new k(this.referenceVideoElement,e),this.referenceVideoFrameBuffer.isMobile=this.isMobile,this.referenceVideoFrameBuffer.start()):(this.referenceVideoElement=document.createElement("video"),this.withRefVideo(c=>{this.isMobile?(c.style.zIndex="2",c.style.display="block",c.style.top="0",c.style.left="0",c.style.opacity="0.25",c.style.width="20px",c.style.height="15px"):(c.style.zIndex="-1",c.style.display="none",c.style.width="100px",c.style.height="70px"),c.style.objectFit="cover",c.style.objectPosition="left top",c.muted=!0,c.volume=0,c.playsInline=!0,c.autoplay=!1,c.controls=!1,c.loop=!0,this.videoElement.after(c),this.referenceVideoFrameBuffer=new k(c,e),this.referenceVideoFrameBuffer.isMobile=this.isMobile,this.referenceVideoFrameBuffer.start()}),this.syncVideoSizes()),this.referenceVideoElement.src=l,this.referenceVideoElement.play().then(()=>{this.showButton("compare")}).catch(()=>{this.hideButton("compare")})})}hideButton(t){let e=this.getButtonForTool(t);e.style.display="none"}showButton(t){let e=this.getButtonForTool(t);e.style.display=""}addSingletonShape(t){let e=this.serialize([t])[0],i=this.shapes.filter(s=>s.type!==t.type);this.replaceFrame(this.playbackFrame,[...i,e])}serialize(t=this.shapes){let e=this.canvasWidth,i=this.canvasHeight;return t.map(s=>this.pluginForTool(s.type).normalize(s,e,i))}deserialize(t){let e=1/this.canvasWidth,i=1/this.canvasHeight;return t.map(s=>this.pluginForTool(s.type).normalize(s,e,i))}getRelativeCoords(t){let e=this.canvas.getBoundingClientRect();return{x:this.getEventX(t)-e.left,y:this.getEventY(t)-e.top}}handleMouseDown(t){if(t.preventDefault(),this.isMouseDown=!0,D(t))return;let e=this.frameFromProgressBar(t,!0);if(e){this.isProgressBarNavigation=!0;let i=this.getAnnotationFrame(t);this.isVideoPaused&&(i!==null?this.playbackFrame=i:this.playbackFrame=e);return}this.currentTool&&this.pluginForTool(this.currentTool).onPointerDown(t)}get isDrawing(){return this.currentTool?this.pluginForTool(this.currentTool).isDrawing:!1}get isVideoPaused(){return this.videoElement.tagName==="VIDEO"?this.videoElement.paused:!0}get hasGlobalOverlays(){return this.globalShapes.length>0}handleMouseMove(t){if(t.preventDefault(),!D(t)){if(this.isMouseDown){let e=this.isProgressBarNavigation?this.frameFromProgressBar(t,!1):null;if(e!==null&&!this.isDrawing){if(e===this.lastNavigatedFrame)return;this.lastNavigatedFrame=e,this.isVideoPaused&&(this.playbackFrame=e);return}else this.hideControls(),this.clearCanvas(),this.hasGlobalOverlays||this.addVideoOverlay(),this.drawShapesOverlay()}else this.redrawFullCanvas();this.currentTool&&this.pluginForTool(this.currentTool).onPointerMove(t)}}getEventX(t){return t.clientX}getEventY(t){return t.clientY}handleMouseUp(t){this.isMouseDown=!1,this.isProgressBarNavigation=!1,this.showControls(),!D(t)&&(this.currentTool&&this.pluginForTool(this.currentTool).onPointerUp(t),this.redrawFullCanvas())}focusOnMediaNode(){this.videoElement.focus()}drawShapesOverlay(){let t={strokeStyle:this.ctx.strokeStyle,fillStyle:this.ctx.fillStyle,lineWidth:this.ctx.lineWidth};for(let e of this.deserialize(this.globalShapes)){this.ctx.strokeStyle=e.strokeStyle,this.ctx.fillStyle=e.fillStyle,this.ctx.lineWidth=e.lineWidth;try{this.pluginForTool(e.type).draw(e)}catch(i){console.error(i)}}for(let e of this.deserialize(this.shapes)){this.ctx.strokeStyle=e.strokeStyle,this.ctx.fillStyle=e.fillStyle,this.ctx.lineWidth=e.lineWidth;try{this.pluginForTool(e.type).draw(e)}catch(i){console.error(i)}}this.ctx.strokeStyle=t.strokeStyle,this.ctx.fillStyle=t.fillStyle,this.ctx.lineWidth=t.lineWidth}clearCanvas(){this.ctx.clearRect(0,0,this.canvasWidth,this.canvasHeight)}frameToDataUrl(){try{this.clearCanvas(),this.addVideoOverlay(),this.addFrameSquareOverlay(),this.drawShapesOverlay();let t=this.canvas.toDataURL("image/png");return this.redrawFullCanvas(),t}catch(t){return console.error(t),null}}redrawFullCanvas(){this.hasGlobalOverlays||(this.clearCanvas(),this.addVideoOverlay()),this.drawShapesOverlay(),this.addFrameSquareOverlay(),this.addProgressBarOverlay()}replaceFrame(t,e){this.timeStack.set(t,this.parseShapes(this.stringifyShapes(e)))}addShapesToFrame(t,e){let i=this.timeStack.get(t)||[];this.timeStack.set(t,[...i,...this.parseShapes(this.stringifyShapes(e))])}setFrameRate(t){var e;(e=this.destructors.find(i=>i.name==="frameRateDetector"))==null||e(),this.fps=t}stringifyShapes(t){return JSON.stringify(t,(e,i)=>e==="image"?i.src:i)}parseShapes(t){return JSON.parse(t,(e,i)=>{if(e==="image"){let s=new Image;return s.src=i,s}return i})}filterNonSerializableShapes(t){return t.filter(e=>e.type!=="image")}saveCurrentFrame(){return{frame:this.playbackFrame,version:1,fps:this.fps,shapes:this.parseShapes(this.stringifyShapes(this.filterNonSerializableShapes(this.shapes)))}}loadAllFrames(t){this.cleanFrameStacks(),t.forEach(e=>{this.timeStack.set(e.frame,e.shapes)})}appendFrames(t){t.forEach(e=>{this.addShapesToFrame(e.frame,e.shapes)})}saveAllFrames(){return Array.from(this.timeStack.keys()).filter(s=>{var r;return(r=this.timeStack.get(s))==null?void 0:r.length}).map(s=>{var r;return{frame:s,fps:this.fps,version:1,shapes:this.filterNonSerializableShapes((r=this.timeStack.get(s))!=null?r:[])}})}getAnnotationFrame(t){var a,l;let e=t.offsetX,i=t.offsetY,s=this.isMobile?10:5;return(l=(a=this.annotatedFrameCoordinates.find(h=>e>=h.x-s&&e<=h.x+s&&i>=h.y-s&&i<=h.y+s))==null?void 0:a.frame)!=null?l:null}get totalFrames(){let t=this.videoElement;return t.tagName!=="VIDEO"?1:Math.ceil(t.duration*this.fps)}frameFromProgressBar(t,e=!0){let i=this.videoElement;if(i.tagName!=="VIDEO")return null;let{x:s,width:r,height:a,y:l}=this.progressBarCoordinates,h=t.offsetX,c=t.offsetY;return e?h>=s&&h<=s+r&&c>=l&&c<=l+a?Math.ceil((h-s)/r*(i.duration*this.fps)):null:h>=s&&h<=s+r?Math.ceil((h-s)/r*(i.duration*this.fps)):null}hasAnnotationsForFrame(t){if(this.globalShapes.length>0)return!0;if(this.timeStack.has(t)){let e=this.timeStack.get(t);return e&&e.length>0}return!1}stopAnnotationsAsVideo(){this.isAnnotationsAsVideoActive=!1}startAnnotationsAsVideo(){this.isAnnotationsAsVideoActive=!0,this.playAnnotationsAsVideo()}playAnnotationsAsVideo(){this.isAnnotationsAsVideoActive&&(this.hasGlobalOverlays||this.clearCanvas(),this.isMobile?this.hasGlobalOverlays||this.addVideoOverlay():this.addVideoOverlay(),this.drawShapesOverlay(),this.addFrameSquareOverlay(),this.addProgressBarOverlay())}};function zt(o=this.activeTimeFrame){this.ctx.save(),this.ctx.fillStyle="rgba(0, 0, 0, 0.5)";let n=50,t=30,e=20;this.ctx.fillRect(this.canvasWidth-n,this.canvasHeight-t,n,t),this.ctx.fillStyle="white",this.ctx.font=`${e}px sans-serif`,this.ctx.fillText(`${o}`.padStart(3,"0"),this.canvasWidth-40,this.canvasHeight-7),this.ctx.restore()}function Ot(){var s,r,a;let o=this.videoElement;if(o.tagName!=="VIDEO")return;let n=(s=this.videoFrameBuffer)==null?void 0:s.frameNumberFromTime(o.currentTime),t=(a=(r=this.videoFrameBuffer)==null?void 0:r.getFrame(n||0))!=null?a:o,e=t?t.width:o.videoWidth,i=t?t.height:o.videoHeight;this.ctx.drawImage(t,0,0,e,i,0,0,this.canvasWidth,this.canvasHeight)}function Ut(){let o=this.videoElement;if(o.tagName!=="VIDEO")return;this.annotatedFrameCoordinates=[];let t=Array.from(this.timeStack.keys()).filter(v=>{var f;return(f=this.timeStack.get(v))==null?void 0:f.length}),e=o.duration*this.fps,{x:i,width:s,height:r,y:a}=this.progressBarCoordinates,l=t.map(v=>Math.ceil(v/e*s));this.ctx.save(),this.ctx.fillStyle="rgba(0, 0, 0, 0.5)",this.ctx.fillRect(i,a,s,r),this.ctx.fillStyle="#F3CE32";let h=this.isMobile?16:8;l.forEach((v,f)=>{this.ctx.beginPath();let x=i+v,C=this.canvasHeight-r/2;this.ctx.fillRect(x-h/2,C-h/2,h,h),this.annotatedFrameCoordinates.push({x,y:C,frame:t[f]})});let c=this.playbackFrame,m=Math.ceil(c/e*s)+i;this.ctx.fillStyle="white",this.ctx.beginPath();let d=m,u=this.canvasHeight-r/2;this.ctx.beginPath(),this.ctx.fillRect(d-h/2,u-h/2,h,h),this.ctx.fill(),this.ctx.restore()}S.prototype.initUI=It;S.prototype.initCanvas=Pt;S.prototype.addFrameSquareOverlay=zt;S.prototype.addVideoOverlay=Ot;S.prototype.addProgressBarOverlay=Ut;export{S as SmAnnotate}; diff --git a/dist/types/core.d.ts b/dist/types/core.d.ts index 430e6b9..ee3ed57 100644 --- a/dist/types/core.d.ts +++ b/dist/types/core.d.ts @@ -29,6 +29,7 @@ export declare class AnnotationTool extends AnnotationToolBase { }[]; prevFrame(): void; nextFrame(): void; + removeGlobalShape(shapeType: IShape['type']): void; addGlobalShape(shape: IShape): void; get selectedColor(): string; get selectedStrokeSize(): number; @@ -57,6 +58,7 @@ export declare class AnnotationTool extends AnnotationToolBase { set undoStack(shapes: IShape[][]); get pixelRatio(): number; constructor(videoElement: HTMLVideoElement | HTMLImageElement); + setVideoBlob(blob: Blob, fps?: number): Promise; setVideoUrl(url: string, fps?: number): Promise; enableVideoFrameBuffer(): void; hide(): void; diff --git a/dist/types/plugins/audio-peaks.d.ts b/dist/types/plugins/audio-peaks.d.ts new file mode 100644 index 0000000..4e340b4 --- /dev/null +++ b/dist/types/plugins/audio-peaks.d.ts @@ -0,0 +1,45 @@ +import { IShapeBase, BasePlugin, ToolPlugin } from "./base"; +import { AnnotationTool } from "../core"; +import type { PeakData } from "webaudio-peaks"; +export interface IAudioPeaks extends IShapeBase { + x: number; + y: number; +} +export declare class AudioPeaksPlugin extends BasePlugin implements ToolPlugin { + name: string; + canvas: HTMLCanvasElement; + drawCtx: CanvasRenderingContext2D; + constructor(annotationTool: AnnotationTool); + onVideoBlobSet(blob: Blob): Promise; + on(event: string, arg: unknown): void; + extractPeaks(decodedData: AudioBuffer): Promise; + setProps(peaks: PeakData): void; + init(blob: ArrayBuffer): Promise; + initCanvas(): void; + move(shape: IAudioPeaks, dx: number, dy: number): IAudioPeaks; + normalize(shape: IAudioPeaks, canvasWidth: number, canvasHeight: number): IAudioPeaks; + onPointerDown(event: PointerEvent): void; + onPointerMove(event: PointerEvent): void; + onPointerUp(event: PointerEvent): void; + props: { + peaks: Int8Array | Int16Array | Int32Array; + theme: { + waveOutlineColor: string; + waveFillColor: string; + waveProgressColor: string; + }; + waveHeight: number; + bits: number; + }; + reset(): void; + draw(_: IAudioPeaks): void; + get pixelRatio(): number; + get progressBarCoordinates(): { + x: number; + y: number; + width: number; + height: number; + }; + clearLocalCanvas(): void; + drawOnCanvas(): void; +} diff --git a/dist/types/plugins/base.d.ts b/dist/types/plugins/base.d.ts index 8202982..adcf1c9 100644 --- a/dist/types/plugins/base.d.ts +++ b/dist/types/plugins/base.d.ts @@ -25,6 +25,7 @@ export declare class BasePlugin { startY: number; isDrawing: boolean; constructor(annotationTool: AnnotationTool); + on(event: string, arg: unknown): void; get ctx(): CanvasRenderingContext2D; onDeactivate(): void; onActivate(): void; diff --git a/dist/types/plugins/index.d.ts b/dist/types/plugins/index.d.ts index f7c5c90..5d158ed 100644 --- a/dist/types/plugins/index.d.ts +++ b/dist/types/plugins/index.d.ts @@ -8,7 +8,8 @@ import { EraserToolPlugin, IEraser } from "./eraser"; import { IMove, MoveToolPlugin } from "./move"; import { IImage, ImageToolPlugin } from "./image"; import { ICompare, CompareToolPlugin } from "./compare"; -export type IShape = IRectangle | ICircle | ILine | IArrow | IText | IEraser | ICurve | IMove | IImage | ICompare; +import { IAudioPeaks, AudioPeaksPlugin } from "./audio-peaks"; +export type IShape = IRectangle | ICircle | ILine | IArrow | IText | IEraser | ICurve | IMove | IImage | ICompare | IAudioPeaks; export type Tool = IShape["type"]; export interface ShapeMap { rectangle: IRectangle; @@ -21,6 +22,7 @@ export interface ShapeMap { move: IMove; image: IImage; compare: ICompare; + "audio-peaks": IAudioPeaks; } -export type PluginInstances = RectangleToolPlugin | CircleToolPlugin | LineToolPlugin | ArrowToolPlugin | TextToolPlugin | EraserToolPlugin | CurveToolPlugin | MoveToolPlugin | ImageToolPlugin | CompareToolPlugin; -export declare const plugins: (typeof RectangleToolPlugin | typeof CircleToolPlugin | typeof CurveToolPlugin | typeof LineToolPlugin | typeof ArrowToolPlugin | typeof TextToolPlugin | typeof EraserToolPlugin | typeof ImageToolPlugin | typeof MoveToolPlugin | typeof CompareToolPlugin)[]; +export type PluginInstances = RectangleToolPlugin | CircleToolPlugin | LineToolPlugin | ArrowToolPlugin | TextToolPlugin | EraserToolPlugin | CurveToolPlugin | MoveToolPlugin | ImageToolPlugin | CompareToolPlugin | AudioPeaksPlugin; +export declare const plugins: (typeof RectangleToolPlugin | typeof CircleToolPlugin | typeof CurveToolPlugin | typeof LineToolPlugin | typeof ArrowToolPlugin | typeof TextToolPlugin | typeof EraserToolPlugin | typeof ImageToolPlugin | typeof MoveToolPlugin | typeof CompareToolPlugin | typeof AudioPeaksPlugin)[]; diff --git a/package.json b/package.json index 602c02b..072a6bc 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,8 @@ "types": "dist/types/index.d.ts", "devDependencies": { "esbuild": "^0.17.15", - "typescript": "^5.0.4" + "typescript": "^5.0.4", + "webaudio-peaks": "^1.0.0" }, "exports": "./dist/index.js", "scripts": { diff --git a/src/core.ts b/src/core.ts index 126868b..62a9955 100644 --- a/src/core.ts +++ b/src/core.ts @@ -65,7 +65,9 @@ export class AnnotationTool extends AnnotationToolBase { this.playbackFrame = newFrame; } } - + removeGlobalShape(shapeType: IShape['type']) { + this.globalShapes = this.globalShapes.filter((s) => s.type !== shapeType); + } addGlobalShape(shape: IShape) { this.globalShapes.push(shape); } @@ -179,10 +181,19 @@ export class AnnotationTool extends AnnotationToolBase { this.init(videoElement); } + + async setVideoBlob(blob: Blob, fps = this.fps) { + const url = URL.createObjectURL(blob); + await this.setVideoUrl(url, fps); + this.plugins.forEach((p) => { + p.on('videoBlobSet', blob); + }); + } + async setVideoUrl(url: string, fps = this.fps) { if (this.videoElement instanceof HTMLImageElement) return; const video = this.videoElement as HTMLVideoElement; - video.src = url; + video.src = url.toString(); await this.videoElement.load(); this.setFrameRate(fps); if (this.videoFrameBuffer) { diff --git a/src/plugins/audio-peaks.ts b/src/plugins/audio-peaks.ts new file mode 100644 index 0000000..9d614c8 --- /dev/null +++ b/src/plugins/audio-peaks.ts @@ -0,0 +1,213 @@ +import { IShapeBase, BasePlugin, ToolPlugin } from "./base"; +import { AnnotationTool } from "../core"; +import type { PeakData } from "webaudio-peaks"; + +export interface IAudioPeaks extends IShapeBase { + x: number; + y: number; +} + +function findMinMaxNumbers(array: Int8Array): [number, number] { + let min = array[0]; + let max = array[0]; + for (let i = 1; i < array.length; i++) { + if (array[i] < min) min = array[i]; + if (array[i] > max) max = array[i]; + } + return [min, max]; +} + +export class AudioPeaksPlugin + extends BasePlugin + implements ToolPlugin +{ + name = "audio-peaks"; + canvas = document.createElement("canvas"); + drawCtx!: CanvasRenderingContext2D; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + constructor(annotationTool: AnnotationTool) { + super(annotationTool); + this.drawCtx = this.canvas.getContext("2d")!; + } + async onVideoBlobSet(blob: Blob) { + const buffer = await blob.arrayBuffer(); + this.init(buffer); + } + on(event: string, arg: unknown) { + if (event === "videoBlobSet") { + this.onVideoBlobSet(arg as Blob); + } + } + async extractPeaks(decodedData: AudioBuffer) { + const { default: extractPeaks } = await import("webaudio-peaks"); + const progressBarWidth = this.progressBarCoordinates.width; + const perPixel = Math.ceil(decodedData.length / progressBarWidth); + + //calculate peaks from an AudioBuffer + const peaks = extractPeaks(decodedData, perPixel, true); + return peaks; + } + setProps(peaks: PeakData) { + // normalize peaks to bits + const [min, max] = findMinMaxNumbers(peaks.data[0] as Int8Array); + const maxNumber = Math.pow(2, peaks.bits - 1) - 1; + const minNumber = -Math.pow(2, peaks.bits - 1); + this.props.peaks = peaks.data[0].map((peak) => { + if (peak < 0) { + return Math.round((peak / min) * minNumber); + } else { + return Math.round((peak / max) * maxNumber); + } + }); + this.props.bits = peaks.bits; + } + async init(blob: ArrayBuffer) { + try { + const audioContext = new AudioContext(); + const decodedData = await audioContext.decodeAudioData(blob); + const peaks = await this.extractPeaks(decodedData); + + this.initCanvas(); + this.setProps(peaks); + + this.annotationTool.removeGlobalShape("audio-peaks"); + this.annotationTool.addGlobalShape({ + x: 0, + y: 0, + strokeStyle: "red", + fillStyle: "red", + lineWidth: 1, + type: "audio-peaks", + }); + this.clearLocalCanvas(); + this.drawOnCanvas(); + } catch (e) { + this.initCanvas(); + this.props.peaks = new Int8Array(); + this.annotationTool.removeGlobalShape("audio-peaks"); + this.clearLocalCanvas(); + console.error(e); + } + } + initCanvas() { + this.canvas.width = this.progressBarCoordinates.width * this.pixelRatio; + this.canvas.height = this.props.waveHeight * this.pixelRatio; + this.drawCtx.scale(this.pixelRatio, this.pixelRatio); + } + move(shape: IAudioPeaks, dx: number, dy: number) { + shape.x += dx; + shape.y += dy; + return shape; + } + normalize( + shape: IAudioPeaks, + canvasWidth: number, + canvasHeight: number + ): IAudioPeaks { + return { + ...shape, + x: shape.x / canvasWidth, + y: shape.y / canvasHeight, + }; + } + onPointerDown(event: PointerEvent) { + return; + } + onPointerMove(event: PointerEvent) { + return; + } + onPointerUp(event: PointerEvent) { + return; + } + props = { + peaks: new Int8Array() as Int8Array | Int16Array | Int32Array, + theme: { + // color of the waveform outline + waveOutlineColor: "rgba(255,192,203,0.7)", + waveFillColor: "grey", + waveProgressColor: "orange", + }, + waveHeight: 40, + bits: 16, + }; + reset() { + this.clearLocalCanvas(); + this.props.peaks = new Int8Array(); + this.annotationTool.removeGlobalShape("audio-peaks"); + } + draw(_: IAudioPeaks) { + const maybeVideoElement = this.annotationTool + .videoElement as HTMLVideoElement; + if (!maybeVideoElement || maybeVideoElement.tagName !== "VIDEO") { + return; + } + + const isMuted = maybeVideoElement.muted; + if (isMuted || maybeVideoElement.volume === 0) { + return; + } + + this.ctx.clearRect( + 0, + 0, + this.annotationTool.canvasWidth, + this.annotationTool.canvasHeight + ); + + const { waveHeight, theme } = this.props; + const cc = this.ctx; + + const h2 = waveHeight / 2; + let y = this.progressBarCoordinates.y - 20; + + const { x, width } = this.progressBarCoordinates; + const currentFrame = this.annotationTool.playbackFrame; + const totalFrames = maybeVideoElement.duration * this.annotationTool.fps; + + const currentFrameCoordinate = + Math.ceil((currentFrame / totalFrames) * width) + x; + + //call its drawImage() function passing it the source canvas directly + this.ctx.drawImage(this.canvas, x, y, width, waveHeight); + cc.fillStyle = theme.waveProgressColor; + + cc.fillRect(currentFrameCoordinate, y + 0, 1, h2 * 2); + } + get pixelRatio() { + return this.annotationTool.pixelRatio; + } + get progressBarCoordinates() { + return this.annotationTool.progressBarCoordinates; + } + clearLocalCanvas() { + this.drawCtx.clearRect(0, 0, this.canvas.width, this.canvas.height); + } + drawOnCanvas() { + const { peaks, bits, waveHeight, theme } = this.props; + const cc = this.drawCtx; + let offset = 0; + let shift = 0; + + const h2 = waveHeight / 2; + const maxValue = 2 ** (bits - 1); + let y = 0; + + const peakSegmentLength = peaks.length; + // console.log('peaks.length', peaks.length, this.progressBarCoordinates.width); + + // cc.fillStyle = 'white'; + // theme.waveOutlineColor; + cc.fillStyle = theme.waveOutlineColor; + + for (let i = 0; i < peakSegmentLength; i += 1) { + // const minPeak = peaks[(i + offset) * 2] / maxValue; + const maxPeak = peaks[(i + offset) * 2 + 1] / maxValue; + + // const min = Math.abs(minPeak * h2); + const max = Math.abs(maxPeak * h2); + // cc.fillRect(i + shift, y + 0 + h2 - max, 1, max + min); // + + cc.fillRect(i + shift, y + 0 + h2 - max, 1, max ); // + min + } + } +} diff --git a/src/plugins/base.ts b/src/plugins/base.ts index 554ac10..89ba19a 100644 --- a/src/plugins/base.ts +++ b/src/plugins/base.ts @@ -30,6 +30,9 @@ export class BasePlugin { constructor(annotationTool: AnnotationTool) { this.annotationTool = annotationTool; } + on(event: string, arg: unknown) { + // noop + } get ctx() { return this.annotationTool.ctx; } diff --git a/src/plugins/index.ts b/src/plugins/index.ts index b380ecf..c6ec193 100644 --- a/src/plugins/index.ts +++ b/src/plugins/index.ts @@ -8,6 +8,7 @@ import { EraserToolPlugin, IEraser } from "./eraser"; import { IMove, MoveToolPlugin } from "./move"; import { IImage, ImageToolPlugin } from "./image"; import { ICompare, CompareToolPlugin } from "./compare"; +import { IAudioPeaks, AudioPeaksPlugin } from "./audio-peaks"; export type IShape = | IRectangle @@ -19,7 +20,8 @@ export type IShape = | ICurve | IMove | IImage - | ICompare; + | ICompare + | IAudioPeaks; export type Tool = IShape["type"]; @@ -34,9 +36,10 @@ export interface ShapeMap { move: IMove; image: IImage; compare: ICompare; + "audio-peaks": IAudioPeaks; } -export type PluginInstances = RectangleToolPlugin | CircleToolPlugin | LineToolPlugin | ArrowToolPlugin | TextToolPlugin | EraserToolPlugin | CurveToolPlugin | MoveToolPlugin | ImageToolPlugin | CompareToolPlugin; +export type PluginInstances = RectangleToolPlugin | CircleToolPlugin | LineToolPlugin | ArrowToolPlugin | TextToolPlugin | EraserToolPlugin | CurveToolPlugin | MoveToolPlugin | ImageToolPlugin | CompareToolPlugin | AudioPeaksPlugin; export const plugins = [ RectangleToolPlugin, @@ -49,4 +52,5 @@ export const plugins = [ MoveToolPlugin, ImageToolPlugin, CompareToolPlugin, + AudioPeaksPlugin, ] \ No newline at end of file diff --git a/src/ui/mute-unmute-button.ts b/src/ui/mute-unmute-button.ts index e9adc9c..4fa2a7c 100644 --- a/src/ui/mute-unmute-button.ts +++ b/src/ui/mute-unmute-button.ts @@ -15,9 +15,9 @@ export function createMuteUnmuteButton( button.style.margin = "5px"; if (video.muted || video.volume === 0) { - button.innerHTML = unmuteIcon; - } else { button.innerHTML = muteIcon; + } else { + button.innerHTML = unmuteIcon; } tool.addEvent(video, "volumechange", () => { @@ -31,6 +31,7 @@ export function createMuteUnmuteButton( tool.addEvent(button, "click", () => { if (video.muted) { video.muted = false; + return; } if (video.volume === 0) { video.volume = 1; diff --git a/yarn.lock b/yarn.lock index deb98f8..22cd25a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -144,3 +144,8 @@ typescript@^5.0.4: version "5.0.4" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.0.4.tgz#b217fd20119bd61a94d4011274e0ab369058da3b" integrity sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw== + +webaudio-peaks@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/webaudio-peaks/-/webaudio-peaks-1.0.0.tgz#f0fb4cfc6c882de8cbb59c47f653942166b71651" + integrity sha512-N7ck946hz2LNZxVveeMA3nWawFwYxfd0LYVXBwLJJvOrOx/8QBTFMuqqz+qUZecjDPpMxgNWsRSU/pTy5B7CSw==