@mediafox/core 1.2.13 → 1.2.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"compositor.d.ts","sourceRoot":"","sources":["../../src/compositor/compositor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"compositor.d.ts","sourceRoot":"","sources":["../../src/compositor/compositor.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- class I{events=new Map;maxListeners;captureRejections;emitCache=[];constructor(O={}){this.maxListeners=O.maxListeners??10,this.captureRejections=O.captureRejections??!1}on(O,$){if(!this.events.has(O))this.events.set(O,new Set);let K=this.events.get(O);if(!K)return()=>{};if(K.size>=this.maxListeners)console.warn(`MaxListenersExceededWarning: Possible EventEmitter memory leak detected. ${K.size} ${String(O)} listeners added. Use emitter.setMaxListeners() to increase limit`);let j=$;return K.add(j),()=>{K.delete(j)}}once(O,$){let K=(j)=>{this.off(O,K),$(j)};return this.on(O,K)}off(O,$){let K=this.events.get(O);if(!K)return;if($){let j=$;K.delete(j)}else K.clear()}emit(O,$){let K=this.events.get(O);if(!K||K.size===0)return;let j=this.emitCache;j.length=0;for(let Q of K)j.push(Q);for(let Q=0;Q<j.length;Q++){let V=j[Q];try{let J=V($);if(this.captureRejections&&YO(J))this.handlePromiseRejection(J)}catch(J){if(this.captureRejections&&this.events.has("error"))this.emit("error",J);else throw J}}}handlePromiseRejection(O){O.catch(($)=>{if(this.events.has("error"))this.emit("error",$);else throw $})}removeAllListeners(O){if(O)this.events.delete(O);else this.events.clear()}setMaxListeners(O){this.maxListeners=O}getMaxListeners(){return this.maxListeners}listeners(O){let $=this.events.get(O);return $?Array.from($):[]}listenerCount(O){let $=this.events.get(O);return $?$.size:0}eventNames(){return Array.from(this.events.keys())}}function YO(O){if(!O||typeof O!=="object"&&typeof O!=="function")return!1;let $=O;return typeof $.then==="function"&&typeof $.catch==="function"}class s{audioContext;masterGain;activeSources=new Map;activeSourceIdsScratch=new Set;playing=!1;disposed=!1;playbackId=0;startContextTime=0;startMediaTime=0;pauseTime=0;masterVolume=1;masterMuted=!1;constructor(O={}){if(O.audioContext)this.audioContext=O.audioContext;else{let $=globalThis,K=$.AudioContext||$.webkitAudioContext;if(!K)throw Error("AudioContext is not supported in this environment");this.audioContext=new K}this.masterGain=this.audioContext.createGain(),this.masterGain.connect(this.audioContext.destination)}registerSource(O,$){if(this.disposed)return;let K=this.audioContext.createGain(),j=this.audioContext.createStereoPanner();K.connect(j),j.connect(this.masterGain),this.activeSources.set(O.id,{sourceId:O.id,bufferSink:$,iterator:null,gainNode:K,panNode:j,queuedNodes:new Set,volume:1,pan:0,muted:!1,startSourceTime:0,currentSourceTime:0,iteratorStartTime:0,lastScheduledTime:0})}unregisterSource(O){let $=this.activeSources.get(O);if(!$)return;this.stopSourceAudio($),$.gainNode.disconnect(),$.panNode.disconnect(),this.activeSources.delete(O)}hasSource(O){return this.activeSources.has(O)}processAudioLayers(O,$){if(this.disposed)return;let K=this.activeSourceIdsScratch;K.clear();for(let j of O){let Q=j.source.id;K.add(Q);let V=this.activeSources.get(Q);if(!V)continue;let J=j.volume??1,U=j.pan??0,Z=j.muted??!1,L=j.sourceTime??$;if(V.volume!==J||V.muted!==Z)V.volume=J,V.muted=Z,V.gainNode.gain.value=Z?0:J*J;if(V.pan!==U)V.pan=U,V.panNode.pan.value=Math.max(-1,Math.min(1,U));if(Math.abs(L-V.currentSourceTime)>0.5&&V.iterator!==null)this.restartSourceIterator(V,L);V.currentSourceTime=L}for(let[j,Q]of this.activeSources)if(!K.has(j)&&Q.iterator!==null)this.stopSourceAudio(Q)}async play(O=this.pauseTime){if(this.playing||this.disposed)return;if(this.audioContext.state==="suspended")await this.audioContext.resume();this.playbackId++,this.playing=!0,this.startContextTime=this.audioContext.currentTime,this.startMediaTime=O,this.pauseTime=O;for(let $ of this.activeSources.values())if($.iterator)$.iterator.return(),$.iterator=null}startSourcePlayback(O,$){let K=this.activeSources.get(O);if(!K||K.iterator!==null)return;this.restartSourceIterator(K,$)}restartSourceIterator(O,$){this.stopSourceAudio(O),O.startSourceTime=$,O.currentSourceTime=$,O.iteratorStartTime=this.audioContext.currentTime,O.iterator=O.bufferSink.buffers($),O.lastScheduledTime=$,this.scheduleSourceBuffers(O,this.playbackId)}async scheduleSourceBuffers(O,$){let K=O.iterator;if(!K)return;try{for await(let{buffer:j,timestamp:Q}of K){if($!==this.playbackId||this.disposed||!this.playing)break;let V=this.audioContext.createBufferSource();V.buffer=j,V.connect(O.gainNode);let J=Q-O.startSourceTime,U=O.iteratorStartTime+J;if(U>=this.audioContext.currentTime)V.start(U);else{let A=this.audioContext.currentTime-U;if(A<j.duration)V.start(this.audioContext.currentTime,A);else continue}O.queuedNodes.add(V),V.onended=()=>{O.queuedNodes.delete(V)},O.lastScheduledTime=Q;let Z=this.audioContext.currentTime-O.iteratorStartTime;if(Q-O.startSourceTime-Z>1)await this.waitForCatchup(O,Q)}}catch{}}async waitForCatchup(O,$){return new Promise((K)=>{let j=setInterval(()=>{if(!this.playing||this.disposed){clearInterval(j),K();return}let Q=this.audioContext.currentTime-O.iteratorStartTime;if($-O.startSourceTime-Q<1)clearInterval(j),K()},100)})}pause(){if(!this.playing)return;this.pauseTime=this.getCurrentTime(),this.playing=!1;for(let O of this.activeSources.values())this.stopSourceAudio(O)}stop(){this.pause(),this.pauseTime=0,this.startContextTime=0,this.startMediaTime=0}async seek(O){let $=this.playing;if(this.pause(),this.pauseTime=O,this.startMediaTime=O,$)await this.play(O)}stopSourceAudio(O){for(let $ of O.queuedNodes)try{$.stop()}catch{}if(O.queuedNodes.clear(),O.iterator)O.iterator.return(),O.iterator=null}getCurrentTime(){if(this.playing)return this.startMediaTime+(this.audioContext.currentTime-this.startContextTime);return this.pauseTime}setMasterVolume(O){this.masterVolume=Math.max(0,Math.min(1,O)),this.updateMasterGain()}setMasterMuted(O){this.masterMuted=O,this.updateMasterGain()}updateMasterGain(){let O=this.masterMuted?0:this.masterVolume;this.masterGain.gain.value=O*O}getAudioContext(){return this.audioContext}isPlaying(){return this.playing}dispose(){if(this.disposed)return;this.disposed=!0,this.playbackId++,this.stop();for(let O of this.activeSources.values())this.stopSourceAudio(O),O.gainNode.disconnect(),O.panNode.disconnect();if(this.activeSources.clear(),this.masterGain.disconnect(),this.audioContext.state!=="closed")this.audioContext.close()}}import{ALL_FORMATS as NO,AudioBufferSink as JO,BlobSource as DO,BufferSource as _O,CanvasSink as EO,FilePathSource as MO,Input as qO,ReadableStreamSource as CO,UrlSource as RO}from"mediabunny";class UO{id;type="video";duration;width;height;data;disposed=!1;constructor(O,$,K,j,Q){this.id=O,this.data=$,this.duration=K,this.width=j,this.height=Q}async getFrameAt(O){if(this.disposed)return null;return this.withLock(async()=>{if(this.disposed)return null;let $=this.data.currentFrame;if($){let V=$.timestamp+($.duration||0);if(O>=$.timestamp&&($.duration?O<V:O===$.timestamp))return this.data.lastRequestedTime=O,$.canvas}let K=this.data.lastRequestedTime;if(this.data.iterator===null||O<K||Math.abs(O-K)>this.data.seekThresholdSeconds)await this.restartIterator(O);let Q=await this.advanceToTime(O);return this.data.lastRequestedTime=O,Q?.canvas??null})}async restartIterator(O){if(this.data.iterator)try{await this.data.iterator.return()}catch{}this.data.iterator=this.data.canvasSink.canvases(O),this.data.currentFrame=null,this.data.nextFrame=null}async advanceToTime(O){let $=this.data.iterator;if(!$)return this.data.canvasSink.getCanvas(O);while(!0){let K=this.data.nextFrame;if(K){if(K.timestamp>O)return this.data.currentFrame;this.data.currentFrame=K,this.data.nextFrame=null;continue}let j;try{j=await $.next()}catch{try{return await this.data.canvasSink.getCanvas(O)}catch{return null}}if(j.done)return this.data.currentFrame;this.data.nextFrame=j.value}}async withLock(O){let $=this.data.lock.catch(()=>{}),K=()=>{},j=new Promise((Q)=>{K=()=>{Q()}});this.data.lock=$.then(()=>j),await $;try{return await O()}finally{K()}}getAudioBufferSink(){return this.data.audioBufferSink}hasAudio(){return this.data.audioBufferSink!==null}clearCache(){}dispose(){if(this.disposed)return;if(this.disposed=!0,this.data.iterator){try{this.data.iterator.return()}catch{}this.data.iterator=null}this.data.currentFrame=null,this.data.nextFrame=null,this.data.input.dispose()}}class LO{id;type="image";duration=1/0;width;height;data;disposed=!1;constructor(O,$){this.id=O,this.data=$,this.width=$.image.width,this.height=$.image.height}async getFrameAt(O){if(this.disposed)return null;return this.data.image}dispose(){if(this.disposed)return;if(this.disposed=!0,"close"in this.data.image)this.data.image.close()}}class ZO{id;type="audio";duration;width=0;height=0;data;disposed=!1;constructor(O,$,K){this.id=O,this.data=$,this.duration=K}async getFrameAt(O){return null}getAudioBufferSink(){return this.data.audioBufferSink}dispose(){if(this.disposed)return;this.disposed=!0,this.data.input.dispose()}}class x{sources=new Map;audioContext=null;nextId=0;constructor(O){this.audioContext=O??null}generateId(){return`source_${this.nextId++}`}async loadVideo(O,$={}){let K=$.id??this.generateId(),j=this.createInput(O),Q=await j.getVideoTracks();if(Q.length===0)throw j.dispose(),Error("Source has no video track");let V=Q[0];if(!await V.canDecode())throw j.dispose(),Error(`Cannot decode video track with codec: ${V.codec}`);let U=new EO(V,{poolSize:4}),Z=await V.computeDuration(),L=0.75,A=null,G=null;try{let N=await j.getAudioTracks();if(N.length>0){if(A=N[0],await A.canDecode())G=new JO(A)}}catch{}let X=new UO(K,{input:j,videoTrack:V,canvasSink:U,iterator:null,currentFrame:null,nextFrame:null,lastRequestedTime:-1/0,seekThresholdSeconds:L,lock:Promise.resolve(),audioTrack:A,audioBufferSink:G},Z,V.displayWidth,V.displayHeight);return this.sources.set(K,X),X}async loadImage(O){let $=this.generateId(),K;if(typeof O!=="string")K=await createImageBitmap(O);else if(typeof Image>"u"){let Q=await fetch(O);if(!Q.ok)throw Error(`Failed to load image: ${O}`);let V=await Q.blob();K=await createImageBitmap(V)}else K=await new Promise((Q,V)=>{let J=new Image;J.onload=()=>Q(J),J.onerror=()=>V(Error(`Failed to load image: ${O}`)),J.crossOrigin="anonymous",J.src=O});let j=new LO($,{image:K});return this.sources.set($,j),j}async loadAudio(O,$={}){let K=$.id??this.generateId(),j=this.createInput(O),Q=await j.getAudioTracks();if(Q.length===0)throw j.dispose(),Error("Source has no audio track");let V=Q[0];if(!await V.canDecode())throw j.dispose(),Error(`Cannot decode audio track with codec: ${V.codec}`);let U=await V.computeDuration(),Z=new JO(V),L=new ZO(K,{input:j,audioTrack:V,audioBufferSink:Z},U);return this.sources.set(K,L),L}createInput(O){let $;if(O instanceof File||O instanceof Blob)$=new DO(O);else if(O instanceof ArrayBuffer||O instanceof Uint8Array)$=new _O(O);else if(typeof O==="string"||O instanceof URL){let K=O instanceof URL?O.href:O;if(typeof window>"u"&&!K.startsWith("http"))$=new MO(K);else $=new RO(K)}else if(typeof ReadableStream<"u"&&O instanceof ReadableStream)$=new CO(O);else throw Error("Unsupported source type");return new qO({source:$,formats:NO})}getSource(O){return this.sources.get(O)}hasSource(O){return this.sources.has(O)}unloadSource(O){let $=this.sources.get(O);if($)return $.dispose(),this.sources.delete(O),!0;return!1}getAllSources(){return Array.from(this.sources.values())}clear(){for(let O of this.sources.values())O.dispose();this.sources.clear()}dispose(){if(this.clear(),this.audioContext&&this.audioContext.state!=="closed")this.audioContext.close();this.audioContext=null}}class i{worker;nextId=1;pending=new Map;ready;constructor(O){let $=typeof O.worker==="boolean"?{}:O.worker??{},K=$.type??"module",j=$.url??new URL("./compositor-worker.js",import.meta.url);this.worker=new Worker(j,{type:K}),this.worker.onmessage=(J)=>{let{id:U,ok:Z,result:L,error:A}=J.data,G=this.pending.get(U);if(!G)return;if(this.pending.delete(U),Z)G.resolve(L);else G.reject(Error(A??"Worker error"))},this.worker.onerror=(J)=>{let U=J.error instanceof Error?J.error:Error("Worker error");for(let Z of this.pending.values())Z.reject(U);this.pending.clear()};let Q=O.canvas.transferControlToOffscreen(),V={canvas:Q,width:O.width,height:O.height,backgroundColor:O.backgroundColor};this.ready=this.call("init",V,[Q])}postMessage(O,$,K){let j=this.nextId++;return this.worker.postMessage({id:j,kind:O,payload:$},K??[]),j}call(O,$,K){let j=this.postMessage(O,$,K);return new Promise((Q,V)=>{this.pending.set(j,{resolve:Q,reject:V})})}async loadSource(O,$){await this.ready;let K={source:O,options:$};return this.call("loadSource",K)}async loadImage(O){await this.ready;let $={source:O};return this.call("loadImage",$)}async loadAudio(O,$){await this.ready;let K={source:O,options:$};return this.call("loadAudio",K)}async unloadSource(O){await this.ready;let $={id:O};return this.call("unloadSource",$)}async render(O){await this.ready;let $={frame:O};return this.call("render",$)}async clear(){return await this.ready,this.call("clear")}async resize(O,$,K){await this.ready;let j={width:O,height:$,fitMode:K};return this.call("resize",j)}async exportFrame(O,$){await this.ready;let K={frame:O,options:$};return this.call("exportFrame",K)}dispose(){try{this.worker.postMessage({id:this.nextId++,kind:"dispose"})}catch{}this.worker.terminate(),this.pending.clear()}}class a{canvas;ctx=null;width;height;backgroundColor;fitMode;sourcePool;audioManager=null;workerClient=null;workerSources=new Map;workerAudioSources=new Map;emitter;state;animationFrameId=null;lastFrameTime=0;lastRenderTime=0;previewOptions=null;disposed=!1;renderBuffers={visibleLayers:[],framePromises:[],frameImages:[]};lastTimeUpdateEmit=0;timeUpdateThrottleMs=100;renderPending=!1;activeAudioSourceIds=new Set;audioScratch={nextActiveSourceIds:new Set,newSourceIds:[],newSourceTimes:[]};registeredAudioSources=new Set;pendingPlayAfterSeek=!1;constructor(O){this.canvas=O.canvas,this.width=O.width??(this.canvas.width||1920),this.height=O.height??(this.canvas.height||1080),this.backgroundColor=O.backgroundColor??"#000000",this.fitMode=O.fitMode??"fill",this.emitter=new I({maxListeners:50}),this.state={playing:!1,currentTime:0,duration:0,seeking:!1},this.canvas.width=this.width,this.canvas.height=this.height;let $=typeof O.worker==="boolean"?O.worker:O.worker?O.worker.enabled??!0:!1,K=$&&typeof Worker<"u"&&typeof OffscreenCanvas<"u"&&typeof this.canvas.transferControlToOffscreen==="function"&&!(this.canvas instanceof OffscreenCanvas);if($&&!K)throw Error("Worker compositor requires HTMLCanvasElement, OffscreenCanvas, and Worker support");if(this.sourcePool=new x,K)try{this.workerClient=new i({canvas:this.canvas,width:this.width,height:this.height,backgroundColor:this.backgroundColor,worker:O.worker??!0})}catch(j){console.warn("[Compositor] Worker initialization failed, falling back to main thread rendering:",j),this.workerClient=null}if(O.enableAudio!==!1)this.audioManager=new s;if(!this.workerClient){if(this.ctx=this.canvas.getContext("2d",{alpha:!1,desynchronized:!0}),!this.ctx)throw Error("Failed to get 2D context for compositor canvas");this.clear()}}async loadSource(O,$){if(this.checkDisposed(),this.workerClient){let j=await this.workerClient.loadSource(O,$),Q=this.createWorkerSource(j);if(this.audioManager&&j.hasAudio)await this.loadWorkerAudio(O,Q.id);return this.emitter.emit("sourceloaded",{id:Q.id,source:Q}),Q}let K=await this.sourcePool.loadVideo(O,$);return this.registerSourceAudio(K),this.emitter.emit("sourceloaded",{id:K.id,source:K}),K}async loadImage(O){if(this.checkDisposed(),this.workerClient){let K=await this.workerClient.loadImage(O),j=this.createWorkerSource(K);return this.emitter.emit("sourceloaded",{id:j.id,source:j}),j}let $=await this.sourcePool.loadImage(O);return this.emitter.emit("sourceloaded",{id:$.id,source:$}),$}async loadAudio(O,$){if(this.checkDisposed(),this.workerClient){let j=await this.workerClient.loadAudio(O,$),Q=this.createWorkerSource(j);if(this.audioManager)await this.loadWorkerAudio(O,Q.id);return this.emitter.emit("sourceloaded",{id:Q.id,source:Q}),Q}let K=await this.sourcePool.loadAudio(O,$);return this.registerSourceAudio(K),this.emitter.emit("sourceloaded",{id:K.id,source:K}),K}unloadSource(O){if(this.workerClient){if(!this.workerSources.get(O))return!1;return this.workerClient.unloadSource(O),this.workerSources.delete(O),this.unloadWorkerAudio(O),this.emitter.emit("sourceunloaded",{id:O}),!0}if(this.registeredAudioSources.has(O))this.audioManager?.unregisterSource(O),this.registeredAudioSources.delete(O);let $=this.sourcePool.unloadSource(O);if($)this.emitter.emit("sourceunloaded",{id:O});return $}registerSourceAudio(O){if(!this.audioManager)return;if(this.registeredAudioSources.has(O.id))return;let $=O.getAudioBufferSink?.();if($)this.audioManager.registerSource(O,$),this.registeredAudioSources.add(O.id)}processAudioLayers(O,$){if(!this.audioManager)return;let K=this.audioScratch.newSourceIds,j=this.audioScratch.newSourceTimes,Q=this.audioScratch.nextActiveSourceIds,V=this.activeAudioSourceIds;K.length=0,j.length=0,Q.clear();for(let J=0;J<O.length;J++){let U=O[J];if(U.muted)continue;let Z=U.source.id;if(!this.audioManager.hasSource(Z))continue;if(Q.add(Z),!V.has(Z))K.push(Z),j.push(U.sourceTime??$)}if(V.size>0)V.clear();for(let J of Q)V.add(J);this.audioManager.processAudioLayers(O,$);for(let J=0;J<K.length;J++)this.audioManager.startSourcePlayback(K[J],j[J])}getSource(O){if(this.workerClient)return this.workerSources.get(O);return this.sourcePool.getSource(O)}getAllSources(){if(this.workerClient)return Array.from(this.workerSources.values());return this.sourcePool.getAllSources()}async render(O){if(this.checkDisposed(),this.workerClient){let L=this.serializeWorkerFrame(O);return this.workerClient.render(L)}let $=this.ctx;if(!$)return!1;let{visibleLayers:K,framePromises:j,frameImages:Q}=this.renderBuffers;K.length=0,j.length=0,Q.length=0;let V=!1,J=-1/0,U=O.layers;for(let L=0;L<U.length;L++){let A=U[L];if(A.visible===!1)continue;let G=A.zIndex??0;if(G<J)V=!0;J=G,K.push(A)}if(K.length===0)return $.fillStyle=this.backgroundColor,$.fillRect(0,0,this.width,this.height),!0;if(V)K.sort((L,A)=>(L.zIndex??0)-(A.zIndex??0));for(let L=0;L<K.length;L++){let A=K[L],G=A.sourceTime??O.time;j[L]=A.source.getFrameAt(G)}let Z=await Promise.all(j);for(let L=0;L<Z.length;L++)Q[L]=Z[L]??null;$.fillStyle=this.backgroundColor,$.fillRect(0,0,this.width,this.height);for(let L=0;L<K.length;L++){let A=Q[L];if(A)this.renderLayer(A,K[L])}return!0}renderLayer(O,$){let K=this.ctx;if(!K)return;let j=$.transform,Q=$.source.width??this.width,V=$.source.height??this.height,J=$.fitMode===void 0||$.fitMode==="auto"?this.fitMode:$.fitMode,U=Q,Z=V,L=0,A=0;if(Q===0||V===0)U=this.width,Z=this.height;else if(J==="none")U=Q,Z=V,L=(this.width-U)/2,A=(this.height-Z)/2;else{let P=Q/V,z=this.width/this.height;switch(J){case"fill":U=this.width,Z=this.height;break;case"cover":if(P>z)Z=this.height,U=this.height*P,L=(this.width-U)/2;else U=this.width,Z=this.width/P,A=(this.height-Z)/2;break;default:if(P>z)U=this.width,Z=this.width/P,A=(this.height-Z)/2;else Z=this.height,U=this.height*P,L=(this.width-U)/2;break}}if(!j){K.drawImage(O,L,A,U,Z);return}let G=(j.x??0)+L,X=(j.y??0)+A,N=j.width??U,Y=j.height??Z,M=j.rotation??0,q=j.scaleX??1,C=j.scaleY??1,S=j.opacity??1,R=j.filter,W=S!==1,b=M!==0||q!==1||C!==1,w=!!R&&R!=="none";if(!(W||b||w)){K.drawImage(O,G,X,N,Y);return}if(!b){if(K.save(),W)K.globalAlpha=S;if(w)K.filter=R;K.drawImage(O,G,X,N,Y),K.restore();return}let _=j.anchorX??0.5,B=j.anchorY??0.5;if(K.save(),W)K.globalAlpha=S;if(w)K.filter=R;if(K.translate(G+N*_,X+Y*B),M!==0)K.rotate(M*Math.PI/180);if(q!==1||C!==1)K.scale(q,C);K.drawImage(O,-N*_,-Y*B,N,Y),K.restore()}createWorkerSource(O){let $={id:O.id,type:O.type,duration:O.duration,width:O.width,height:O.height,async getFrameAt(){throw Error("getFrameAt is not available when worker rendering is enabled")},getAudioBufferSink(){return null},hasAudio(){return O.hasAudio??!1},dispose(){}};return this.workerSources.set($.id,$),$}async loadWorkerAudio(O,$){if(!this.audioManager)return;if(this.workerAudioSources.has($))this.unloadWorkerAudio($);try{let K=await this.sourcePool.loadAudio(O,{id:$});this.workerAudioSources.set($,K),this.registerSourceAudio(K)}catch{}}unloadWorkerAudio(O){if(!this.audioManager)return;if(this.workerAudioSources.has(O))this.audioManager.unregisterSource(O),this.registeredAudioSources.delete(O),this.sourcePool.unloadSource(O),this.workerAudioSources.delete(O)}serializeWorkerFrame(O){if(!this.workerClient)throw Error("Worker compositor not initialized");let $=O.layers,K=Array($.length);for(let j=0;j<$.length;j++){let Q=$[j],V=Q.source.id;if(!this.workerSources.has(V))throw Error(`Layer source ${V} is not managed by this compositor`);K[j]={sourceId:V,sourceTime:Q.sourceTime,transform:Q.transform,fitMode:Q.fitMode,visible:Q.visible,zIndex:Q.zIndex}}return{time:O.time,layers:K}}clear(){if(this.workerClient){this.workerClient.clear();return}if(!this.ctx)return;this.ctx.fillStyle=this.backgroundColor,this.ctx.fillRect(0,0,this.width,this.height)}preview(O){this.checkDisposed(),this.previewOptions=O,this.state.duration=O.duration,this.lastRenderTime=0,this.emitter.emit("compositionchange",void 0)}async play(){if(this.checkDisposed(),this.state.playing)return;if(!this.previewOptions)throw Error("No preview configured. Call preview() first.");if(this.state.seeking){this.pendingPlayAfterSeek=!0;return}if(this.state.playing=!0,this.lastFrameTime=performance.now(),this.lastRenderTime=this.lastFrameTime,this.emitter.emit("play",void 0),this.audioManager){this.activeAudioSourceIds.clear(),await this.audioManager.play(this.state.currentTime);let O=this.previewOptions.getComposition(this.state.currentTime);this.processAudioLayers(O.audio??[],this.state.currentTime)}this.startRenderLoop()}pause(){if(this.checkDisposed(),!this.state.playing)return;if(this.state.playing=!1,this.pendingPlayAfterSeek=!1,this.stopRenderLoop(),this.audioManager)this.audioManager.pause();this.emitter.emit("pause",void 0)}async seek(O){if(this.checkDisposed(),!this.previewOptions)return;let $=Math.max(0,Math.min(O,this.state.duration));if(this.state.seeking=!0,this.emitter.emit("seeking",{time:$}),this.state.currentTime=$,this.audioManager)await this.audioManager.seek($),this.activeAudioSourceIds.clear();let K=this.previewOptions.getComposition($);if(this.audioManager)this.processAudioLayers(K.audio??[],$);if(await this.render(K),this.state.seeking=!1,this.emitter.emit("seeked",{time:$}),this.emitter.emit("timeupdate",{currentTime:$}),this.pendingPlayAfterSeek)this.pendingPlayAfterSeek=!1,await this.play()}startRenderLoop(){if(this.animationFrameId!==null)return;let O=()=>{if(!this.state.playing||!this.previewOptions)return;this.animationFrameId=requestAnimationFrame(O);let $=performance.now(),K=($-this.lastFrameTime)/1000;if(this.lastFrameTime=$,this.state.currentTime+=K,this.state.currentTime>=this.state.duration)if(this.previewOptions.loop)this.state.currentTime=0;else{this.state.currentTime=this.state.duration,this.pause(),this.emitter.emit("ended",void 0);return}let j=this.previewOptions.fps??0,Q=j>0?1000/j:0;if(!this.renderPending&&(Q===0||$-this.lastRenderTime>=Q)){this.renderPending=!0,this.lastRenderTime=$;let J=this.previewOptions.getComposition(this.state.currentTime);if(this.audioManager)this.processAudioLayers(J.audio??[],this.state.currentTime);this.render(J).catch(()=>{}).finally(()=>{this.renderPending=!1})}if($-this.lastTimeUpdateEmit>=this.timeUpdateThrottleMs)this.lastTimeUpdateEmit=$,this.emitter.emit("timeupdate",{currentTime:this.state.currentTime})};this.animationFrameId=requestAnimationFrame(O)}stopRenderLoop(){if(this.animationFrameId!==null)cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null}async exportFrame(O,$={}){if(this.checkDisposed(),!this.previewOptions)return null;let K=this.previewOptions.getComposition(O);if(this.workerClient){let j=this.serializeWorkerFrame(K);return this.workerClient.exportFrame(j,$)}if(await this.render(K),"toBlob"in this.canvas)return new Promise((j)=>{this.canvas.toBlob((Q)=>j(Q),`image/${$.format??"png"}`,$.quality)});else return this.canvas.convertToBlob({type:`image/${$.format??"png"}`,quality:$.quality})}get currentTime(){return this.state.currentTime}get duration(){return this.state.duration}get playing(){return this.state.playing}get paused(){return!this.state.playing}get seeking(){return this.state.seeking}getWidth(){return this.width}getHeight(){return this.height}resize(O,$,K){if(this.checkDisposed(),this.width=O,this.height=$,K!==void 0)this.fitMode=K;if(this.workerClient){this.workerClient.resize(O,$,this.fitMode);return}this.canvas.width=O,this.canvas.height=$,this.clear()}setFitMode(O){if(this.checkDisposed(),this.fitMode=O,this.workerClient)this.workerClient.resize(this.width,this.height,O)}getFitMode(){return this.fitMode}on(O,$){return this.emitter.on(O,$)}once(O,$){return this.emitter.once(O,$)}off(O,$){this.emitter.off(O,$)}setVolume(O){this.audioManager?.setMasterVolume(O)}setMuted(O){this.audioManager?.setMasterMuted(O)}getAudioContext(){if(!this.audioManager)throw Error("Audio is disabled for this compositor");return this.audioManager.getAudioContext()}checkDisposed(){if(this.disposed)throw Error("Compositor has been disposed")}dispose(){if(this.disposed)return;this.disposed=!0,this.stopRenderLoop(),this.audioManager?.dispose(),this.workerClient?.dispose(),this.workerClient=null,this.sourcePool.dispose(),this.registeredAudioSources.clear(),this.activeAudioSourceIds.clear(),this.audioScratch.nextActiveSourceIds.clear(),this.audioScratch.newSourceIds.length=0,this.audioScratch.newSourceTimes.length=0,this.workerSources.clear(),this.workerAudioSources.clear(),this.emitter.removeAllListeners(),this.ctx=null,this.previewOptions=null}}import{CanvasSink as FO,VideoSampleSink as SO}from"mediabunny";class y{canvas;ctx=null;isInitialized=!1;rotation=0;constructor(O){this.canvas=O.canvas,this.rotation=O.rotation??0,this.initialize()}initialize(){try{if(this.ctx=this.canvas.getContext("2d",{alpha:!1,desynchronized:!0}),!this.ctx)return!1;return this.ctx.imageSmoothingEnabled=!0,this.ctx.imageSmoothingQuality="high",this.isInitialized=!0,!0}catch{return!1}}isReady(){return this.isInitialized&&this.ctx!==null}render(O){if(!this.isReady()||!this.ctx)return!1;try{let{width:$,height:K}=O;if($===0||K===0)return!1;let j=this.canvas.width,Q=this.canvas.height;if(j===0||Q===0)return!1;let V=this.rotation===90||this.rotation===270,J=V?K:$,U=V?$:K,Z=Math.min(j/J,Q/U),L=Math.round(J*Z),A=Math.round(U*Z),G=Math.round((j-L)/2),X=Math.round((Q-A)/2);if(this.ctx.fillStyle="black",this.ctx.fillRect(0,0,j,Q),this.ctx.save(),this.ctx.translate(G+L/2,X+A/2),this.rotation!==0)this.ctx.rotate(this.rotation*Math.PI/180);if(V)this.ctx.drawImage(O,0,0,$,K,-A/2,-L/2,A,L);else this.ctx.drawImage(O,0,0,$,K,-L/2,-A/2,L,A);return this.ctx.restore(),!0}catch{return!1}}clear(){if(!this.isReady()||!this.ctx)return;this.ctx.fillStyle="black",this.ctx.fillRect(0,0,this.canvas.width,this.canvas.height)}setRotation(O){this.rotation=O}getRotation(){return this.rotation}dispose(){this.ctx=null,this.isInitialized=!1}}class r{resources;isInitialized=!1;canvas;textureWidth=0;textureHeight=0;options;boundHandleContextLost=null;boundHandleContextRestored=null;rotation=0;positionsArray=new Float32Array(8);vertexShaderSource=`
1
+ class x{events=new Map;maxListeners;captureRejections;emitCache=[];constructor(O={}){this.maxListeners=O.maxListeners??10,this.captureRejections=O.captureRejections??!1}on(O,$){if(!this.events.has(O))this.events.set(O,new Set);let K=this.events.get(O);if(!K)return()=>{};if(K.size>=this.maxListeners)console.warn(`MaxListenersExceededWarning: Possible EventEmitter memory leak detected. ${K.size} ${String(O)} listeners added. Use emitter.setMaxListeners() to increase limit`);let j=$;return K.add(j),()=>{K.delete(j)}}once(O,$){let K=(j)=>{this.off(O,K),$(j)};return this.on(O,K)}off(O,$){let K=this.events.get(O);if(!K)return;if($){let j=$;K.delete(j)}else K.clear()}emit(O,$){let K=this.events.get(O);if(!K||K.size===0)return;let j=this.emitCache;j.length=0;for(let Q of K)j.push(Q);for(let Q=0;Q<j.length;Q++){let V=j[Q];try{let J=V($);if(this.captureRejections&&NO(J))this.handlePromiseRejection(J)}catch(J){if(this.captureRejections&&this.events.has("error"))this.emit("error",J);else throw J}}}handlePromiseRejection(O){O.catch(($)=>{if(this.events.has("error"))this.emit("error",$);else throw $})}removeAllListeners(O){if(O)this.events.delete(O);else this.events.clear()}setMaxListeners(O){this.maxListeners=O}getMaxListeners(){return this.maxListeners}listeners(O){let $=this.events.get(O);return $?Array.from($):[]}listenerCount(O){let $=this.events.get(O);return $?$.size:0}eventNames(){return Array.from(this.events.keys())}}function NO(O){if(!O||typeof O!=="object"&&typeof O!=="function")return!1;let $=O;return typeof $.then==="function"&&typeof $.catch==="function"}class s{audioContext;masterGain;activeSources=new Map;activeSourceIdsScratch=new Set;playing=!1;disposed=!1;playbackId=0;startContextTime=0;startMediaTime=0;pauseTime=0;masterVolume=1;masterMuted=!1;constructor(O={}){if(O.audioContext)this.audioContext=O.audioContext;else{let $=globalThis,K=$.AudioContext||$.webkitAudioContext;if(!K)throw Error("AudioContext is not supported in this environment");this.audioContext=new K}this.masterGain=this.audioContext.createGain(),this.masterGain.connect(this.audioContext.destination)}registerSource(O,$){if(this.disposed)return;let K=this.audioContext.createGain(),j=this.audioContext.createStereoPanner();K.connect(j),j.connect(this.masterGain),this.activeSources.set(O.id,{sourceId:O.id,bufferSink:$,iterator:null,gainNode:K,panNode:j,queuedNodes:new Set,volume:1,pan:0,muted:!1,startSourceTime:0,currentSourceTime:0,iteratorStartTime:0,lastScheduledTime:0})}unregisterSource(O){let $=this.activeSources.get(O);if(!$)return;this.stopSourceAudio($),$.gainNode.disconnect(),$.panNode.disconnect(),this.activeSources.delete(O)}hasSource(O){return this.activeSources.has(O)}processAudioLayers(O,$){if(this.disposed)return;let K=this.activeSourceIdsScratch;K.clear();for(let j of O){let Q=j.source.id;K.add(Q);let V=this.activeSources.get(Q);if(!V)continue;let J=j.volume??1,U=j.pan??0,G=j.muted??!1,Z=j.sourceTime??$;if(V.volume!==J||V.muted!==G)V.volume=J,V.muted=G,V.gainNode.gain.value=G?0:J*J;if(V.pan!==U)V.pan=U,V.panNode.pan.value=Math.max(-1,Math.min(1,U));if(Math.abs(Z-V.currentSourceTime)>0.5&&V.iterator!==null)this.restartSourceIterator(V,Z);V.currentSourceTime=Z}for(let[j,Q]of this.activeSources)if(!K.has(j)&&Q.iterator!==null)this.stopSourceAudio(Q)}async play(O=this.pauseTime){if(this.playing||this.disposed)return;if(this.audioContext.state==="suspended")await this.audioContext.resume();this.playbackId++,this.playing=!0,this.startContextTime=this.audioContext.currentTime,this.startMediaTime=O,this.pauseTime=O;for(let $ of this.activeSources.values())if($.iterator)$.iterator.return(),$.iterator=null}startSourcePlayback(O,$){let K=this.activeSources.get(O);if(!K||K.iterator!==null)return;this.restartSourceIterator(K,$)}restartSourceIterator(O,$){this.stopSourceAudio(O),O.startSourceTime=$,O.currentSourceTime=$,O.iteratorStartTime=this.audioContext.currentTime,O.iterator=O.bufferSink.buffers($),O.lastScheduledTime=$,this.scheduleSourceBuffers(O,this.playbackId)}async scheduleSourceBuffers(O,$){let K=O.iterator;if(!K)return;try{for await(let{buffer:j,timestamp:Q}of K){if($!==this.playbackId||this.disposed||!this.playing)break;let V=this.audioContext.createBufferSource();V.buffer=j,V.connect(O.gainNode);let J=Q-O.startSourceTime,U=O.iteratorStartTime+J;if(U>=this.audioContext.currentTime)V.start(U);else{let L=this.audioContext.currentTime-U;if(L<j.duration)V.start(this.audioContext.currentTime,L);else continue}O.queuedNodes.add(V),V.onended=()=>{O.queuedNodes.delete(V)},O.lastScheduledTime=Q;let G=this.audioContext.currentTime-O.iteratorStartTime;if(Q-O.startSourceTime-G>1)await this.waitForCatchup(O,Q)}}catch{}}async waitForCatchup(O,$){return new Promise((K)=>{let j=setInterval(()=>{if(!this.playing||this.disposed){clearInterval(j),K();return}let Q=this.audioContext.currentTime-O.iteratorStartTime;if($-O.startSourceTime-Q<1)clearInterval(j),K()},100)})}pause(){if(!this.playing)return;this.pauseTime=this.getCurrentTime(),this.playing=!1;for(let O of this.activeSources.values())this.stopSourceAudio(O)}stop(){this.pause(),this.pauseTime=0,this.startContextTime=0,this.startMediaTime=0}async seek(O){let $=this.playing;if(this.pause(),this.pauseTime=O,this.startMediaTime=O,$)await this.play(O)}stopSourceAudio(O){for(let $ of O.queuedNodes)try{$.stop()}catch{}if(O.queuedNodes.clear(),O.iterator)O.iterator.return(),O.iterator=null}getCurrentTime(){if(this.playing)return this.startMediaTime+(this.audioContext.currentTime-this.startContextTime);return this.pauseTime}setMasterVolume(O){this.masterVolume=Math.max(0,Math.min(1,O)),this.updateMasterGain()}setMasterMuted(O){this.masterMuted=O,this.updateMasterGain()}updateMasterGain(){let O=this.masterMuted?0:this.masterVolume;this.masterGain.gain.value=O*O}getAudioContext(){return this.audioContext}isPlaying(){return this.playing}dispose(){if(this.disposed)return;this.disposed=!0,this.playbackId++,this.stop();for(let O of this.activeSources.values())this.stopSourceAudio(O),O.gainNode.disconnect(),O.panNode.disconnect();if(this.activeSources.clear(),this.masterGain.disconnect(),this.audioContext.state!=="closed")this.audioContext.close()}}import{ALL_FORMATS as AO,AudioBufferSink as JO,BlobSource as DO,BufferSource as qO,CanvasSink as MO,FilePathSource as CO,Input as _O,ReadableStreamSource as EO,UrlSource as RO}from"mediabunny";class UO{id;type="video";duration;width;height;data;disposed=!1;constructor(O,$,K,j,Q){this.id=O,this.data=$,this.duration=K,this.width=j,this.height=Q}async getFrameAt(O){if(this.disposed)return null;return this.withLock(async()=>{if(this.disposed)return null;let $=this.data.currentFrame;if($){let V=$.timestamp+($.duration||0);if(O>=$.timestamp&&($.duration?O<V:O===$.timestamp))return this.data.lastRequestedTime=O,$.canvas}let K=this.data.lastRequestedTime;if(this.data.iterator===null||O<K||Math.abs(O-K)>this.data.seekThresholdSeconds)await this.restartIterator(O);let Q=await this.advanceToTime(O);return this.data.lastRequestedTime=O,Q?.canvas??null})}async restartIterator(O){if(this.data.iterator)try{await this.data.iterator.return()}catch{}this.data.iterator=this.data.canvasSink.canvases(O),this.data.currentFrame=null,this.data.nextFrame=null}async advanceToTime(O){let $=this.data.iterator;if(!$)return this.data.canvasSink.getCanvas(O);while(!0){let K=this.data.nextFrame;if(K){if(K.timestamp>O)return this.data.currentFrame;this.data.currentFrame=K,this.data.nextFrame=null;continue}let j;try{j=await $.next()}catch{try{return await this.data.canvasSink.getCanvas(O)}catch{return null}}if(j.done)return this.data.currentFrame;this.data.nextFrame=j.value}}async withLock(O){let $=this.data.lock.catch(()=>{}),K=()=>{},j=new Promise((Q)=>{K=()=>{Q()}});this.data.lock=$.then(()=>j),await $;try{return await O()}finally{K()}}getAudioBufferSink(){return this.data.audioBufferSink}hasAudio(){return this.data.audioBufferSink!==null}clearCache(){}dispose(){if(this.disposed)return;if(this.disposed=!0,this.data.iterator){try{this.data.iterator.return()}catch{}this.data.iterator=null}this.data.currentFrame=null,this.data.nextFrame=null,this.data.input.dispose()}}class ZO{id;type="image";duration=1/0;width;height;data;disposed=!1;constructor(O,$){this.id=O,this.data=$,this.width=$.image.width,this.height=$.image.height}async getFrameAt(O){if(this.disposed)return null;return this.data.image}dispose(){if(this.disposed)return;if(this.disposed=!0,"close"in this.data.image)this.data.image.close()}}class GO{id;type="audio";duration;width=0;height=0;data;disposed=!1;constructor(O,$,K){this.id=O,this.data=$,this.duration=K}async getFrameAt(O){return null}getAudioBufferSink(){return this.data.audioBufferSink}dispose(){if(this.disposed)return;this.disposed=!0,this.data.input.dispose()}}class I{sources=new Map;audioContext=null;nextId=0;constructor(O){this.audioContext=O??null}generateId(){return`source_${this.nextId++}`}async loadVideo(O,$={}){let K=$.id??this.generateId(),j=this.createInput(O),Q=await j.getVideoTracks();if(Q.length===0)throw j.dispose(),Error("Source has no video track");let V=Q[0];if(!await V.canDecode())throw j.dispose(),Error(`Cannot decode video track with codec: ${V.codec}`);let U=new MO(V,{poolSize:4}),G=await V.computeDuration(),Z=0.75,L=null,z=null;try{let A=await j.getAudioTracks();if(A.length>0){if(L=A[0],await L.canDecode())z=new JO(L)}}catch{}let Y=new UO(K,{input:j,videoTrack:V,canvasSink:U,iterator:null,currentFrame:null,nextFrame:null,lastRequestedTime:-1/0,seekThresholdSeconds:Z,lock:Promise.resolve(),audioTrack:L,audioBufferSink:z},G,V.displayWidth,V.displayHeight);return this.sources.set(K,Y),Y}async loadImage(O){let $=this.generateId(),K;if(typeof O!=="string")K=await createImageBitmap(O);else if(typeof Image>"u"){let Q=await fetch(O);if(!Q.ok)throw Error(`Failed to load image: ${O}`);let V=await Q.blob();K=await createImageBitmap(V)}else K=await new Promise((Q,V)=>{let J=new Image;J.onload=()=>Q(J),J.onerror=()=>V(Error(`Failed to load image: ${O}`)),J.crossOrigin="anonymous",J.src=O});let j=new ZO($,{image:K});return this.sources.set($,j),j}async loadAudio(O,$={}){let K=$.id??this.generateId(),j=this.createInput(O),Q=await j.getAudioTracks();if(Q.length===0)throw j.dispose(),Error("Source has no audio track");let V=Q[0];if(!await V.canDecode())throw j.dispose(),Error(`Cannot decode audio track with codec: ${V.codec}`);let U=await V.computeDuration(),G=new JO(V),Z=new GO(K,{input:j,audioTrack:V,audioBufferSink:G},U);return this.sources.set(K,Z),Z}createInput(O){let $;if(O instanceof File||O instanceof Blob)$=new DO(O);else if(O instanceof ArrayBuffer||O instanceof Uint8Array)$=new qO(O);else if(typeof O==="string"||O instanceof URL){let K=O instanceof URL?O.href:O;if(typeof window>"u"&&!K.startsWith("http"))$=new CO(K);else $=new RO(K)}else if(typeof ReadableStream<"u"&&O instanceof ReadableStream)$=new EO(O);else throw Error("Unsupported source type");return new _O({source:$,formats:AO})}getSource(O){return this.sources.get(O)}hasSource(O){return this.sources.has(O)}unloadSource(O){let $=this.sources.get(O);if($)return $.dispose(),this.sources.delete(O),!0;return!1}getAllSources(){return Array.from(this.sources.values())}clear(){for(let O of this.sources.values())O.dispose();this.sources.clear()}dispose(){if(this.clear(),this.audioContext&&this.audioContext.state!=="closed")this.audioContext.close();this.audioContext=null}}class i{worker;nextId=1;pending=new Map;ready;constructor(O){let $=typeof O.worker==="boolean"?{}:O.worker??{},K=$.type??"module",j=$.url??new URL("./compositor-worker.js",import.meta.url);this.worker=new Worker(j,{type:K}),this.worker.onmessage=(J)=>{let{id:U,ok:G,result:Z,error:L}=J.data,z=this.pending.get(U);if(!z)return;if(this.pending.delete(U),G)z.resolve(Z);else z.reject(Error(L??"Worker error"))},this.worker.onerror=(J)=>{let U=J.error instanceof Error?J.error:Error("Worker error");for(let G of this.pending.values())G.reject(U);this.pending.clear()};let Q=O.canvas.transferControlToOffscreen(),V={canvas:Q,width:O.width,height:O.height,backgroundColor:O.backgroundColor};this.ready=this.call("init",V,[Q])}postMessage(O,$,K){let j=this.nextId++;return this.worker.postMessage({id:j,kind:O,payload:$},K??[]),j}call(O,$,K){let j=this.postMessage(O,$,K);return new Promise((Q,V)=>{this.pending.set(j,{resolve:Q,reject:V})})}async loadSource(O,$){await this.ready;let K={source:O,options:$};return this.call("loadSource",K)}async loadImage(O){await this.ready;let $={source:O};return this.call("loadImage",$)}async loadAudio(O,$){await this.ready;let K={source:O,options:$};return this.call("loadAudio",K)}async unloadSource(O){await this.ready;let $={id:O};return this.call("unloadSource",$)}async render(O){await this.ready;let $={frame:O};return this.call("render",$)}async clear(){return await this.ready,this.call("clear")}async resize(O,$,K){await this.ready;let j={width:O,height:$,fitMode:K};return this.call("resize",j)}async exportFrame(O,$){await this.ready;let K={frame:O,options:$};return this.call("exportFrame",K)}dispose(){try{this.worker.postMessage({id:this.nextId++,kind:"dispose"})}catch{}this.worker.terminate(),this.pending.clear()}}class a{canvas;ctx=null;width;height;backgroundColor;fitMode;sourcePool;audioManager=null;workerClient=null;workerSources=new Map;workerAudioSources=new Map;emitter;state;animationFrameId=null;lastFrameTime=0;lastRenderTime=0;previewOptions=null;disposed=!1;renderBuffers={visibleLayers:[],framePromises:[],frameImages:[]};lastTimeUpdateEmit=0;timeUpdateThrottleMs=100;renderPending=!1;activeAudioSourceIds=new Set;audioScratch={nextActiveSourceIds:new Set,newSourceIds:[],newSourceTimes:[]};registeredAudioSources=new Set;pendingPlayAfterSeek=!1;constructor(O){this.canvas=O.canvas,this.width=O.width??(this.canvas.width||1920),this.height=O.height??(this.canvas.height||1080),this.backgroundColor=O.backgroundColor??"#000000",this.fitMode=O.fitMode??"fill",this.emitter=new x({maxListeners:50}),this.state={playing:!1,currentTime:0,duration:0,seeking:!1},this.canvas.width=this.width,this.canvas.height=this.height;let $=typeof O.worker==="boolean"?O.worker:O.worker?O.worker.enabled??!0:!1,K=$&&typeof Worker<"u"&&typeof OffscreenCanvas<"u"&&typeof this.canvas.transferControlToOffscreen==="function"&&!(this.canvas instanceof OffscreenCanvas);if($&&!K)throw Error("Worker compositor requires HTMLCanvasElement, OffscreenCanvas, and Worker support");if(this.sourcePool=new I,K)try{this.workerClient=new i({canvas:this.canvas,width:this.width,height:this.height,backgroundColor:this.backgroundColor,worker:O.worker??!0})}catch(j){console.warn("[Compositor] Worker initialization failed, falling back to main thread rendering:",j),this.workerClient=null}if(O.enableAudio!==!1)this.audioManager=new s;if(!this.workerClient){if(this.ctx=this.canvas.getContext("2d",{alpha:!1,desynchronized:!0}),!this.ctx)throw Error("Failed to get 2D context for compositor canvas");this.clear()}}async loadSource(O,$){if(this.checkDisposed(),this.workerClient){let j=await this.workerClient.loadSource(O,$),Q=this.createWorkerSource(j);if(this.audioManager&&j.hasAudio)await this.loadWorkerAudio(O,Q.id);return this.emitter.emit("sourceloaded",{id:Q.id,source:Q}),Q}let K=await this.sourcePool.loadVideo(O,$);return this.registerSourceAudio(K),this.emitter.emit("sourceloaded",{id:K.id,source:K}),K}async loadImage(O){if(this.checkDisposed(),this.workerClient){let K=await this.workerClient.loadImage(O),j=this.createWorkerSource(K);return this.emitter.emit("sourceloaded",{id:j.id,source:j}),j}let $=await this.sourcePool.loadImage(O);return this.emitter.emit("sourceloaded",{id:$.id,source:$}),$}async loadAudio(O,$){if(this.checkDisposed(),this.workerClient){let j=await this.workerClient.loadAudio(O,$),Q=this.createWorkerSource(j);if(this.audioManager)await this.loadWorkerAudio(O,Q.id);return this.emitter.emit("sourceloaded",{id:Q.id,source:Q}),Q}let K=await this.sourcePool.loadAudio(O,$);return this.registerSourceAudio(K),this.emitter.emit("sourceloaded",{id:K.id,source:K}),K}unloadSource(O){if(this.workerClient){if(!this.workerSources.get(O))return!1;return this.workerClient.unloadSource(O),this.workerSources.delete(O),this.unloadWorkerAudio(O),this.emitter.emit("sourceunloaded",{id:O}),!0}if(this.registeredAudioSources.has(O))this.audioManager?.unregisterSource(O),this.registeredAudioSources.delete(O);let $=this.sourcePool.unloadSource(O);if($)this.emitter.emit("sourceunloaded",{id:O});return $}registerSourceAudio(O){if(!this.audioManager)return;if(this.registeredAudioSources.has(O.id))return;let $=O.getAudioBufferSink?.();if($)this.audioManager.registerSource(O,$),this.registeredAudioSources.add(O.id)}processAudioLayers(O,$){if(!this.audioManager)return;let K=this.audioScratch.newSourceIds,j=this.audioScratch.newSourceTimes,Q=this.audioScratch.nextActiveSourceIds,V=this.activeAudioSourceIds;K.length=0,j.length=0,Q.clear();for(let J=0;J<O.length;J++){let U=O[J];if(U.muted)continue;let G=U.source.id;if(!this.audioManager.hasSource(G))continue;if(Q.add(G),!V.has(G))K.push(G),j.push(U.sourceTime??$)}if(V.size>0)V.clear();for(let J of Q)V.add(J);this.audioManager.processAudioLayers(O,$);for(let J=0;J<K.length;J++)this.audioManager.startSourcePlayback(K[J],j[J])}getSource(O){if(this.workerClient)return this.workerSources.get(O);return this.sourcePool.getSource(O)}getAllSources(){if(this.workerClient)return Array.from(this.workerSources.values());return this.sourcePool.getAllSources()}async render(O){if(this.checkDisposed(),this.workerClient){let Z=this.serializeWorkerFrame(O);return this.workerClient.render(Z)}let $=this.ctx;if(!$)return!1;let{visibleLayers:K,framePromises:j,frameImages:Q}=this.renderBuffers;K.length=0,j.length=0,Q.length=0;let V=!1,J=-1/0,U=O.layers;for(let Z=0;Z<U.length;Z++){let L=U[Z];if(L.visible===!1)continue;let z=L.zIndex??0;if(z<J)V=!0;J=z,K.push(L)}if(K.length===0)return $.fillStyle=this.backgroundColor,$.fillRect(0,0,this.width,this.height),!0;if(V)K.sort((Z,L)=>(Z.zIndex??0)-(L.zIndex??0));for(let Z=0;Z<K.length;Z++){let L=K[Z],z=L.sourceTime??O.time;j[Z]=L.source.getFrameAt(z)}let G=await Promise.all(j);for(let Z=0;Z<G.length;Z++)Q[Z]=G[Z]??null;$.fillStyle=this.backgroundColor,$.fillRect(0,0,this.width,this.height);for(let Z=0;Z<K.length;Z++){let L=Q[Z];if(L)this.renderLayer(L,K[Z])}return!0}renderLayer(O,$){let K=this.ctx;if(!K)return;let j=$.transform,Q=$.source.width??this.width,V=$.source.height??this.height,J=$.fitMode===void 0||$.fitMode==="auto"?this.fitMode:$.fitMode,U=Q,G=V,Z=0,L=0;if(Q===0||V===0)U=this.width,G=this.height;else if(J==="none")U=Q,G=V,Z=(this.width-U)/2,L=(this.height-G)/2;else{let P=Q/V,B=this.width/this.height;switch(J){case"fill":U=this.width,G=this.height;break;case"cover":if(P>B)G=this.height,U=this.height*P,Z=(this.width-U)/2;else U=this.width,G=this.width/P,L=(this.height-G)/2;break;default:if(P>B)U=this.width,G=this.width/P,L=(this.height-G)/2;else G=this.height,U=this.height*P,Z=(this.width-U)/2;break}}if(!j){K.drawImage(O,Z,L,U,G);return}let z=(j.x??0)+Z,Y=(j.y??0)+L,A=j.width??U,N=j.height??G,C=j.rotation??0,_=j.scaleX??1,E=j.scaleY??1,W=j.opacity??1,R=j.filter,F=W!==1,b=C!==0||_!==1||E!==1,w=!!R&&R!=="none";if(!(F||b||w)){K.drawImage(O,z,Y,A,N);return}if(!b){if(K.save(),F)K.globalAlpha=W;if(w)K.filter=R;K.drawImage(O,z,Y,A,N),K.restore();return}let q=j.anchorX??0.5,X=j.anchorY??0.5;if(K.save(),F)K.globalAlpha=W;if(w)K.filter=R;if(K.translate(z+A*q,Y+N*X),C!==0)K.rotate(C*Math.PI/180);if(_!==1||E!==1)K.scale(_,E);K.drawImage(O,-A*q,-N*X,A,N),K.restore()}createWorkerSource(O){let $={id:O.id,type:O.type,duration:O.duration,width:O.width,height:O.height,async getFrameAt(){throw Error("getFrameAt is not available when worker rendering is enabled")},getAudioBufferSink(){return null},hasAudio(){return O.hasAudio??!1},dispose(){}};return this.workerSources.set($.id,$),$}async loadWorkerAudio(O,$){if(!this.audioManager)return;if(this.workerAudioSources.has($))this.unloadWorkerAudio($);try{let K=await this.sourcePool.loadAudio(O,{id:$});this.workerAudioSources.set($,K),this.registerSourceAudio(K)}catch{}}unloadWorkerAudio(O){if(!this.audioManager)return;if(this.workerAudioSources.has(O))this.audioManager.unregisterSource(O),this.registeredAudioSources.delete(O),this.sourcePool.unloadSource(O),this.workerAudioSources.delete(O)}serializeWorkerFrame(O){if(!this.workerClient)throw Error("Worker compositor not initialized");let $=O.layers,K=Array($.length);for(let j=0;j<$.length;j++){let Q=$[j],V=Q.source.id;if(!this.workerSources.has(V))throw Error(`Layer source ${V} is not managed by this compositor`);K[j]={sourceId:V,sourceTime:Q.sourceTime,transform:Q.transform,fitMode:Q.fitMode,visible:Q.visible,zIndex:Q.zIndex}}return{time:O.time,layers:K}}clear(){if(this.workerClient){this.workerClient.clear();return}if(!this.ctx)return;this.ctx.fillStyle=this.backgroundColor,this.ctx.fillRect(0,0,this.width,this.height)}preview(O){this.checkDisposed(),this.previewOptions=O,this.state.duration=O.duration,this.lastRenderTime=0,this.emitter.emit("compositionchange",void 0)}async play(){if(this.checkDisposed(),this.state.playing)return;if(!this.previewOptions)throw Error("No preview configured. Call preview() first.");if(this.state.seeking){this.pendingPlayAfterSeek=!0;return}if(this.state.playing=!0,this.lastFrameTime=performance.now(),this.lastRenderTime=this.lastFrameTime,this.emitter.emit("play",void 0),this.audioManager){this.activeAudioSourceIds.clear(),await this.audioManager.play(this.state.currentTime);let O=this.previewOptions.getComposition(this.state.currentTime);this.processAudioLayers(O.audio??[],this.state.currentTime)}this.startRenderLoop()}pause(){if(this.checkDisposed(),!this.state.playing)return;if(this.state.playing=!1,this.pendingPlayAfterSeek=!1,this.stopRenderLoop(),this.audioManager)this.audioManager.pause();this.emitter.emit("pause",void 0)}async seek(O){if(this.checkDisposed(),!this.previewOptions)return;let $=Math.max(0,Math.min(O,this.state.duration));if(this.state.seeking=!0,this.emitter.emit("seeking",{time:$}),this.state.currentTime=$,this.audioManager)await this.audioManager.seek($),this.activeAudioSourceIds.clear();let K=this.previewOptions.getComposition($);if(this.audioManager)this.processAudioLayers(K.audio??[],$);if(await this.render(K),this.state.seeking=!1,this.emitter.emit("seeked",{time:$}),this.emitter.emit("timeupdate",{currentTime:$}),this.pendingPlayAfterSeek)this.pendingPlayAfterSeek=!1,await this.play()}startRenderLoop(){if(this.animationFrameId!==null)return;let O=()=>{if(!this.state.playing||!this.previewOptions)return;this.animationFrameId=requestAnimationFrame(O);let $=performance.now(),K=($-this.lastFrameTime)/1000;if(this.lastFrameTime=$,this.state.currentTime+=K,this.state.currentTime>=this.state.duration)if(this.previewOptions.loop)this.state.currentTime=0;else{this.state.currentTime=this.state.duration,this.pause(),this.emitter.emit("ended",void 0);return}let j=this.previewOptions.fps??0,Q=j>0?1000/j:0;if(!this.renderPending&&(Q===0||$-this.lastRenderTime>=Q)){this.renderPending=!0,this.lastRenderTime=$;let J=this.previewOptions.getComposition(this.state.currentTime);if(this.audioManager)this.processAudioLayers(J.audio??[],this.state.currentTime);this.render(J).catch(()=>{}).finally(()=>{this.renderPending=!1})}if($-this.lastTimeUpdateEmit>=this.timeUpdateThrottleMs)this.lastTimeUpdateEmit=$,this.emitter.emit("timeupdate",{currentTime:this.state.currentTime})};this.animationFrameId=requestAnimationFrame(O)}stopRenderLoop(){if(this.animationFrameId!==null)cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null}async exportFrame(O,$={}){if(this.checkDisposed(),!this.previewOptions)return null;let K=this.previewOptions.getComposition(O);if(this.workerClient){let j=this.serializeWorkerFrame(K);return this.workerClient.exportFrame(j,$)}if(await this.render(K),"toBlob"in this.canvas)return new Promise((j)=>{this.canvas.toBlob((Q)=>j(Q),`image/${$.format??"png"}`,$.quality)});else return this.canvas.convertToBlob({type:`image/${$.format??"png"}`,quality:$.quality})}get currentTime(){return this.state.currentTime}get duration(){return this.state.duration}get playing(){return this.state.playing}get paused(){return!this.state.playing}get seeking(){return this.state.seeking}getWidth(){return this.width}getHeight(){return this.height}resize(O,$,K){if(this.checkDisposed(),this.width=O,this.height=$,K!==void 0)this.fitMode=K;if(this.workerClient){this.workerClient.resize(O,$,this.fitMode);return}this.canvas.width=O,this.canvas.height=$,this.clear()}setFitMode(O){if(this.checkDisposed(),this.fitMode=O,this.workerClient)this.workerClient.resize(this.width,this.height,O)}getFitMode(){return this.fitMode}on(O,$){return this.emitter.on(O,$)}once(O,$){return this.emitter.once(O,$)}off(O,$){this.emitter.off(O,$)}setVolume(O){this.audioManager?.setMasterVolume(O)}setMuted(O){this.audioManager?.setMasterMuted(O)}getAudioContext(){if(!this.audioManager)throw Error("Audio is disabled for this compositor");return this.audioManager.getAudioContext()}checkDisposed(){if(this.disposed)throw Error("Compositor has been disposed")}dispose(){if(this.disposed)return;this.disposed=!0,this.stopRenderLoop(),this.audioManager?.dispose(),this.workerClient?.dispose(),this.workerClient=null,this.sourcePool.dispose(),this.registeredAudioSources.clear(),this.activeAudioSourceIds.clear(),this.audioScratch.nextActiveSourceIds.clear(),this.audioScratch.newSourceIds.length=0,this.audioScratch.newSourceTimes.length=0,this.workerSources.clear(),this.workerAudioSources.clear(),this.emitter.removeAllListeners(),this.ctx=null,this.previewOptions=null}}import{CanvasSink as SO,VideoSampleSink as WO}from"mediabunny";class y{canvas;ctx=null;isInitialized=!1;rotation=0;constructor(O){this.canvas=O.canvas,this.rotation=O.rotation??0,this.initialize()}initialize(){try{if(this.ctx=this.canvas.getContext("2d",{alpha:!1,desynchronized:!0}),!this.ctx)return!1;return this.ctx.imageSmoothingEnabled=!0,this.ctx.imageSmoothingQuality="high",this.isInitialized=!0,!0}catch{return!1}}isReady(){return this.isInitialized&&this.ctx!==null}render(O){if(!this.isReady()||!this.ctx)return!1;try{let{width:$,height:K}=O;if($===0||K===0)return!1;let j=this.canvas.width,Q=this.canvas.height;if(j===0||Q===0)return!1;let V=this.rotation===90||this.rotation===270,J=V?K:$,U=V?$:K,G=Math.min(j/J,Q/U),Z=Math.round(J*G),L=Math.round(U*G),z=Math.round((j-Z)/2),Y=Math.round((Q-L)/2);if(this.ctx.fillStyle="black",this.ctx.fillRect(0,0,j,Q),this.ctx.save(),this.ctx.translate(z+Z/2,Y+L/2),this.rotation!==0)this.ctx.rotate(this.rotation*Math.PI/180);if(V)this.ctx.drawImage(O,0,0,$,K,-L/2,-Z/2,L,Z);else this.ctx.drawImage(O,0,0,$,K,-Z/2,-L/2,Z,L);return this.ctx.restore(),!0}catch{return!1}}clear(){if(!this.isReady()||!this.ctx)return;this.ctx.fillStyle="black",this.ctx.fillRect(0,0,this.canvas.width,this.canvas.height)}setRotation(O){this.rotation=O}getRotation(){return this.rotation}dispose(){this.ctx=null,this.isInitialized=!1}}class r{resources;isInitialized=!1;canvas;textureWidth=0;textureHeight=0;options;boundHandleContextLost=null;boundHandleContextRestored=null;rotation=0;positionsArray=new Float32Array(8);vertexShaderSource=`
2
2
  attribute vec2 a_position;
3
3
  attribute vec2 a_texCoord;
4
4
  varying vec2 v_texCoord;
@@ -16,7 +16,7 @@ class I{events=new Map;maxListeners;captureRejections;emitCache=[];constructor(O
16
16
  vec4 color = texture2D(u_texture, v_texCoord);
17
17
  gl_FragColor = color;
18
18
  }
19
- `;constructor(O){this.canvas=O.canvas,this.options=O,this.rotation=O.rotation??0,this.resources={gl:null,program:null,texture:null,vertexBuffer:null,texCoordBuffer:null,positionLocation:-1,texCoordLocation:-1,textureLocation:null},this.initialize()}initialize(){try{let O={alpha:this.options.alpha??!1,antialias:this.options.antialias??!1,depth:!1,stencil:!1,preserveDrawingBuffer:this.options.preserveDrawingBuffer??!1,powerPreference:this.options.powerPreference??"high-performance"},$=this.canvas.getContext("webgl",O);if(!$&&"getContext"in this.canvas)$=this.canvas.getContext("experimental-webgl",O);if(!$)return!1;this.resources.gl=$;let K=this.createShader($,$.VERTEX_SHADER,this.vertexShaderSource),j=this.createShader($,$.FRAGMENT_SHADER,this.fragmentShaderSource);if(!K||!j)throw Error("Failed to create shaders");let Q=$.createProgram();if(!Q)throw Error("Failed to create program");if($.attachShader(Q,K),$.attachShader(Q,j),$.linkProgram(Q),!$.getProgramParameter(Q,$.LINK_STATUS)){let J=$.getProgramInfoLog(Q);throw Error(`Failed to link program: ${J}`)}this.resources.program=Q,this.resources.positionLocation=$.getAttribLocation(Q,"a_position"),this.resources.texCoordLocation=$.getAttribLocation(Q,"a_texCoord"),this.resources.textureLocation=$.getUniformLocation(Q,"u_texture"),this.setupQuadBuffers($);let V=$.createTexture();if(!V)throw Error("Failed to create texture");if($.bindTexture($.TEXTURE_2D,V),$.texParameteri($.TEXTURE_2D,$.TEXTURE_WRAP_S,$.CLAMP_TO_EDGE),$.texParameteri($.TEXTURE_2D,$.TEXTURE_WRAP_T,$.CLAMP_TO_EDGE),$.texParameteri($.TEXTURE_2D,$.TEXTURE_MIN_FILTER,$.LINEAR),$.texParameteri($.TEXTURE_2D,$.TEXTURE_MAG_FILTER,$.LINEAR),this.resources.texture=V,$.disable($.DEPTH_TEST),$.disable($.CULL_FACE),$.disable($.BLEND),"addEventListener"in this.canvas)this.boundHandleContextLost=this.handleContextLost.bind(this),this.boundHandleContextRestored=this.handleContextRestored.bind(this),this.canvas.addEventListener("webglcontextlost",this.boundHandleContextLost,!1),this.canvas.addEventListener("webglcontextrestored",this.boundHandleContextRestored,!1);return this.isInitialized=!0,!0}catch{return this.cleanup(),!1}}createShader(O,$,K){let j=O.createShader($);if(!j)return null;if(O.shaderSource(j,K),O.compileShader(j),!O.getShaderParameter(j,O.COMPILE_STATUS))return O.deleteShader(j),null;return j}setupQuadBuffers(O){let $=new Float32Array([-1,-1,1,-1,-1,1,1,1]),K=new Float32Array([0,1,1,1,0,0,1,0]),j=O.createBuffer();O.bindBuffer(O.ARRAY_BUFFER,j),O.bufferData(O.ARRAY_BUFFER,$,O.STATIC_DRAW),this.resources.vertexBuffer=j;let Q=O.createBuffer();O.bindBuffer(O.ARRAY_BUFFER,Q),O.bufferData(O.ARRAY_BUFFER,K,O.STATIC_DRAW),this.resources.texCoordBuffer=Q}isReady(){return this.isInitialized&&this.resources.gl!==null}render(O){if(!this.isInitialized||!this.resources.gl)return!1;let $=this.resources.gl;try{let{width:K,height:j}=O;if(K===0||j===0)return!1;let Q=this.canvas.width,V=this.canvas.height;if(Q===0||V===0)return!1;if($.viewport(0,0,Q,V),$.bindTexture($.TEXTURE_2D,this.resources.texture),K!==this.textureWidth||j!==this.textureHeight)$.texImage2D($.TEXTURE_2D,0,$.RGBA,$.RGBA,$.UNSIGNED_BYTE,O),this.textureWidth=K,this.textureHeight=j;else $.texSubImage2D($.TEXTURE_2D,0,0,0,$.RGBA,$.UNSIGNED_BYTE,O);$.clearColor(0,0,0,1),$.clear($.COLOR_BUFFER_BIT);let J=this.rotation===90||this.rotation===270,U=J?this.textureHeight:this.textureWidth,Z=J?this.textureWidth:this.textureHeight,L=Math.min(Q/U,V/Z),A=Math.round(U*L),G=Math.round(Z*L),X=Math.round((Q-A)/2),N=Math.round((V-G)/2),Y=X/Q*2-1,M=(X+A)/Q*2-1,q=1-N/V*2,C=1-(N+G)/V*2,S=(Y+M)/2,R=(q+C)/2,W=(M-Y)/2,b=(q-C)/2,w=this.rotation*Math.PI/180,F=Math.cos(w),_=Math.sin(w),B=J?b:W,P=J?W:b,z=this.positionsArray;return z[0]=-B*F- -P*_+S,z[1]=-B*_+-P*F+R,z[2]=B*F- -P*_+S,z[3]=B*_+-P*F+R,z[4]=-B*F-P*_+S,z[5]=-B*_+P*F+R,z[6]=B*F-P*_+S,z[7]=B*_+P*F+R,$.bindBuffer($.ARRAY_BUFFER,this.resources.vertexBuffer),$.bufferData($.ARRAY_BUFFER,z,$.DYNAMIC_DRAW),$.useProgram(this.resources.program),$.bindBuffer($.ARRAY_BUFFER,this.resources.vertexBuffer),$.enableVertexAttribArray(this.resources.positionLocation),$.vertexAttribPointer(this.resources.positionLocation,2,$.FLOAT,!1,0,0),$.bindBuffer($.ARRAY_BUFFER,this.resources.texCoordBuffer),$.enableVertexAttribArray(this.resources.texCoordLocation),$.vertexAttribPointer(this.resources.texCoordLocation,2,$.FLOAT,!1,0,0),$.uniform1i(this.resources.textureLocation,0),$.drawArrays($.TRIANGLE_STRIP,0,4),!0}catch{return!1}}clear(){if(!this.resources.gl)return;let O=this.resources.gl;O.clearColor(0,0,0,1),O.clear(O.COLOR_BUFFER_BIT)}handleContextLost(O){O.preventDefault(),this.isInitialized=!1}handleContextRestored(){this.initialize()}cleanup(){let O=this.resources.gl;if(!O)return;if(this.resources.texture)O.deleteTexture(this.resources.texture);if(this.resources.vertexBuffer)O.deleteBuffer(this.resources.vertexBuffer);if(this.resources.texCoordBuffer)O.deleteBuffer(this.resources.texCoordBuffer);if(this.resources.program)O.deleteProgram(this.resources.program);this.resources={gl:null,program:null,texture:null,vertexBuffer:null,texCoordBuffer:null,positionLocation:-1,texCoordLocation:-1,textureLocation:null},this.isInitialized=!1}setRotation(O){this.rotation=O}getRotation(){return this.rotation}dispose(){if(this.resources.gl){let O=this.resources.gl.getExtension("WEBGL_lose_context");if(O)try{O.loseContext()}catch{}}if(this.cleanup(),"removeEventListener"in this.canvas){if(this.boundHandleContextLost)this.canvas.removeEventListener("webglcontextlost",this.boundHandleContextLost),this.boundHandleContextLost=null;if(this.boundHandleContextRestored)this.canvas.removeEventListener("webglcontextrestored",this.boundHandleContextRestored),this.boundHandleContextRestored=null}}}class t{canvas;device=null;context=null;pipeline=null;texture=null;sampler=null;bindGroup=null;vertexBuffer=null;isInitialized=!1;textureWidth=0;textureHeight=0;powerPreference;rotation=0;quadArray=new Float32Array(16);vertexShaderSource=`
19
+ `;constructor(O){this.canvas=O.canvas,this.options=O,this.rotation=O.rotation??0,this.resources={gl:null,program:null,texture:null,vertexBuffer:null,texCoordBuffer:null,positionLocation:-1,texCoordLocation:-1,textureLocation:null},this.initialize()}initialize(){try{let O={alpha:this.options.alpha??!1,antialias:this.options.antialias??!1,depth:!1,stencil:!1,preserveDrawingBuffer:this.options.preserveDrawingBuffer??!1,powerPreference:this.options.powerPreference??"high-performance"},$=this.canvas.getContext("webgl",O);if(!$&&"getContext"in this.canvas)$=this.canvas.getContext("experimental-webgl",O);if(!$)return!1;this.resources.gl=$;let K=this.createShader($,$.VERTEX_SHADER,this.vertexShaderSource),j=this.createShader($,$.FRAGMENT_SHADER,this.fragmentShaderSource);if(!K||!j)throw Error("Failed to create shaders");let Q=$.createProgram();if(!Q)throw Error("Failed to create program");if($.attachShader(Q,K),$.attachShader(Q,j),$.linkProgram(Q),!$.getProgramParameter(Q,$.LINK_STATUS)){let J=$.getProgramInfoLog(Q);throw Error(`Failed to link program: ${J}`)}this.resources.program=Q,this.resources.positionLocation=$.getAttribLocation(Q,"a_position"),this.resources.texCoordLocation=$.getAttribLocation(Q,"a_texCoord"),this.resources.textureLocation=$.getUniformLocation(Q,"u_texture"),this.setupQuadBuffers($);let V=$.createTexture();if(!V)throw Error("Failed to create texture");if($.bindTexture($.TEXTURE_2D,V),$.texParameteri($.TEXTURE_2D,$.TEXTURE_WRAP_S,$.CLAMP_TO_EDGE),$.texParameteri($.TEXTURE_2D,$.TEXTURE_WRAP_T,$.CLAMP_TO_EDGE),$.texParameteri($.TEXTURE_2D,$.TEXTURE_MIN_FILTER,$.LINEAR),$.texParameteri($.TEXTURE_2D,$.TEXTURE_MAG_FILTER,$.LINEAR),this.resources.texture=V,$.disable($.DEPTH_TEST),$.disable($.CULL_FACE),$.disable($.BLEND),"addEventListener"in this.canvas)this.boundHandleContextLost=this.handleContextLost.bind(this),this.boundHandleContextRestored=this.handleContextRestored.bind(this),this.canvas.addEventListener("webglcontextlost",this.boundHandleContextLost,!1),this.canvas.addEventListener("webglcontextrestored",this.boundHandleContextRestored,!1);return this.isInitialized=!0,!0}catch{return this.cleanup(),!1}}createShader(O,$,K){let j=O.createShader($);if(!j)return null;if(O.shaderSource(j,K),O.compileShader(j),!O.getShaderParameter(j,O.COMPILE_STATUS))return O.deleteShader(j),null;return j}setupQuadBuffers(O){let $=new Float32Array([-1,-1,1,-1,-1,1,1,1]),K=new Float32Array([0,1,1,1,0,0,1,0]),j=O.createBuffer();O.bindBuffer(O.ARRAY_BUFFER,j),O.bufferData(O.ARRAY_BUFFER,$,O.STATIC_DRAW),this.resources.vertexBuffer=j;let Q=O.createBuffer();O.bindBuffer(O.ARRAY_BUFFER,Q),O.bufferData(O.ARRAY_BUFFER,K,O.STATIC_DRAW),this.resources.texCoordBuffer=Q}isReady(){return this.isInitialized&&this.resources.gl!==null}render(O){if(!this.isInitialized||!this.resources.gl)return!1;let $=this.resources.gl;try{let{width:K,height:j}=O;if(K===0||j===0)return!1;let Q=this.canvas.width,V=this.canvas.height;if(Q===0||V===0)return!1;if($.viewport(0,0,Q,V),$.bindTexture($.TEXTURE_2D,this.resources.texture),K!==this.textureWidth||j!==this.textureHeight)$.texImage2D($.TEXTURE_2D,0,$.RGBA,$.RGBA,$.UNSIGNED_BYTE,O),this.textureWidth=K,this.textureHeight=j;else $.texSubImage2D($.TEXTURE_2D,0,0,0,$.RGBA,$.UNSIGNED_BYTE,O);$.clearColor(0,0,0,1),$.clear($.COLOR_BUFFER_BIT);let J=this.rotation===90||this.rotation===270,U=J?this.textureHeight:this.textureWidth,G=J?this.textureWidth:this.textureHeight,Z=Math.min(Q/U,V/G),L=Math.round(U*Z),z=Math.round(G*Z),Y=Math.round((Q-L)/2),A=Math.round((V-z)/2),N=Y/Q*2-1,C=(Y+L)/Q*2-1,_=1-A/V*2,E=1-(A+z)/V*2,W=(N+C)/2,R=(_+E)/2,F=(C-N)/2,b=(_-E)/2,w=this.rotation*Math.PI/180,S=Math.cos(w),q=Math.sin(w),X=J?b:F,P=J?F:b,B=this.positionsArray;return B[0]=-X*S- -P*q+W,B[1]=-X*q+-P*S+R,B[2]=X*S- -P*q+W,B[3]=X*q+-P*S+R,B[4]=-X*S-P*q+W,B[5]=-X*q+P*S+R,B[6]=X*S-P*q+W,B[7]=X*q+P*S+R,$.bindBuffer($.ARRAY_BUFFER,this.resources.vertexBuffer),$.bufferData($.ARRAY_BUFFER,B,$.DYNAMIC_DRAW),$.useProgram(this.resources.program),$.bindBuffer($.ARRAY_BUFFER,this.resources.vertexBuffer),$.enableVertexAttribArray(this.resources.positionLocation),$.vertexAttribPointer(this.resources.positionLocation,2,$.FLOAT,!1,0,0),$.bindBuffer($.ARRAY_BUFFER,this.resources.texCoordBuffer),$.enableVertexAttribArray(this.resources.texCoordLocation),$.vertexAttribPointer(this.resources.texCoordLocation,2,$.FLOAT,!1,0,0),$.uniform1i(this.resources.textureLocation,0),$.drawArrays($.TRIANGLE_STRIP,0,4),!0}catch{return!1}}clear(){if(!this.resources.gl)return;let O=this.resources.gl;O.clearColor(0,0,0,1),O.clear(O.COLOR_BUFFER_BIT)}handleContextLost(O){O.preventDefault(),this.isInitialized=!1}handleContextRestored(){this.initialize()}cleanup(){let O=this.resources.gl;if(!O)return;if(this.resources.texture)O.deleteTexture(this.resources.texture);if(this.resources.vertexBuffer)O.deleteBuffer(this.resources.vertexBuffer);if(this.resources.texCoordBuffer)O.deleteBuffer(this.resources.texCoordBuffer);if(this.resources.program)O.deleteProgram(this.resources.program);this.resources={gl:null,program:null,texture:null,vertexBuffer:null,texCoordBuffer:null,positionLocation:-1,texCoordLocation:-1,textureLocation:null},this.isInitialized=!1}setRotation(O){this.rotation=O}getRotation(){return this.rotation}dispose(){if(this.resources.gl){let O=this.resources.gl.getExtension("WEBGL_lose_context");if(O)try{O.loseContext()}catch{}}if(this.cleanup(),"removeEventListener"in this.canvas){if(this.boundHandleContextLost)this.canvas.removeEventListener("webglcontextlost",this.boundHandleContextLost),this.boundHandleContextLost=null;if(this.boundHandleContextRestored)this.canvas.removeEventListener("webglcontextrestored",this.boundHandleContextRestored),this.boundHandleContextRestored=null}}}class t{canvas;device=null;context=null;pipeline=null;texture=null;sampler=null;bindGroup=null;vertexBuffer=null;isInitialized=!1;textureWidth=0;textureHeight=0;powerPreference;rotation=0;quadArray=new Float32Array(16);vertexShaderSource=`
20
20
  struct VSOut {
21
21
  @builtin(position) pos : vec4f,
22
22
  @location(0) uv : vec2f,
@@ -37,4 +37,4 @@ class I{events=new Map;maxListeners;captureRejections;emitCache=[];constructor(O
37
37
  fn fs_main(@location(0) uv: vec2f) -> @location(0) vec4f {
38
38
  return textureSample(texture_view, texture_sampler, uv);
39
39
  }
40
- `;constructor(O){this.canvas=O.canvas,this.powerPreference=O.powerPreference||"high-performance",this.rotation=O.rotation??0,this.initialize().catch(($)=>{console.error("WebGPU initialization failed:",$)})}async initialize(){try{let O=navigator;if(!O.gpu)return console.log("WebGPU not available in navigator"),!1;let $=await O.gpu.requestAdapter({powerPreference:this.powerPreference});if(!$)return console.log("WebGPU adapter not available"),!1;if(this.device=await $.requestDevice(),!this.device)return console.log("WebGPU device not available"),!1;if("getContext"in this.canvas)this.context=this.canvas.getContext("webgpu");if(!this.context)return console.log("WebGPU context not available on canvas"),!1;let K=O.gpu.getPreferredCanvasFormat();return this.context.configure({device:this.device,format:K,usage:GPUTextureUsage.RENDER_ATTACHMENT,alphaMode:"opaque"}),await this.createRenderPipeline(),this.createVertexBuffer(),this.isInitialized=!0,console.log("WebGPU renderer initialized successfully"),!0}catch(O){return console.error("WebGPU initialization error:",O),!1}}async createRenderPipeline(){if(!this.device)return;let O=navigator;if(!O.gpu)return;let $=this.device.createShaderModule({code:this.vertexShaderSource}),K=this.device.createShaderModule({code:this.fragmentShaderSource});this.pipeline=this.device.createRenderPipeline({layout:"auto",vertex:{module:$,entryPoint:"vs_main",buffers:[{arrayStride:16,attributes:[{shaderLocation:0,offset:0,format:"float32x2"},{shaderLocation:1,offset:8,format:"float32x2"}]}]},fragment:{module:K,entryPoint:"fs_main",targets:[{format:O.gpu.getPreferredCanvasFormat()}]},primitive:{topology:"triangle-strip"}})}createVertexBuffer(){if(!this.device)return;this.vertexBuffer=this.device.createBuffer({size:64,usage:GPUBufferUsage.VERTEX|GPUBufferUsage.COPY_DST})}createTexture(O,$){if(!this.device)return;if(this.texture)this.texture.destroy();if(this.texture=this.device.createTexture({size:{width:O,height:$},format:"rgba8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT}),!this.sampler)this.sampler=this.device.createSampler({magFilter:"linear",minFilter:"linear",addressModeU:"clamp-to-edge",addressModeV:"clamp-to-edge"});this.createBindGroup()}createBindGroup(){if(!this.device||!this.texture||!this.sampler||!this.pipeline)return;this.bindGroup=this.device.createBindGroup({layout:this.pipeline.getBindGroupLayout(0),entries:[{binding:0,resource:this.sampler},{binding:1,resource:this.texture.createView()}]})}isReady(){return this.isInitialized&&this.device!==null&&this.context!==null&&this.pipeline!==null}render(O){if(!this.isReady()||!this.device||!this.context||!this.pipeline)return!1;try{let{width:$,height:K}=O;if($===0||K===0)return console.warn(`WebGPU: Source canvas has zero dimensions (${$}x${K})`),!1;let j=this.canvas.width,Q=this.canvas.height;if(j===0||Q===0)return console.warn(`WebGPU: Output canvas has zero dimensions (${j}x${Q})`),!1;if($!==this.textureWidth||K!==this.textureHeight)this.createTexture($,K),this.textureWidth=$,this.textureHeight=K;if(!this.texture)return!1;try{this.device.queue.copyExternalImageToTexture({source:O},{texture:this.texture},{width:$,height:K})}catch{let n=O.getContext("2d");if(!n)return!1;if(!("getImageData"in n))return!1;let BO=n.getImageData(0,0,$,K),XO=new Uint8Array(BO.data.buffer);this.device.queue.writeTexture({texture:this.texture,origin:{x:0,y:0,z:0}},XO,{bytesPerRow:$*4,rowsPerImage:K},{width:$,height:K,depthOrArrayLayers:1})}let V=this.device.createCommandEncoder(),J=this.context.getCurrentTexture().createView(),U=V.beginRenderPass({colorAttachments:[{view:J,clearValue:{r:0,g:0,b:0,a:1},loadOp:"clear",storeOp:"store"}]});if(U.setPipeline(this.pipeline),this.bindGroup)U.setBindGroup(0,this.bindGroup);let Z=this.rotation===90||this.rotation===270,L=Z?this.textureHeight:this.textureWidth,A=Z?this.textureWidth:this.textureHeight,G=Math.min(j/L,Q/A),X=Math.round(L*G),N=Math.round(A*G),Y=Math.round((j-X)/2),M=Math.round((Q-N)/2),q=Y/j*2-1,C=(Y+X)/j*2-1,S=1-M/Q*2,R=1-(M+N)/Q*2,W=(q+C)/2,b=(S+R)/2,w=(C-q)/2,F=(S-R)/2,_=this.rotation*Math.PI/180,B=Math.cos(_),P=Math.sin(_),z=Z?F:w,T=Z?w:F,D=this.quadArray;if(D[0]=-z*B- -T*P+W,D[1]=-z*P+-T*B+b,D[2]=0,D[3]=1,D[4]=z*B- -T*P+W,D[5]=z*P+-T*B+b,D[6]=1,D[7]=1,D[8]=-z*B-T*P+W,D[9]=-z*P+T*B+b,D[10]=0,D[11]=0,D[12]=z*B-T*P+W,D[13]=z*P+T*B+b,D[14]=1,D[15]=0,this.vertexBuffer)this.device.queue.writeBuffer(this.vertexBuffer,0,D),U.setVertexBuffer(0,this.vertexBuffer);return U.draw(4,1,0,0),U.end(),this.device.queue.submit([V.finish()]),!0}catch{return!1}}clear(){if(!this.isReady()||!this.device||!this.context)return;try{let O=this.device.createCommandEncoder(),$=this.context.getCurrentTexture().createView();O.beginRenderPass({colorAttachments:[{view:$,clearValue:{r:0,g:0,b:0,a:1},loadOp:"clear",storeOp:"store"}]}).end(),this.device.queue.submit([O.finish()])}catch{}}setRotation(O){this.rotation=O}getRotation(){return this.rotation}dispose(){try{if(this.texture)this.texture.destroy(),this.texture=null;if(this.vertexBuffer)this.vertexBuffer.destroy(),this.vertexBuffer=null;this.device=null,this.context=null,this.pipeline=null,this.sampler=null,this.bindGroup=null,this.isInitialized=!1}catch{}}}class H{canvas;powerPreference;constructor(O){this.canvas=O.canvas,this.powerPreference=O.powerPreference||"high-performance"}async createRenderer(O){try{switch(O){case"webgpu":return await this.createWebGPURenderer();case"webgl":return this.createWebGLRenderer();case"canvas2d":return this.createCanvas2DRenderer();default:return null}}catch{return null}}async createRendererWithFallback(O){let $=[O];if(O!=="webgl")$.push("webgl");if(O!=="canvas2d")$.push("canvas2d");for(let j of $){let Q=await this.createRenderer(j);if(Q?.isReady())return{renderer:Q,actualType:j};if(Q)Q.dispose()}return{renderer:this.createCanvas2DRenderer(),actualType:"canvas2d"}}async createWebGPURenderer(){if(!navigator.gpu)return null;if(!("getContext"in this.canvas))return console.log("WebGPU requires HTMLCanvasElement, not OffscreenCanvas"),null;let $=new t({canvas:this.canvas,powerPreference:this.powerPreference}),K=1000,j=performance.now();if(await(async()=>{while(!$.isReady()){if(performance.now()-j>K)return console.log("WebGPU renderer initialization timed out"),!1;if("requestIdleCallback"in window)await new Promise((J)=>requestIdleCallback(()=>J(void 0)));else await new Promise((J)=>requestAnimationFrame(()=>J(void 0)))}return!0})())return console.log("WebGPU renderer initialized successfully"),$;return $.isReady()?$:null}createWebGLRenderer(){try{let O=new r({canvas:this.canvas,powerPreference:this.powerPreference,preserveDrawingBuffer:!1,antialias:!1,alpha:!1});return O.isReady()?O:null}catch{return null}}createCanvas2DRenderer(){return new y({canvas:this.canvas})}static getSupportedRenderers(){let O=[];if(navigator.gpu)O.push("webgpu");try{let K=document.createElement("canvas");if(K.getContext("webgl")||K.getContext("experimental-webgl"))O.push("webgl")}catch{}return O.push("canvas2d"),O}static getRendererDisplayName(O){switch(O){case"canvas2d":return"Canvas 2D";case"webgl":return"WebGL";case"webgpu":return"WebGPU";default:return"Unknown"}}static isRendererSupported(O){if(O==="canvas2d")return!0;return H.getSupportedRenderers().includes(O)}}var e=new WeakMap;function AO(O,$){e.set(O,$)}function WO(O){let $=e.get(O);if($)e.delete(O);return $}class v{canvas=null;canvasSink=null;sampleSink=null;options;frameIterator=null;currentFrame=null;nextFrame=null;disposed=!1;renderingId=0;renderer=null;rendererType="canvas2d";onRendererChange;onRendererFallback;onRotationChange;initPromise=null;resizeObserver=null;lastObservedWidth=0;lastObservedHeight=0;videoAspectRatio=null;debug=!1;pluginManager=null;overlayCanvas=null;overlayCtx=null;lastOverlayTime=0;rotation=0;sourceWidth=0;sourceHeight=0;updateFrameResult={frameUpdated:!1,isStarving:!1};constructor(O={}){if(this.options={poolSize:O.poolSize??2,rendererType:O.rendererType??"webgpu",...O},this.rendererType=this.options.rendererType??"webgpu",this.debug=O.debug??!1,this.initPromise=null,O.canvas){if(this.canvas=O.canvas,this.options.width!==void 0)O.canvas.width=this.options.width;if(this.options.height!==void 0)O.canvas.height=this.options.height;this.initPromise=this.initializeRenderer(O.canvas,this.rendererType).catch(($)=>{if(this.debug)console.error("Failed to initialize renderer:",$)}),this.setupResizeObserver(O.canvas)}}setupResizeObserver(O){if(!("getBoundingClientRect"in O)||typeof ResizeObserver>"u")return;if(this.options.width!==void 0||this.options.height!==void 0)return;this.cleanupResizeObserver();let $=O;this.resizeObserver=new ResizeObserver((K)=>{if(this.disposed||!this.resizeObserver)return;for(let j of K){let{width:Q,height:V}=this.getCanvasDimensionsFromEntry(j,$);if(Q!==this.lastObservedWidth||V!==this.lastObservedHeight){if(this.lastObservedWidth=Q,this.lastObservedHeight=V,$.width!==Q||$.height!==V){if($.width=Q,$.height=V,this.updateCanvasAspectRatio(),this.currentFrame&&this.renderer&&this.renderer.isReady())this.renderFrame(this.currentFrame)}}}});try{this.resizeObserver.observe($,{box:"device-pixel-content-box"})}catch{try{this.resizeObserver.observe($,{box:"content-box"})}catch{this.resizeObserver.observe($)}}requestAnimationFrame(()=>{if(this.disposed||!this.resizeObserver)return;let{width:K,height:j}=this.getCanvasDimensionsFromCanvas($);if(this.lastObservedWidth=K,this.lastObservedHeight=j,$.width!==K||$.height!==j){if($.width=K,$.height=j,this.updateCanvasAspectRatio(),this.currentFrame&&this.renderer&&this.renderer.isReady())this.renderFrame(this.currentFrame)}})}getCanvasDimensionsFromEntry(O,$){let K=0,j=0,Q=window.devicePixelRatio||1;if(O.devicePixelContentBoxSize?.length)K=O.devicePixelContentBoxSize[0].inlineSize,j=O.devicePixelContentBoxSize[0].blockSize;else if(O.contentBoxSize?.length)K=Math.round(O.contentBoxSize[0].inlineSize*Q),j=Math.round(O.contentBoxSize[0].blockSize*Q);else if(O.contentRect)K=Math.round(O.contentRect.width*Q),j=Math.round(O.contentRect.height*Q);if(K===0||j===0)return this.getCanvasDimensionsFromCanvas($);return{width:Math.max(1,K),height:Math.max(1,j)}}getCanvasDimensionsFromCanvas(O){let $=0,K=0,j=window.devicePixelRatio||1,Q=O.getBoundingClientRect();if($=Math.round(Q.width*j),K=Math.round(Q.height*j),$===0||K===0)$=Math.round(O.clientWidth*j)||$,K=Math.round(O.clientHeight*j)||K;if($===0||K===0)console.warn("Canvas has zero dimensions after all fallbacks, using 1x1");return{width:Math.max(1,$),height:Math.max(1,K)}}cleanupResizeObserver(){if(this.resizeObserver)this.resizeObserver.disconnect(),this.resizeObserver=null,this.lastObservedWidth=0,this.lastObservedHeight=0}retryUntilCanvasReady(O,$,K=60){let j=0,Q=()=>{if(j++,O.canvas.width>0&&O.canvas.height>0)$();else if(j<K)requestAnimationFrame(Q);else{if(this.debug)console.warn("Canvas dimensions timeout, forcing action");$()}};requestAnimationFrame(Q)}updateCanvasAspectRatio(){if(!this.canvas||!this.videoAspectRatio||!("style"in this.canvas))return;this.canvas.style.aspectRatio=this.videoAspectRatio}updateCanvasBackingBuffer(O){let{width:$,height:K}=this.getCanvasDimensionsFromCanvas(O);if(O.width!==$||O.height!==K)return O.width=$,O.height=K,!0;return!1}async initializeRenderer(O,$){if(this.debug)console.log(`Initializing renderer: ${$}`);let j=await new H({canvas:O}).createRendererWithFallback($);if(this.debug)console.log(`Renderer factory result: ${j.actualType}`);if(!j.renderer.isReady()){if(this.debug)console.warn(`VideoRenderer: Renderer (${j.actualType}) not ready`);throw j.renderer.dispose(),Error(`Failed to initialize renderer: ${j.actualType}`)}if(this.renderer=j.renderer,this.rendererType=j.actualType,this.debug)console.log(`Initialized renderer: ${this.rendererType}`);if(j.actualType!==$){if(this.onRendererFallback)this.onRendererFallback($,j.actualType)}if(this.onRendererChange){if(this.debug)console.log(`Emitting renderer change: ${this.rendererType}`);this.onRendererChange(this.rendererType)}if(this.currentFrame&&this.renderer&&this.renderer.isReady()){if(this.debug)console.log(`Rendering initial frame with ${this.rendererType}`);if(this.currentFrame.canvas.width===0||this.currentFrame.canvas.height===0){if(this.debug)console.log("Initial frame has zero dimensions, scheduling render when ready...");this.retryUntilCanvasReady(this.currentFrame,()=>{if(this.currentFrame&&this.debug)console.log(`Canvas ready (${this.currentFrame.canvas.width}x${this.currentFrame.canvas.height}), rendering initial frame`);if(this.currentFrame)this.renderFrame(this.currentFrame)})}else this.renderFrame(this.currentFrame)}}async setCanvas(O){if(this.cleanupOverlayCanvas(),this.canvas=O,this.renderer)this.renderer.dispose(),this.renderer=null;if(this.options.width!==void 0)O.width=this.options.width;if(this.options.height!==void 0)O.height=this.options.height;this.setupResizeObserver(O);try{await this.initializeRenderer(O,this.rendererType)}catch($){if(this.debug)console.error("Failed to initialize renderer:",$);if(!this.renderer){if(this.renderer=new y({canvas:O}),this.rendererType="canvas2d",this.onRendererChange)this.onRendererChange("canvas2d")}}}async setVideoTrack(O){if(await this.disposeVideoResources(),O.codec===null)throw Error("Unsupported video codec");if(!await O.canDecode())throw Error(`Cannot decode video track with codec: ${O.codec}`);let K=WO(O);if(this.sourceWidth=O.displayWidth,this.sourceHeight=O.displayHeight,!this.videoAspectRatio&&O.displayWidth&&O.displayHeight){let j=(U,Z)=>Z===0?U:j(Z,U%Z),Q=j(O.displayWidth,O.displayHeight),V=O.displayWidth/Q,J=O.displayHeight/Q;this.videoAspectRatio=`${V}/${J}`,this.updateCanvasAspectRatio()}if(this.notifyRotationChange(),this.initPromise)try{await this.initPromise}catch(j){if(this.debug)console.error("Renderer initialization failed:",j)}if(!this.renderer){if(this.debug)console.warn("Renderer not ready, creating Canvas2D fallback");if(this.canvas){if(this.renderer=new y({canvas:this.canvas}),this.rendererType="canvas2d",this.onRendererChange)this.onRendererChange("canvas2d")}}if(this.canvas){if(this.options.width!==void 0||this.options.height!==void 0){let j=this.options.width??O.displayWidth,Q=this.options.height??O.displayHeight;if(this.canvas.width!==j||this.canvas.height!==Q)this.canvas.width=j,this.canvas.height=Q,this.updateCanvasAspectRatio()}else if(!this.resizeObserver){if(this.canvas.width===0||this.canvas.height===0)this.canvas.width=O.displayWidth,this.canvas.height=O.displayHeight,this.updateCanvasAspectRatio()}}if(K?.canvasSink)this.canvasSink=K.canvasSink;else this.canvasSink=new FO(O,{rotation:this.options.rotation,poolSize:this.options.poolSize});if(this.sampleSink=new SO(O),this.disposed=!1,K?.firstFrame){if(this.currentFrame=K.firstFrame,this.currentFrame.canvas.width>0&&this.currentFrame.canvas.height>0)this.renderFrame(this.currentFrame);else this.retryUntilCanvasReady(this.currentFrame,()=>{if(this.currentFrame)this.renderFrame(this.currentFrame)},30);this.frameIterator=this.canvasSink.canvases(0),this.frameIterator.next().then(()=>{this.fetchNextFrame()})}else try{await this.seek(0)}catch(j){if(this.debug)console.error("Initial seek failed:",j)}requestAnimationFrame(()=>{if(this.resizeObserver&&this.canvas&&"getBoundingClientRect"in this.canvas)this.updateCanvasBackingBuffer(this.canvas);if(this.currentFrame&&this.renderer&&this.renderer.isReady())this.renderFrame(this.currentFrame)})}async seek(O){if(!this.canvasSink)return;this.renderingId++;let $=this.renderingId;if(this.frameIterator){try{await this.frameIterator.return()}catch{}this.frameIterator=null}let K=this.canvasSink.canvases(O);this.frameIterator=K;try{let j=await K.next(),Q=await K.next();if($!==this.renderingId)return;let V=j.value??null,J=Q.value??null;if(V)if(this.currentFrame=V,V.canvas.width>0&&V.canvas.height>0)this.renderFrame(V);else this.retryUntilCanvasReady(V,()=>this.renderFrame(V),30);if(this.nextFrame=J,!this.nextFrame)this.fetchNextFrame()}catch{}}updateFrame(O){let $=this.updateFrameResult;if(this.disposed)return $.frameUpdated=!1,$.isStarving=!1,$;if(!this.nextFrame){if(this.frameIterator)this.fetchNextFrame();return $.frameUpdated=!1,$.isStarving=!0,$}if(this.nextFrame.timestamp<=O){if(this.currentFrame=this.nextFrame,this.nextFrame=null,this.renderFrame(this.currentFrame),this.frameIterator)this.fetchNextFrame();return $.frameUpdated=!0,$.isStarving=!1,$}return $.frameUpdated=!1,$.isStarving=!1,$}async fetchNextFrame(){let O=this.frameIterator;if(!O||this.disposed)return;let $=this.renderingId;try{let j=(await O.next()).value??null;if(!j||$!==this.renderingId||this.disposed)return;this.nextFrame=j}catch{}}renderFrame(O){if(this.currentFrame=O,!this.renderer||!this.canvas){if(this.initPromise)this.initPromise.then(()=>{if(this.currentFrame===O&&this.renderer&&this.renderer.isReady()){if(this.debug)console.log("Rendering frame after renderer initialization");this.renderFrameWithPlugins(O)}});return}if(!this.renderer.isReady()){if(this.debug)console.warn(`VideoRenderer: Renderer (${this.rendererType}) not ready, skipping frame`);return}this.renderFrameWithPlugins(O)}renderFrameWithPlugins(O){if(!this.renderer||!this.canvas)return;let $=O.timestamp;if(this.pluginManager){if(this.pluginManager.executeBeforeRender(O,$)?.skip)return}let K=O;if(this.pluginManager)K=this.pluginManager.executeTransformFrame(O);if(!this.renderer.render(K.canvas)){if(this.debug)console.warn(`Failed to render frame with ${this.rendererType} (canvas: ${K.canvas.width}x${K.canvas.height})`);if(K.canvas.width===0||K.canvas.height===0)this.retryUntilCanvasReady(K,()=>{if(this.currentFrame===O&&this.renderer&&this.renderer.isReady()){if(!this.renderer.render(K.canvas)&&this.debug)console.warn("Retry render also failed")}},1);return}if(this.executeOverlays($),this.pluginManager)this.pluginManager.executeAfterRender(this.canvas)}executeOverlays(O){if(!this.pluginManager||!this.canvas)return;this.lastOverlayTime=O;let $={width:this.canvas.width,height:this.canvas.height};if(this.rendererType==="canvas2d"){let K=this.canvas.getContext("2d");if(!K)return;this.pluginManager.executeOverlays(K,O,$)}else{if(this.ensureOverlayCanvas(),!this.overlayCanvas||!this.overlayCtx)return;this.overlayCtx.clearRect(0,0,this.overlayCanvas.width,this.overlayCanvas.height),this.pluginManager.executeOverlays(this.overlayCtx,O,$)}}refreshOverlays(){if(!this.canvas)return;if(this.rendererType==="canvas2d"){if(this.currentFrame&&this.renderer?.isReady())this.renderer.render(this.currentFrame.canvas),this.executeOverlays(this.lastOverlayTime)}else if(this.overlayCanvas&&this.overlayCtx){if(this.overlayCtx.clearRect(0,0,this.overlayCanvas.width,this.overlayCanvas.height),this.pluginManager){let O={width:this.canvas.width,height:this.canvas.height};this.pluginManager.executeOverlays(this.overlayCtx,this.lastOverlayTime,O)}}}ensureOverlayCanvas(){if(!this.canvas||!(this.canvas instanceof HTMLCanvasElement))return;if(!this.overlayCanvas){this.overlayCanvas=document.createElement("canvas"),this.overlayCanvas.style.position="absolute",this.overlayCanvas.style.top="0",this.overlayCanvas.style.left="0",this.overlayCanvas.style.width="100%",this.overlayCanvas.style.height="100%",this.overlayCanvas.style.pointerEvents="none",this.overlayCanvas.style.zIndex="1",this.overlayCtx=this.overlayCanvas.getContext("2d");let O=this.canvas.parentElement;if(O){if(getComputedStyle(O).position==="static")O.style.position="relative";O.insertBefore(this.overlayCanvas,this.canvas.nextSibling)}}if(this.overlayCanvas.width!==this.canvas.width||this.overlayCanvas.height!==this.canvas.height)this.overlayCanvas.width=this.canvas.width,this.overlayCanvas.height=this.canvas.height}cleanupOverlayCanvas(){if(this.overlayCanvas)this.overlayCanvas.remove(),this.overlayCanvas=null,this.overlayCtx=null}async getFrameAt(O){if(!this.canvasSink)return null;return this.canvasSink.getCanvas(O)}async getSampleAt(O){if(!this.sampleSink)return null;return this.sampleSink.getSample(O)}async extractFrames(O,$,K=1){if(!this.canvasSink)return[];let j=[],Q=[];for(let V=O;V<=$;V+=K)Q.push(V);for await(let V of this.canvasSink.canvasesAtTimestamps(Q))if(V)j.push(V);return j}async screenshot(O,$={}){if(!this.canvas)return null;if(O!==void 0&&this.canvasSink){let K=await this.canvasSink.getCanvas(O);if(K)this.renderFrame(K)}if("toBlob"in this.canvas)return new Promise((K)=>{this.canvas.toBlob((j)=>K(j),`image/${$.format??"png"}`,$.quality)});else return this.canvas.convertToBlob({type:`image/${$.format??"png"}`,quality:$.quality})}getCurrentFrame(){return this.currentFrame}getNextFrame(){return this.nextFrame}getRendererType(){return this.rendererType}getCanvas(){return this.canvas}updateCanvasDimensions(){if(!this.canvas||!("getBoundingClientRect"in this.canvas))return;let O=this.canvas;if(this.updateCanvasBackingBuffer(O)&&this.currentFrame&&this.renderer&&this.renderer.isReady())this.renderFrame(this.currentFrame)}async switchRenderer(O){if(!this.canvas)throw Error("Cannot switch renderer: No canvas set");let $=this.rendererType;if(O===$)return;if(this.debug)console.warn(`Switching renderer from ${$} to ${O}. This will recreate the canvas element.`);if(this.canvas instanceof HTMLCanvasElement){let K=this.canvas,j=K.parentElement;if(!j)throw Error("Cannot switch renderer: Canvas has no parent element");let Q=document.createElement("canvas");if(Q.width=K.width,Q.height=K.height,Q.className=K.className,Q.id=K.id,Q.style.cssText=K.style.cssText,Array.from(K.attributes).forEach((V)=>{if(V.name!=="id"&&V.name!=="class"&&V.name!=="style")Q.setAttribute(V.name,V.value)}),this.renderer)this.renderer.dispose(),this.renderer=null;j.replaceChild(Q,K),this.canvas=Q;try{await this.initializeRenderer(Q,O)}catch(V){if(this.debug)console.error(`Failed to switch to ${O}:`,V);if(!this.renderer){if(this.renderer=new y({canvas:Q}),this.rendererType="canvas2d",this.onRendererChange)this.onRendererChange("canvas2d")}}}else{if(this.debug)console.warn("Runtime switching for OffscreenCanvas may not work if context is already set");if(this.renderer)this.renderer.dispose(),this.renderer=null;try{await this.initializeRenderer(this.canvas,O)}catch(K){if(this.debug)console.error(`Failed to switch to ${O}:`,K);if(!this.renderer){if(this.renderer=new y({canvas:this.canvas}),this.rendererType="canvas2d",this.onRendererChange)this.onRendererChange("canvas2d")}}}if(this.currentFrame&&this.renderer&&this.renderer.isReady()){if(this.debug)console.log(`Re-rendering after switch to ${this.rendererType}`);queueMicrotask(()=>{if(this.currentFrame&&this.renderer&&this.renderer.isReady())this.renderFrame(this.currentFrame)})}}setRendererChangeCallback(O){if(this.onRendererChange=O,this.renderer&&this.rendererType){if(this.debug)console.log(`Renderer already initialized as ${this.rendererType}, emitting change event`);O(this.rendererType)}}setRendererFallbackCallback(O){this.onRendererFallback=O}setRotationChangeCallback(O){this.onRotationChange=O}setRotation(O){if(this.rotation===O)return;if(this.rotation=O,this.renderer)this.renderer.setRotation(O);if(this.notifyRotationChange(),this.currentFrame&&this.renderer&&this.renderer.isReady())this.renderFrame(this.currentFrame)}getRotation(){return this.rotation}getDisplaySize(){let O=this.rotation===90||this.rotation===270;return{width:O?this.sourceHeight:this.sourceWidth,height:O?this.sourceWidth:this.sourceHeight}}notifyRotationChange(){if(this.onRotationChange&&this.sourceWidth>0&&this.sourceHeight>0)this.onRotationChange(this.rotation,this.getDisplaySize())}setPluginManager(O){this.pluginManager=O}static getSupportedRenderers(){return H.getSupportedRenderers()}async clearIterators(){if(this.renderingId++,this.frameIterator){try{await this.frameIterator.return()}catch{}this.frameIterator=null}this.currentFrame=null,this.nextFrame=null}async disposeVideoResources(){if(this.disposed=!0,this.renderingId++,this.frameIterator){try{await this.frameIterator.return()}catch{}this.frameIterator=null}this.currentFrame=null,this.nextFrame=null,this.canvasSink=null,this.sampleSink=null,this.videoAspectRatio=null}dispose(){if(this.disposed=!0,this.renderingId++,this.frameIterator)this.frameIterator.return(),this.frameIterator=null;if(this.renderer)this.renderer.dispose(),this.renderer=null;this.cleanupResizeObserver(),this.cleanupOverlayCanvas(),this.currentFrame=null,this.nextFrame=null,this.canvasSink=null,this.sampleSink=null,this.onRendererChange=void 0,this.onRendererFallback=void 0}}var f=2,h="[MediaFox]";function HO(O){f=O}function bO(O,...$){if(f<=0)console.debug(`${h} ${O}`,...$)}function wO(O,...$){if(f<=1)console.info(`${h} ${O}`,...$)}function TO(O,...$){if(f<=2)console.warn(`${h} ${O}`,...$)}function yO(O,...$){if(f<=3)console.error(`${h} ${O}`,...$)}var k={setLevel:HO,debug:bO,info:wO,warn:TO,error:yO};class OO{deps;constructor(O){this.deps=O}async load(O,$={}){try{let K=await this.deps.pluginManager.executeBeforeLoad(O);if(K?.cancel)return;if(K?.data!==void 0)O=K.data;await this.deps.playbackController.reset(),this.deps.sourceManager.disposeCurrent();let j=this.deps.state.getState();if(!$.replacePlaylist)this.deps.state.setState({...j,state:"loading",currentTime:$.startTime??0,playing:!1,paused:!0,ended:!1,seeking:!1,error:null,mediaInfo:null,videoTracks:[],audioTracks:[],subtitleTracks:[],selectedVideoTrack:null,selectedAudioTrack:null,selectedSubtitleTrack:null,buffered:[],canPlay:!1,canPlayThrough:!1});else this.deps.state.reset(),this.deps.state.updateLoadingState();this.deps.emit("loadstart",void 0);let Q=$.playlistItemId?this.deps.sourceManager.promoteQueuedSource($.playlistItemId):null;if(!Q)Q=await this.deps.sourceManager.createSource(O);let V=Q.input;if(!V)throw Error("Failed to create input from source");await this.deps.trackManager.initialize(V);let[J,U,Z,L]=await Promise.all([V.computeDuration(),V.getFormat(),V.getMimeType(),V.getMetadataTags()]),A={duration:J,format:U.name,mimeType:Z,metadata:L,hasVideo:this.deps.trackManager.hasVideo(),hasAudio:this.deps.trackManager.hasAudio(),hasSubtitles:this.deps.trackManager.hasSubtitles()};this.deps.state.updateDuration(J),this.deps.state.updateMediaInfo(A),this.deps.state.updateTracks(this.deps.trackManager.getVideoTracks(),this.deps.trackManager.getAudioTracks(),this.deps.trackManager.getSubtitleTracks()),this.deps.playbackController.setDuration(J);let G=Q.prefetchedData,X=G?.videoTrack??this.deps.trackManager.getPrimaryVideoTrack(),N=G?.audioTrack??this.deps.trackManager.getPrimaryAudioTrack();if(X&&G?.canvasSink&&G?.firstFrame)AO(X,{canvasSink:G.canvasSink,firstFrame:G.firstFrame});let Y="",M=!1,q=!1;if(X||N){let C=await this.deps.trackSwitcher.setupInitialTracks(X,N);Y+=C.warningMessage,M=C.videoSupported,q=C.audioSupported}if(!M&&!q){if(!Y)Y="No audio or video track found.";throw Error(Y)}if(Y&&(M||q))this.deps.emit("warning",{type:"codec-warning",message:Y.trim(),error:void 0});if(this.deps.state.updateReadyState(!0,!0),this.deps.emit("loadedmetadata",A),this.deps.emit("loadeddata",void 0),this.deps.emit("canplay",void 0),this.deps.emit("canplaythrough",void 0),this.updateCurrentPlaylistItemDuration(J),await this.deps.pluginManager.executeAfterLoad(A),$.autoplay)await this.play();if($.startTime!==void 0)await this.seek($.startTime)}catch(K){throw this.handleError(K),K}}async play(){try{if(this.deps.state.getState().state==="idle")throw Error("No media loaded");if((await this.deps.pluginManager.executeBeforePlay())?.cancel)return;await this.deps.playbackController.play(),this.deps.state.updatePlaybackState(!0),this.deps.emit("play",void 0),this.deps.emit("playing",void 0),this.deps.pluginManager.executeAfterPlay()}catch(O){throw this.handleError(O),O}}async pause(){if((await this.deps.pluginManager.executeBeforePause())?.cancel)return;this.deps.playbackController.pause(),this.deps.state.updatePlaybackState(!1),this.deps.emit("pause",void 0),this.deps.pluginManager.executeAfterPause()}async seek(O){try{if(this.deps.state.getState().state==="idle")throw Error("No media loaded");let K=await this.deps.pluginManager.executeBeforeSeek(O);if(K?.cancel)return;if(K?.data!==void 0)O=K.data;this.deps.state.updateSeekingState(!0),this.deps.emit("seeking",{currentTime:O}),await this.deps.playbackController.seek(O),this.deps.state.updateSeekingState(!1),this.deps.state.updateTime(this.deps.playbackController.getCurrentTime()),this.deps.emit("seeked",{currentTime:this.deps.playbackController.getCurrentTime()}),this.deps.pluginManager.executeAfterSeek(this.deps.playbackController.getCurrentTime())}catch($){throw this.deps.state.updateSeekingState(!1),this.handleError($),$}}async stop(){try{if((await this.deps.pluginManager.executeBeforeStop())?.cancel)return;await this.pause(),await this.seek(0),this.deps.pluginManager.executeAfterStop()}catch(O){throw this.handleError(O),O}}handleError(O){if(this.deps.pluginManager.executeOnError(O))return;this.deps.state.updateError(O),this.deps.emit("error",O),k.error("Player error:",O)}updateCurrentPlaylistItemDuration(O){let $=this.deps.state.getState(),K=$.currentPlaylistIndex;if(K!==null&&$.playlist.length>0){let j=[...$.playlist],Q=j[K];if(Q)j[K]={...Q,duration:O},this.deps.state.updatePlaylist(j,K)}}}class $O{store;constructor(O){this.store=O}getState(){return this.store.getState()}subscribe(O){return this.store.subscribe(O)}setState(O){this.store.setState(O)}reset(){this.store.reset()}applyInitial(O,$,K){this.store.setState({volume:O,muted:$,playbackRate:K})}updateLoadingState(){this.store.updateLoadingState()}updateReadyState(O,$){this.store.updateReadyState(O,$)}updatePlaybackState(O){this.store.updatePlaybackState(O)}updateSeekingState(O){this.store.updateSeekingState(O)}updateWaitingState(O){this.store.updateWaitingState(O)}updateEndedState(O){this.store.updateEndedState(O)}updateTime(O){this.store.updateTime(O)}updateDuration(O){this.store.updateDuration(O)}updateVolume(O,$){this.store.updateVolume(O,$)}updatePlaybackRate(O){this.store.updatePlaybackRate(O)}updateMediaInfo(O){this.store.updateMediaInfo(O)}updateTracks(O,$,K){this.store.updateTracks(O,$,K)}updateSelectedTracks(O,$){this.store.updateSelectedTracks(O,$)}updateError(O){this.store.updateError(O)}updateRendererType(O){this.store.updateRendererType(O)}updatePlaylist(O,$=null){this.store.updatePlaylist(O,$)}}class KO{chains=new Map;async run(O,$){let K=this.chains.get(O)??Promise.resolve(),j,Q=new Promise((V)=>{j=V});this.chains.set(O,K.then(()=>Q));try{return await K,await $()}finally{j?.()}}}class jO{deps;locks=new KO;constructor(O){this.deps=O}async setupInitialTracks(O,$){let K=!1,j=!1,Q="";if(O)try{if(K=await this.locks.run("video",async()=>{if(O.codec!==null&&await O.canDecode())return await this.deps.playbackController.trySetVideoTrack(O);return!1}),!K)Q+="Unsupported video codec. "}catch(V){Q+="Failed to set up video track. ",k.warn("Video track error:",V)}if($)try{if(j=await this.locks.run("audio",async()=>{if($.codec!==null&&await $.canDecode())return await this.deps.playbackController.trySetAudioTrack($);return!1}),!j)Q+="Unsupported audio codec. "}catch(V){Q+="Failed to set up audio track. ",k.warn("Audio track error:",V)}if(!K&&!j&&!Q)Q="No audio or video track found.";return{videoSupported:K,audioSupported:j,warningMessage:Q}}async selectVideoTrack(O,$){if(!O.selectVideoTrack($))throw Error(`Invalid video track ID: ${$}`);let K=O.getSelectedVideoTrack();if(!K){await this.deps.playbackController.setVideoTrack(null);return}if(!await this.locks.run("video",async()=>{if(K.codec!==null&&await K.canDecode())return await this.deps.playbackController.trySetVideoTrack(K);return!1}))this.deps.emit("warning",{type:"video-codec-unsupported",message:"Video codec not supported.",error:void 0}),await this.deps.playbackController.setVideoTrack(null)}async selectAudioTrack(O,$){if(!O.selectAudioTrack($))throw Error(`Invalid audio track ID: ${$}`);let K=O.getSelectedAudioTrack();if(!K){await this.deps.playbackController.setAudioTrack(null);return}if(!await this.locks.run("audio",async()=>{if(K.codec!==null&&await K.canDecode())return await this.deps.playbackController.trySetAudioTrack(K);return!1}))this.deps.emit("warning",{type:"audio-codec-unsupported",message:"Audio codec not supported. Continuing without audio.",error:void 0}),await this.deps.playbackController.setAudioTrack(null)}}import{AudioBufferSink as IO,AudioSampleSink as xO}from"mediabunny";class p{audioContext;gainNode=null;outputNode=null;bufferSink=null;sampleSink=null;bufferIterator=null;queuedNodes=new Set;startContextTime=0;startMediaTime=0;pauseTime=0;playing=!1;volume=1;muted=!1;disposed=!1;playbackId=0;playbackRate=1;pluginManager=null;constructor(O={}){if(O.audioContext)this.audioContext=O.audioContext;else{let $=window,K=$.AudioContext||$.webkitAudioContext;this.audioContext=new K}this.volume=O.volume??1,this.muted=O.muted??!1,this.setupAudioGraph()}setupAudioGraph(){if(this.gainNode=this.audioContext.createGain(),this.pluginManager){let O=this.pluginManager.executeOnAudioNode(this.audioContext,this.gainNode);this.outputNode=O}else this.outputNode=this.gainNode;this.outputNode.connect(this.audioContext.destination),this.updateGain()}setPluginManager(O){this.pluginManager=O,this.rebuildAudioGraph()}rebuildAudioGraph(){if(!this.gainNode)return;if(this.outputNode?.disconnect(),this.pluginManager){let O=this.pluginManager.executeOnAudioNode(this.audioContext,this.gainNode);this.outputNode=O}else this.outputNode=this.gainNode;this.outputNode.connect(this.audioContext.destination)}async setAudioTrack(O){if(this.dispose(),O.codec===null)throw Error("Unsupported audio codec");if(!await O.canDecode())throw Error(`Cannot decode audio track with codec: ${O.codec}`);this.bufferSink=new IO(O),this.sampleSink=new xO(O),this.disposed=!1}async play(O=this.pauseTime){if(this.playing||!this.bufferSink)return;if(this.audioContext.state==="suspended")await this.audioContext.resume();this.playbackId++;let $=this.playbackId;this.playing=!0,this.startContextTime=this.audioContext.currentTime,this.startMediaTime=O,this.pauseTime=O,this.bufferIterator=this.bufferSink.buffers(O),this.scheduleAudioBuffers($)}async scheduleAudioBuffers(O){let $=this.bufferIterator;if(!$||!this.gainNode)return;try{for await(let{buffer:K,timestamp:j}of $){if(O!==this.playbackId||this.disposed||!this.playing)break;let Q=this.audioContext.createBufferSource();Q.buffer=K,Q.connect(this.gainNode),Q.playbackRate.value=this.playbackRate,Q.playbackRate.setValueAtTime(this.playbackRate,this.audioContext.currentTime);let V=this.startContextTime+(j-this.startMediaTime)/this.playbackRate;if(V>=this.audioContext.currentTime)Q.start(V);else{let J=Math.max(0,(this.audioContext.currentTime-V)*this.playbackRate);if(J<K.duration)Q.start(this.audioContext.currentTime,J);else continue}if(this.queuedNodes.add(Q),Q.onended=()=>{this.queuedNodes.delete(Q)},j-this.getCurrentTime()>=1)await this.waitForCatchup(j)}}catch{}}async waitForCatchup(O){return new Promise(($)=>{let K=setInterval(()=>{if(O-this.getCurrentTime()<1||!this.playing)clearInterval(K),$()},100)})}pause(){if(!this.playing)return;let O=this.getCurrentTime();if(this.playing=!1,this.pauseTime=O,this.stopQueuedNodes(),this.bufferIterator)this.bufferIterator.return(),this.bufferIterator=null}stop(){this.pause(),this.pauseTime=0,this.startContextTime=0,this.startMediaTime=0}async seek(O){let $=this.playing;if($)this.pause();if(this.pauseTime=O,$)await this.play(O)}getCurrentTime(){if(this.playing){let O=this.audioContext.currentTime-this.startContextTime;return this.startMediaTime+O*this.playbackRate}return this.pauseTime}setVolume(O){this.volume=Math.max(0,Math.min(1,O)),this.updateGain()}setMuted(O){this.muted=O,this.updateGain()}updateGain(){if(!this.gainNode)return;let O=this.muted?0:this.volume;this.gainNode.gain.value=O*O}getVolume(){return this.volume}isMuted(){return this.muted}isPlaying(){return this.playing}setPlaybackRate(O){let $=Math.max(0.25,Math.min(4,O));if(this.playbackRate===$)return;let K=this.playing,j=this.getCurrentTime();if(this.playbackRate=$,K)this.pause(),this.pauseTime=j,this.play(j)}getAudioContext(){return this.audioContext}async getBufferAt(O){if(!this.bufferSink)return null;return this.bufferSink.getBuffer(O)}async getSampleAt(O){if(!this.sampleSink)return null;return this.sampleSink.getSample(O)}stopQueuedNodes(){for(let O of this.queuedNodes)try{O.stop()}catch{}this.queuedNodes.clear()}async clearIterators(){if(this.playbackId++,this.stop(),this.bufferIterator){try{await this.bufferIterator.return()}catch{}this.bufferIterator=null}}dispose(){if(this.disposed=!0,this.playbackId++,this.stop(),this.bufferIterator)this.bufferIterator.return(),this.bufferIterator=null;this.bufferSink=null,this.sampleSink=null}destroy(){if(this.dispose(),this.gainNode)this.gainNode.disconnect(),this.gainNode=null;if(this.audioContext.state!=="closed")this.audioContext.close()}}var fO=100,kO=250;class g{videoRenderer;audioManager;playing=!1;currentTime=0;duration=0;playbackRate=1;animationFrameId=null;lastFrameTime=0;syncIntervalId=null;renderIntervalId=null;isWaiting=!1;onTimeUpdate;onEnded;onWaiting;onPlaying;constructor(O={}){this.videoRenderer=new v({canvas:O.canvas,rendererType:O.rendererType}),this.audioManager=new p({audioContext:O.audioContext,volume:O.volume,muted:O.muted}),this.playbackRate=O.playbackRate??1}async setVideoTrack(O){if(!O){this.videoRenderer.dispose();return}await this.videoRenderer.setVideoTrack(O);let $=await O.computeDuration();this.duration=Math.max(this.duration,$)}async trySetVideoTrack(O){try{return await this.setVideoTrack(O),!0}catch{return!1}}async setAudioTrack(O){let $=this.playing,K=this.getCurrentTime();if(!O){this.audioManager.dispose();return}let j=await O.computeDuration(),Q=Math.max(0,Math.min(K,j));if(await this.audioManager.setAudioTrack(O),await this.audioManager.seek(Q),$)await this.audioManager.play(Q);this.currentTime=Q,this.duration=Math.max(this.duration,j)}async trySetAudioTrack(O){try{return await this.setAudioTrack(O),!0}catch{return!1}}async setCanvas(O){await this.videoRenderer.setCanvas(O)}async play(){if(this.playing)return;if(this.playing=!0,this.lastFrameTime=performance.now(),this.currentTime>=this.duration)this.currentTime=0,await this.videoRenderer.seek(0);await this.audioManager.play(this.currentTime),this.startRenderLoop(),this.startSyncInterval()}pause(){if(!this.playing)return;if(this.playing=!1,this.isWaiting=!1,this.audioManager.pause(),this.stopRenderLoop(),this.stopSyncInterval(),this.audioManager.isPlaying())this.currentTime=this.audioManager.getCurrentTime()}async seek(O){let $=Math.max(0,Math.min(O,this.duration));if(this.currentTime=$,await this.videoRenderer.seek($),await this.audioManager.seek($),this.onTimeUpdate)this.onTimeUpdate(this.currentTime)}startRenderLoop(){if(this.animationFrameId!==null||this.renderIntervalId!==null)return;let O=($=!0)=>{if(!this.playing)return;if(this.audioManager.isPlaying())this.currentTime=this.audioManager.getCurrentTime();else{let j=performance.now(),Q=(j-this.lastFrameTime)/1000;this.lastFrameTime=j,this.currentTime+=Q*this.playbackRate}if(this.currentTime>=this.duration){this.handleEnded();return}let{isStarving:K}=this.videoRenderer.updateFrame(this.currentTime);if(K&&!this.isWaiting){if(this.isWaiting=!0,this.onWaiting)this.onWaiting()}else if(!K&&this.isWaiting){if(this.isWaiting=!1,this.onPlaying)this.onPlaying()}if($)this.animationFrameId=requestAnimationFrame(()=>O())};if(this.animationFrameId=requestAnimationFrame(()=>O()),this.renderIntervalId===null)this.renderIntervalId=window.setInterval(()=>O(!1),fO)}stopRenderLoop(){if(this.animationFrameId!==null)cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null;if(this.renderIntervalId!==null)clearInterval(this.renderIntervalId),this.renderIntervalId=null}startSyncInterval(){if(this.syncIntervalId!==null)return;this.syncIntervalId=window.setInterval(()=>{if(this.playing&&this.onTimeUpdate)this.onTimeUpdate(this.currentTime)},kO)}stopSyncInterval(){if(this.syncIntervalId!==null)clearInterval(this.syncIntervalId),this.syncIntervalId=null}handleEnded(){if(this.pause(),this.currentTime=this.duration,this.onEnded)this.onEnded()}getCurrentTime(){if(this.playing&&this.audioManager.isPlaying())return this.audioManager.getCurrentTime();return this.currentTime}getDuration(){return this.duration}setDuration(O){this.duration=O}isPlaying(){return this.playing}setVolume(O){this.audioManager.setVolume(O)}getVolume(){return this.audioManager.getVolume()}setMuted(O){this.audioManager.setMuted(O)}isMuted(){return this.audioManager.isMuted()}setPlaybackRate(O){let $=Math.max(0.25,Math.min(4,O));if(this.playbackRate===$)return;this.playbackRate=$,this.audioManager.setPlaybackRate($),this.lastFrameTime=performance.now()}getPlaybackRate(){return this.playbackRate}setTimeUpdateCallback(O){this.onTimeUpdate=O}setEndedCallback(O){this.onEnded=O}setWaitingCallback(O){this.onWaiting=O}setPlayingCallback(O){this.onPlaying=O}isBuffering(){return this.isWaiting}async screenshot(O){return this.videoRenderer.screenshot(this.currentTime,O)}getVideoRenderer(){return this.videoRenderer}getAudioManager(){return this.audioManager}async switchRenderer(O){await this.videoRenderer.switchRenderer(O)}getRendererType(){return this.videoRenderer.getRendererType()}updateCanvasDimensions(){this.videoRenderer.updateCanvasDimensions()}setRendererChangeCallback(O){this.videoRenderer.setRendererChangeCallback(O)}setRendererFallbackCallback(O){this.videoRenderer.setRendererFallbackCallback(O)}setRotationChangeCallback(O){this.videoRenderer.setRotationChangeCallback(O)}setRotation(O){this.videoRenderer.setRotation(O)}getRotation(){return this.videoRenderer.getRotation()}getDisplaySize(){return this.videoRenderer.getDisplaySize()}setPluginManager(O){this.videoRenderer.setPluginManager(O),this.audioManager.setPluginManager(O)}getCanvas(){return this.videoRenderer.getCanvas()}refreshOverlays(){this.videoRenderer.refreshOverlays()}rebuildAudioGraph(){this.audioManager.rebuildAudioGraph()}async reset(){this.pause(),this.stopRenderLoop(),this.stopSyncInterval(),this.currentTime=0,this.duration=0,await Promise.all([this.videoRenderer.clearIterators(),this.audioManager.clearIterators()]),this.playbackRate=1,this.lastFrameTime=0}dispose(){this.pause(),this.videoRenderer.dispose(),this.audioManager.dispose(),this.onTimeUpdate=void 0,this.onEnded=void 0,this.onWaiting=void 0,this.onPlaying=void 0}destroy(){this.dispose(),this.audioManager.destroy()}}function m(){return crypto?.randomUUID?.()??Date.now().toString(36)+Math.random().toString(36).substr(2)}class QO{store;emitter;switchSource;sourceManager;constructor(O,$,K,j){this.store=O,this.emitter=$,this.switchSource=K,this.sourceManager=j}async loadPlaylist(O,$={}){let K=O.map((j)=>{if(j&&typeof j==="object"&&"mediaSource"in j)return{id:m(),mediaSource:j.mediaSource,title:j.title,poster:j.poster,savedPosition:null,duration:null};else return{id:m(),mediaSource:j,savedPosition:null,duration:null}});if(this.store.updatePlaylist(K,K.length>0?0:null),this.emitter.emit("playlistchange",{playlist:K}),K.length>0&&this.switchSource){let j=K[0];if($.startTime!==void 0)j.savedPosition=$.startTime;await this.switchSource(j,$.autoplay??!1)}}addToPlaylist(O,$){let K=this.createPlaylistItem(O);this.store.addToPlaylist(K,$),this.emitter.emit("playlistadd",{item:K,index:$??this.store.getState().playlist.length-1})}async removeFromPlaylist(O){let $=this.store.getState(),K=$.currentPlaylistIndex,j=$.playing;this.store.removeFromPlaylist(O),this.emitter.emit("playlistremove",{index:O}),this.sourceManager?.disposeQueued($.playlist[O]?.id||"");let Q=this.store.getState(),V=Q.currentPlaylistIndex;if(Q.playlist.length===0)this.sourceManager?.disposeAll(),this.emitter.emit("playlistchange",{playlist:Q.playlist}),this.emitter.emit("playlistend",void 0);if(K===O&&V!==null&&V!==K&&this.switchSource){let J=Q.playlist[V];try{await this.switchSource(J,j)}catch(U){this.emitter.emit("playlistitemerror",{index:V,error:U})}}}clearPlaylist(){this.store.clearPlaylist(),this.emitter.emit("playlistchange",{playlist:[]}),this.emitter.emit("playlistend",void 0),this.sourceManager?.disposeAll()}async next(){let O=this.store.getState(),$=O.currentPlaylistIndex??0,K=O.playlist,j=O.playlistMode,Q=null;if(j==="repeat-one")Q=$;else if(j==="sequential"||j==="repeat")if($<K.length-1)Q=$+1;else if(j==="repeat")Q=0;else{this.emitter.emit("playlistend",void 0);return}else if($<K.length-1)Q=$+1;if(Q!==null)await this.switchTo(Q)}async prev(){let $=this.store.getState().currentPlaylistIndex??0;if($>0)await this.switchTo($-1)}async jumpTo(O){let K=this.store.getState().playlist;if(O>=0&&O<K.length)await this.switchTo(O);else if(O>=K.length)this.emitter.emit("playlistend",void 0)}setMode(O){let $=["sequential","manual","repeat","repeat-one",null];if(!$.includes(O))throw Error(`Invalid playlist mode: ${O}. Valid modes: ${$.filter((K)=>K!==null).join(", ")}, null`);this.store.updatePlaylistMode(O)}async switchTo(O){let $=this.store.getState(),K=$.currentPlaylistIndex,j=$.playing,Q=[...$.playlist];if(K!==null&&K!==O){let U=Q[K];Q[K]={...U,savedPosition:$.currentTime}}this.store.updatePlaylist(Q,O);let V=Q[O];if(this.emitter.emit("playlistitemchange",{index:O,item:V,previousIndex:K??void 0}),this.switchSource)await this.switchSource(V,j);if($.playlistMode==="sequential"&&O<Q.length-1){let U=Q[O+1];this.sourceManager?.preloadSource(U.mediaSource,U.id)}}createPlaylistItem(O){if(O&&typeof O==="object"&&"mediaSource"in O)return{id:m(),mediaSource:O.mediaSource,title:O.title,poster:O.poster,savedPosition:null,duration:null};else return{id:m(),mediaSource:O,savedPosition:null,duration:null}}get playlist(){return this.store.getState().playlist}get currentIndex(){return this.store.getState().currentPlaylistIndex}get currentItem(){let O=this.currentIndex;return O!==null?this.playlist[O]:null}get mode(){return this.store.getState().playlistMode}dispose(){if(this.sourceManager)this.sourceManager=void 0;this.switchSource=void 0}}function GO(O,$,K,j){let Q=$.name;return{player:O,getState(){return O.getState()},subscribe(V){let J=O.subscribe(V),U=()=>J.unsubscribe();return K.stateUnsubscribes.push(U),U},getPluginState(){return K.pluginState},setPluginState(V){K.pluginState=V},on(V,J){O.on(V,J);let U=K.eventListeners.get(V);if(!U)U=new Set,K.eventListeners.set(V,U);U.add(J)},off(V,J){O.off(V,J);let U=K.eventListeners.get(V);if(U)U.delete(J)},getCanvas(){return O.getRenderTarget()},getPlugin(V){return j().get(V)?.plugin},hasPlugin(V){return j().has(V)},log(...V){console.log(`[MediaFox:${Q}]`,...V)},warn(...V){console.warn(`[MediaFox:${Q}]`,...V)},error(...V){console.error(`[MediaFox:${Q}]`,...V)}}}class VO{player;plugins=new Map;overlays=[];overlaysSorted=!1;registrationCounter=0;constructor(O){this.player=O}async install(O){let{name:$}=O;if(this.plugins.has($))throw Error(`Plugin "${$}" is already installed`);if(O.dependencies){for(let j of O.dependencies)if(!this.plugins.has(j))throw Error(`Plugin "${$}" requires plugin "${j}" to be installed first`)}let K={plugin:O,context:null,eventListeners:new Map,stateUnsubscribes:[],pluginState:void 0};K.context=GO(this.player,O,K,()=>this.plugins),this.plugins.set($,K);try{await O.install(K.context)}catch(j){throw this.plugins.delete($),j}if(O.hooks?.render?.onOverlay)this.overlays.push({pluginName:$,zIndex:O.hooks.render.onOverlay.zIndex??0,registrationOrder:this.registrationCounter++,render:O.hooks.render.onOverlay}),this.overlaysSorted=!1,this.player.refreshOverlays()}async uninstall(O){let $=this.plugins.get(O);if(!$)throw Error(`Plugin "${O}" is not installed`);try{await $.plugin.uninstall?.()}catch(j){console.error(`Error uninstalling plugin "${O}":`,j)}for(let[j,Q]of $.eventListeners)for(let V of Q)this.player.off(j,V);for(let j of $.stateUnsubscribes)j();let K=this.overlays.some((j)=>j.pluginName===O);if(this.overlays=this.overlays.filter((j)=>j.pluginName!==O),this.plugins.delete(O),K)this.player.refreshOverlays()}has(O){return this.plugins.has(O)}get size(){return this.plugins.size}async executeBeforeLoad(O){for(let[,$]of this.plugins){let K=$.plugin.hooks?.lifecycle?.beforeLoad;if(!K)continue;try{let j=await K.call($.plugin,O);if(j?.cancel)return j;if(j?.data!==void 0)O=j.data}catch(j){console.error(`[MediaFox:${$.plugin.name}] Error in beforeLoad hook:`,j)}}return{data:O}}async executeAfterLoad(O){for(let[,$]of this.plugins){let K=$.plugin.hooks?.lifecycle?.afterLoad;if(!K)continue;try{await K.call($.plugin,O)}catch(j){console.error(`[MediaFox:${$.plugin.name}] Error in afterLoad hook:`,j)}}}async executeBeforePlay(){for(let[,O]of this.plugins){let $=O.plugin.hooks?.lifecycle?.beforePlay;if(!$)continue;try{let K=await $.call(O.plugin);if(K?.cancel)return K}catch(K){console.error(`[MediaFox:${O.plugin.name}] Error in beforePlay hook:`,K)}}return}executeAfterPlay(){for(let[,O]of this.plugins){let $=O.plugin.hooks?.lifecycle?.afterPlay;if(!$)continue;try{$.call(O.plugin)}catch(K){console.error(`[MediaFox:${O.plugin.name}] Error in afterPlay hook:`,K)}}}async executeBeforePause(){for(let[,O]of this.plugins){let $=O.plugin.hooks?.lifecycle?.beforePause;if(!$)continue;try{let K=await $.call(O.plugin);if(K?.cancel)return K}catch(K){console.error(`[MediaFox:${O.plugin.name}] Error in beforePause hook:`,K)}}return}executeAfterPause(){for(let[,O]of this.plugins){let $=O.plugin.hooks?.lifecycle?.afterPause;if(!$)continue;try{$.call(O.plugin)}catch(K){console.error(`[MediaFox:${O.plugin.name}] Error in afterPause hook:`,K)}}}async executeBeforeSeek(O){for(let[,$]of this.plugins){let K=$.plugin.hooks?.lifecycle?.beforeSeek;if(!K)continue;try{let j=await K.call($.plugin,O);if(j?.cancel)return j;if(j?.data!==void 0)O=j.data}catch(j){console.error(`[MediaFox:${$.plugin.name}] Error in beforeSeek hook:`,j)}}return{data:O}}executeAfterSeek(O){for(let[,$]of this.plugins){let K=$.plugin.hooks?.lifecycle?.afterSeek;if(!K)continue;try{K.call($.plugin,O)}catch(j){console.error(`[MediaFox:${$.plugin.name}] Error in afterSeek hook:`,j)}}}async executeBeforeStop(){for(let[,O]of this.plugins){let $=O.plugin.hooks?.lifecycle?.beforeStop;if(!$)continue;try{let K=await $.call(O.plugin);if(K?.cancel)return K}catch(K){console.error(`[MediaFox:${O.plugin.name}] Error in beforeStop hook:`,K)}}return}executeAfterStop(){for(let[,O]of this.plugins){let $=O.plugin.hooks?.lifecycle?.afterStop;if(!$)continue;try{$.call(O.plugin)}catch(K){console.error(`[MediaFox:${O.plugin.name}] Error in afterStop hook:`,K)}}}executeOnError(O){let $=!1;for(let[,K]of this.plugins){let j=K.plugin.hooks?.lifecycle?.onError;if(!j)continue;try{if(j.call(K.plugin,O)?.handled)$=!0}catch(Q){console.error(`[MediaFox:${K.plugin.name}] Error in onError hook:`,Q)}}return $}executeOnEnded(){for(let[,O]of this.plugins){let $=O.plugin.hooks?.lifecycle?.onEnded;if(!$)continue;try{$.call(O.plugin)}catch(K){console.error(`[MediaFox:${O.plugin.name}] Error in onEnded hook:`,K)}}}executeBeforeRender(O,$){for(let[,K]of this.plugins){let j=K.plugin.hooks?.render?.beforeRender;if(!j)continue;try{let Q=j.call(K.plugin,O,$);if(Q?.skip)return Q}catch(Q){console.error(`[MediaFox:${K.plugin.name}] Error in beforeRender hook:`,Q)}}return}executeTransformFrame(O){for(let[,$]of this.plugins){let K=$.plugin.hooks?.render?.transformFrame;if(!K)continue;try{let j=K.call($.plugin,O);if(j)O=j}catch(j){console.error(`[MediaFox:${$.plugin.name}] Error in transformFrame hook:`,j)}}return O}executeAfterRender(O){for(let[,$]of this.plugins){let K=$.plugin.hooks?.render?.afterRender;if(!K)continue;try{K.call($.plugin,O)}catch(j){console.error(`[MediaFox:${$.plugin.name}] Error in afterRender hook:`,j)}}}executeOverlays(O,$,K){if(this.overlays.length===0)return;if(!this.overlaysSorted)this.overlays.sort((j,Q)=>{if(j.zIndex!==Q.zIndex)return j.zIndex-Q.zIndex;return j.registrationOrder-Q.registrationOrder}),this.overlaysSorted=!0;for(let j of this.overlays)try{j.render?.render(O,$,K)}catch(Q){console.error(`[MediaFox:${j.pluginName}] Error in onOverlay hook:`,Q)}}executeBeforeStateUpdate(O){for(let[,$]of this.plugins){let K=$.plugin.hooks?.state?.beforeStateUpdate;if(!K)continue;try{let j=K.call($.plugin,O);if(j===null)return null;if(j!==void 0)O=j}catch(j){console.error(`[MediaFox:${$.plugin.name}] Error in beforeStateUpdate hook:`,j)}}return O}executeOnStateChange(O,$){for(let[,K]of this.plugins){let j=K.plugin.hooks?.state?.onStateChange;if(!j)continue;try{j.call(K.plugin,O,$)}catch(Q){console.error(`[MediaFox:${K.plugin.name}] Error in onStateChange hook:`,Q)}}}executeBeforeEvent(O,$){for(let[,K]of this.plugins){let j=K.plugin.hooks?.event?.beforeEvent;if(!j)continue;try{let Q=j.call(K.plugin,O,$);if(Q?.cancel)return Q;if(Q?.data!==void 0)$=Q.data}catch(Q){console.error(`[MediaFox:${K.plugin.name}] Error in beforeEvent hook:`,Q)}}return{data:$}}executeAfterEvent(O,$){for(let[,K]of this.plugins){let j=K.plugin.hooks?.event?.afterEvent;if(!j)continue;try{j.call(K.plugin,O,$)}catch(Q){console.error(`[MediaFox:${K.plugin.name}] Error in afterEvent hook:`,Q)}}}executeOnAudioNode(O,$){let K=$;for(let[,j]of this.plugins){let Q=j.plugin.hooks?.audio?.onAudioNode;if(!Q)continue;try{let V=Q.call(j.plugin,O,$);if(V)K=V}catch(V){console.error(`[MediaFox:${j.plugin.name}] Error in onAudioNode hook:`,V)}}return K}async dispose(){let O=Array.from(this.plugins.keys()).reverse();for(let $ of O)try{await this.uninstall($)}catch(K){console.error(`Error disposing plugin "${$}":`,K)}}}import{ALL_FORMATS as vO,BlobSource as hO,BufferSource as pO,CanvasSink as gO,FilePathSource as mO,Input as uO,ReadableStreamSource as lO,UrlSource as cO}from"mediabunny";class u{currentSource=null;queuedSources=new Map;options;constructor(O={}){this.options={maxCacheSize:O.maxCacheSize??16777216,crossOrigin:O.crossOrigin,requestInit:O.requestInit}}async createSource(O,$){if(this.currentSource&&!$)this.disposeCurrent();let K,j;if(O instanceof File||O instanceof Blob)K=new hO(O,{maxCacheSize:this.options.maxCacheSize}),j="blob";else if(O instanceof ArrayBuffer||O instanceof Uint8Array)K=new pO(O),j="buffer";else if(typeof O==="string"||O instanceof URL){let J=O instanceof URL?O.href:O;if(typeof window>"u"&&!J.startsWith("http"))K=new mO(J,{maxCacheSize:this.options.maxCacheSize}),j="file";else K=new cO(J,{maxCacheSize:this.options.maxCacheSize,requestInit:this.options.requestInit}),j="url"}else if(typeof ReadableStream<"u"&&O instanceof ReadableStream)K=new lO(O,{maxCacheSize:this.options.maxCacheSize}),j="stream";else throw TypeError("Unsupported media source type");let Q=new uO({source:K,formats:vO}),V={source:K,input:Q,type:j,originalSource:O};if($)this.queuedSources.set($,V);else this.currentSource=V;return V}getCurrentSource(){return this.currentSource}getQueuedSource(O){return this.queuedSources.get(O)||null}async preloadSource(O,$){if(this.queuedSources.has($))return;let K=await this.createSource(O,$);if(K.input)try{let j=await this.prefetchTrackData(K.input);K.prefetchedData=j}catch{}}async prefetchTrackData(O){let $=await O.getVideoTracks(),K=await O.getAudioTracks(),j=$.length>0?$[0]:null,Q=K.length>0?K[0]:null,V=null,J=null,U=0;if(j){if(j.codec!==null&&await j.canDecode()){V=new gO(j,{poolSize:2});let Z=V.canvases(0);J=(await Z.next()).value??null,await Z.return(),U=await j.computeDuration()}}if(!U&&Q)U=await Q.computeDuration();return{videoTrack:j,audioTrack:Q,canvasSink:V,firstFrame:J,duration:U}}promoteQueuedSource(O){let $=this.queuedSources.get(O);if(!$)return null;if(this.queuedSources.delete(O),this.currentSource)this.currentSource.input?.dispose();return this.currentSource=$,$}getOriginalSource(){return this.currentSource?.originalSource??null}disposeCurrent(){if(this.currentSource)this.currentSource.input?.dispose(),this.currentSource=null}disposeQueued(O){let $=this.queuedSources.get(O);if($)$.input?.dispose(),this.queuedSources.delete(O)}disposeAll(){this.disposeCurrent(),this.queuedSources.forEach((O,$)=>{this.disposeQueued($)}),this.queuedSources.clear()}dispose(){this.disposeAll()}static isStreamingSource(O){return O instanceof ReadableStream||typeof O==="string"&&O.startsWith("http")}static isLocalSource(O){return O instanceof File||O instanceof Blob||O instanceof ArrayBuffer||O instanceof Uint8Array||typeof O==="string"&&!O.startsWith("http")}static getSourceType(O){if(O instanceof File)return"file";if(O instanceof Blob)return"blob";if(O instanceof ArrayBuffer||O instanceof Uint8Array)return"buffer";if(O instanceof ReadableStream)return"stream";if(typeof O==="string"||O instanceof URL)return(O instanceof URL?O.href:O).startsWith("http")?"url":"file";return"unknown"}static async fromFetch(O,$){let K=await fetch(O,$);if(!K.ok)throw Error(`Failed to fetch: ${K.status} ${K.statusText}`);return K.blob()}static fromStreamingFetch(O,$){return new ReadableStream({async start(K){let j=await fetch(O,$);if(!j.ok){K.error(Error(`Failed to fetch: ${j.status} ${j.statusText}`));return}let Q=j.body?.getReader();if(!Q){K.error(Error("Response body is not readable"));return}try{while(!0){let{done:V,value:J}=await Q.read();if(V)break;K.enqueue(J)}K.close()}catch(V){K.error(V)}}})}}function l(O,$){if(Object.is(O,$))return!0;if(typeof O!==typeof $)return!1;if(O===null||$===null)return O===$;if(Array.isArray(O)&&Array.isArray($)){if(O.length!==$.length)return!1;for(let K=0;K<O.length;K++)if(!l(O[K],$[K]))return!1;return!0}if(PO(O)&&PO($)){let K=Object.keys(O),j=Object.keys($);if(K.length!==j.length)return!1;for(let Q of K){if(!Object.hasOwn($,Q))return!1;if(!l(O[Q],$[Q]))return!1}return!0}return!1}function PO(O){return typeof O==="object"&&O!==null&&O.constructor===Object}class c{state;previousState;listeners=new Set;updateScheduled=!1;pendingUpdates={};pendingKeys=[];pluginManager=null;listenerCache=[];constructor(){this.state=this.getInitialState(),this.previousState={...this.state}}setPluginManager(O){this.pluginManager=O}getInitialState(){let $=H.getSupportedRenderers()[0]||"canvas2d";return{state:"idle",currentTime:0,duration:0,buffered:[],volume:1,muted:!1,playbackRate:1,playing:!1,paused:!0,ended:!1,seeking:!1,waiting:!1,error:null,mediaInfo:null,videoTracks:[],audioTracks:[],subtitleTracks:[],selectedVideoTrack:null,selectedAudioTrack:null,selectedSubtitleTrack:null,canPlay:!1,canPlayThrough:!1,isLive:!1,rendererType:$,playlist:[],currentPlaylistIndex:null,playlistMode:null,rotation:0,displaySize:{width:0,height:0}}}getState(){return this.state}setState(O){if(this.pluginManager){let K=this.pluginManager.executeBeforeStateUpdate(O);if(K===null)return;O=K}let $=Object.keys(O);for(let K=0;K<$.length;K++){let j=$[K];if(this.pendingUpdates[j]===void 0)this.pendingKeys.push(j);this.setPendingValue(j,O[j])}if(!this.updateScheduled)this.updateScheduled=!0,queueMicrotask(()=>this.flushUpdates())}setPendingValue(O,$){this.pendingUpdates[O]=$}flushUpdates(){let O=this.pendingKeys;if(O.length===0){this.updateScheduled=!1;return}let $=!1;for(let K=0;K<O.length;K++){let j=O[K];if(!l(this.pendingUpdates[j],this.state[j])){$=!0;break}}for(let K=0;K<O.length;K++){let j=O[K];this.copyStateKey(j)}if(this.pendingUpdates={},this.pendingKeys.length=0,this.updateScheduled=!1,$){if(this.notifyListeners(),this.pluginManager)this.pluginManager.executeOnStateChange(this.state,this.previousState)}}copyStateKey(O){if(this.previousState[O]=this.state[O],O in this.pendingUpdates)this.state[O]=this.pendingUpdates[O]}subscribe(O){return this.listeners.add(O),O(this.getState()),()=>{this.listeners.delete(O)}}reset(){this.state=this.getInitialState(),this.pendingUpdates={},this.pendingKeys.length=0,this.updateScheduled=!1,this.notifyListeners()}notifyListeners(){let O=this.state,$=this.listenerCache;$.length=0;for(let K of this.listeners)$.push(K);for(let K=0;K<$.length;K++)try{$[K](O)}catch(j){console.error("Error in state listener:",j)}}updatePlaybackState(O){let $=O?"playing":"paused";this.setState({state:$,playing:O,paused:!O,ended:!1})}updateTime(O){this.setState({currentTime:O})}updateDuration(O){this.setState({duration:O})}updateBuffered(O){this.setState({buffered:O})}updateVolume(O,$){this.setState({volume:O,muted:$})}updatePlaybackRate(O){this.setState({playbackRate:O})}updateMediaInfo(O){this.setState({mediaInfo:O})}updateTracks(O,$,K){let j={};if(O)j.videoTracks=O;if($)j.audioTracks=$;if(K)j.subtitleTracks=K;this.setState(j)}updateSelectedTracks(O,$){switch(O){case"video":this.setState({selectedVideoTrack:$});break;case"audio":this.setState({selectedAudioTrack:$});break;case"subtitle":this.setState({selectedSubtitleTrack:$});break}}updateError(O){this.setState({error:O,state:O?"error":this.state.state})}updateSeekingState(O){this.setState({seeking:O})}updateWaitingState(O){this.setState({waiting:O})}updateReadyState(O,$){this.setState({canPlay:O,canPlayThrough:$,state:O?"ready":this.state.state})}updateEndedState(O){this.setState({ended:O,playing:!1,paused:!0,state:O?"ended":this.state.state})}updateLoadingState(){this.setState({state:"loading",playing:!1,paused:!0,ended:!1,error:null})}updateRendererType(O){this.setState({rendererType:O})}updateRotation(O,$){this.setState({rotation:O,displaySize:$})}updatePlaylist(O,$=null){this.setState({playlist:O,currentPlaylistIndex:$})}updateCurrentPlaylistIndex(O){this.setState({currentPlaylistIndex:O})}updatePlaylistMode(O){this.setState({playlistMode:O})}addToPlaylist(O,$){let K=this.state.playlist,j,Q=this.state.currentPlaylistIndex;if($!==void 0&&$>=0&&$<=K.length){if(j=[...K.slice(0,$),O,...K.slice($)],Q!==null&&Q>=$)Q+=1}else j=[...K,O];this.setState({playlist:j,currentPlaylistIndex:Q})}removeFromPlaylist(O){let $=this.state.playlist;if(O<0||O>=$.length)return;let K=$.filter((Q,V)=>V!==O),j=this.state.currentPlaylistIndex;if(j===O)j=K.length>0?0:null;else if(j!==null&&j>O)j-=1;if(K.length===0)this.setState({playlist:K,currentPlaylistIndex:null,state:"idle",currentTime:0,duration:0,mediaInfo:null,videoTracks:[],audioTracks:[],subtitleTracks:[],selectedVideoTrack:null,selectedAudioTrack:null,selectedSubtitleTrack:null});else this.setState({playlist:K,currentPlaylistIndex:j})}clearPlaylist(){this.setState({playlist:[],currentPlaylistIndex:null,state:"idle",currentTime:0,duration:0,mediaInfo:null,videoTracks:[],audioTracks:[],subtitleTracks:[],selectedVideoTrack:null,selectedAudioTrack:null,selectedSubtitleTrack:null})}}class o{input=null;videoTracks=new Map;audioTracks=new Map;videoTrackInfos=[];audioTrackInfos=[];subtitleTrackInfos=[];subtitleProviders=new Map;subtitleTrackResolvers=new Map;selectedVideoTrack=null;selectedAudioTrack=null;selectedSubtitleTrack=null;onTrackChange;async initialize(O){this.videoTracks.clear(),this.audioTracks.clear(),this.videoTrackInfos=[],this.audioTrackInfos=[],this.selectedVideoTrack=null,this.selectedAudioTrack=null,this.input=O,await this.loadTracks()}async loadTracks(){if(!this.input)return;let O=await this.input.getVideoTracks();this.videoTrackInfos=await Promise.all(O.map(async(K)=>{let j=`video-${K.id}`;this.videoTracks.set(j,K);let Q=0,V=0;try{let U=await K.computePacketStats(100);Q=U.averagePacketRate,V=U.averageBitrate}catch{}return{id:j,codec:K.codec,language:K.languageCode,name:K.name,width:K.codedWidth,height:K.codedHeight,frameRate:Q,bitrate:V,rotation:K.rotation,selected:!1,decodable:await K.canDecode()}}));let $=await this.input.getAudioTracks();if(this.audioTrackInfos=await Promise.all($.map(async(K)=>{let j=`audio-${K.id}`;this.audioTracks.set(j,K);let Q=0;try{Q=(await K.computePacketStats(100)).averageBitrate}catch{}return{id:j,codec:K.codec,language:K.languageCode,name:K.name,channels:K.numberOfChannels,sampleRate:K.sampleRate,bitrate:Q,selected:!1,decodable:await K.canDecode()}})),this.videoTrackInfos.length>0){let K=this.videoTrackInfos.find((j)=>j.decodable);if(K)this.selectVideoTrack(K.id)}if(this.audioTrackInfos.length>0){let K=this.audioTrackInfos.find((j)=>j.decodable);if(K)this.selectAudioTrack(K.id)}}getVideoTracks(){return[...this.videoTrackInfos]}getAudioTracks(){return[...this.audioTrackInfos]}getSubtitleTracks(){return[...this.subtitleTrackInfos]}getSelectedVideoTrack(){if(!this.selectedVideoTrack)return null;return this.videoTracks.get(this.selectedVideoTrack)??null}getSelectedAudioTrack(){if(!this.selectedAudioTrack)return null;return this.audioTracks.get(this.selectedAudioTrack)??null}getSelectedVideoTrackInfo(){if(!this.selectedVideoTrack)return null;return this.videoTrackInfos.find((O)=>O.id===this.selectedVideoTrack)??null}getSelectedAudioTrackInfo(){if(!this.selectedAudioTrack)return null;return this.audioTrackInfos.find((O)=>O.id===this.selectedAudioTrack)??null}getSelectedSubtitleTrackInfo(){if(!this.selectedSubtitleTrack)return null;return this.subtitleTrackInfos.find((O)=>O.id===this.selectedSubtitleTrack)??null}selectVideoTrack(O){if(O===this.selectedVideoTrack)return!0;if(O&&!this.videoTracks.has(O))return!1;let $=this.selectedVideoTrack;if(this.videoTrackInfos.forEach((K)=>{K.selected=K.id===O}),this.selectedVideoTrack=O,this.onTrackChange)this.onTrackChange({type:"video",previousTrackId:$,newTrackId:O});return!0}selectAudioTrack(O){if(O===this.selectedAudioTrack)return!0;if(O&&!this.audioTracks.has(O))return!1;let $=this.selectedAudioTrack;if(this.audioTrackInfos.forEach((K)=>{K.selected=K.id===O}),this.selectedAudioTrack=O,this.onTrackChange)this.onTrackChange({type:"audio",previousTrackId:$,newTrackId:O});return!0}selectSubtitleTrack(O){if(O===this.selectedSubtitleTrack)return!0;if(O&&!this.subtitleTrackResolvers.has(O))return!1;let $=this.selectedSubtitleTrack;if(this.subtitleTrackInfos.forEach((K)=>{K.selected=K.id===O}),this.selectedSubtitleTrack=O,this.onTrackChange)this.onTrackChange({type:"subtitle",previousTrackId:$,newTrackId:O});return!0}registerSubtitleTracks(O,$){this.subtitleProviders.set(O,$),this.rebuildSubtitleTracks()}unregisterSubtitleTracks(O){if(!this.subtitleProviders.delete(O))return;this.rebuildSubtitleTracks()}async getSubtitleTrackResource(O){if(!O)return null;let $=this.subtitleTrackResolvers.get(O);if(!$)return null;return $()}rebuildSubtitleTracks(){let O=this.selectedSubtitleTrack;this.subtitleTrackInfos=[],this.subtitleTrackResolvers.clear();for(let K of this.subtitleProviders.values())for(let j of K){let Q={...j.info,selected:!1};this.subtitleTrackInfos.push(Q),this.subtitleTrackResolvers.set(Q.id,j.resolver)}let $=O;if(!$||!this.subtitleTrackResolvers.has($))$=this.subtitleTrackInfos[0]?.id??null;if(this.selectedSubtitleTrack=$,this.subtitleTrackInfos.forEach((K)=>{K.selected=K.id===this.selectedSubtitleTrack}),O!==this.selectedSubtitleTrack&&this.onTrackChange)this.onTrackChange({type:"subtitle",previousTrackId:O,newTrackId:this.selectedSubtitleTrack})}setTrackChangeListener(O){this.onTrackChange=O}getState(){return{videoTracks:this.getVideoTracks(),audioTracks:this.getAudioTracks(),subtitleTracks:this.getSubtitleTracks(),selectedVideoTrack:this.selectedVideoTrack,selectedAudioTrack:this.selectedAudioTrack,selectedSubtitleTrack:this.selectedSubtitleTrack}}getPrimaryVideoTrack(){if(this.videoTracks.size===0)return null;return this.selectedVideoTrack?this.videoTracks.get(this.selectedVideoTrack)??null:this.videoTracks.values().next().value??null}getPrimaryAudioTrack(){if(this.audioTracks.size===0)return null;return this.selectedAudioTrack?this.audioTracks.get(this.selectedAudioTrack)??null:this.audioTracks.values().next().value??null}hasVideo(){return this.videoTrackInfos.length>0}hasAudio(){return this.audioTrackInfos.length>0}hasSubtitles(){return this.subtitleTrackInfos.length>0}dispose(){this.videoTracks.clear(),this.audioTracks.clear(),this.videoTrackInfos=[],this.audioTrackInfos=[],this.subtitleTrackInfos=[],this.subtitleProviders.clear(),this.subtitleTrackResolvers.clear(),this.selectedVideoTrack=null,this.selectedAudioTrack=null,this.selectedSubtitleTrack=null,this.input=null,this.onTrackChange=void 0}async replaceAudioTrackByInputId(O,$){let K=null;for(let[Q,V]of this.audioTracks.entries())if(V.id===O){K=Q;break}if(!K)return;this.audioTracks.set(K,$);let j=this.audioTrackInfos.findIndex((Q)=>Q.id===K);if(j!==-1){let Q=0;try{Q=(await $.computePacketStats(100)).averageBitrate}catch{}this.audioTrackInfos[j]={...this.audioTrackInfos[j],codec:$.codec,channels:$.numberOfChannels,sampleRate:$.sampleRate,bitrate:Q,decodable:await $.canDecode()}}}async replaceVideoTrackByInputId(O,$){let K=null;for(let[Q,V]of this.videoTracks.entries())if(V.id===O){K=Q;break}if(!K)return;this.videoTracks.set(K,$);let j=this.videoTrackInfos.findIndex((Q)=>Q.id===K);if(j!==-1){let Q=0,V=0;try{let J=await $.computePacketStats(100);Q=J.averagePacketRate,V=J.averageBitrate}catch{}this.videoTrackInfos[j]={...this.videoTrackInfos[j],codec:$.codec,width:$.codedWidth,height:$.codedHeight,rotation:$.rotation,frameRate:Q,bitrate:V,decodable:await $.canDecode()}}}}class d{emitter;store;state;sourceManager;playbackController;trackManager;playlistManager;pluginManager;options;disposed=!1;getCurrentInput=()=>this.sourceManager.getCurrentSource()?.input??null;trackSwitcher;core;constructor(O={}){this.options={volume:1,muted:!1,playbackRate:1,autoplay:!1,preload:"metadata",...O},this.emitter=new I({maxListeners:100}),this.store=new c,this.state=new $O(this.store),this.sourceManager=new u({maxCacheSize:O.maxCacheSize,crossOrigin:O.crossOrigin}),this.playbackController=new g({canvas:O.renderTarget,audioContext:O.audioContext,volume:this.options.volume,muted:this.options.muted,playbackRate:this.options.playbackRate,rendererType:this.options.renderer}),this.trackManager=new o,this.playlistManager=new QO(this.store,this.emitter,async($,K)=>{await this.core.load($.mediaSource,{startTime:$.savedPosition??0,autoplay:K,playlistItemId:$.id})},this.sourceManager),this.trackSwitcher=new jO({sourceManager:this.sourceManager,trackManager:this.trackManager,playbackController:this.playbackController,emit:this.emit.bind(this),store:this.store,getCurrentInput:this.getCurrentInput}),this.pluginManager=new VO(this),this.core=new OO({state:this.state,sourceManager:this.sourceManager,trackManager:this.trackManager,playbackController:this.playbackController,trackSwitcher:this.trackSwitcher,emit:this.emit.bind(this),pluginManager:this.pluginManager}),this.playbackController.setPluginManager(this.pluginManager),this.store.setPluginManager(this.pluginManager),this.setupInternalListeners(),this.state.applyInitial(this.options.volume??1,this.options.muted??!1,this.options.playbackRate??1),this.state.updateRendererType(this.options.renderer||"webgpu")}setupInternalListeners(){this.playbackController.setTimeUpdateCallback((O)=>{this.state.updateTime(O),this.emit("timeupdate",{currentTime:O})}),this.playbackController.setEndedCallback(()=>{this.state.updateEndedState(!0),this.emit("ended",void 0);let O=this.getState();if(O.playlist.length>0&&O.currentPlaylistIndex!==null){let{playlistMode:$,currentPlaylistIndex:K}=O;if($==="repeat-one"){let j=K;queueMicrotask(async()=>{try{await this.seek(0),await this.play()}catch(Q){this.emitter.emit("playlistitemerror",{index:j,error:Q})}})}else if($==="repeat"){let j=K<O.playlist.length-1?K+1:0;queueMicrotask(async()=>{try{await this.playlistManager.next()}catch(Q){this.emitter.emit("playlistitemerror",{index:j,error:Q})}})}else if($==="sequential"&&K<O.playlist.length-1){let j=K+1;queueMicrotask(async()=>{try{await this.playlistManager.next()}catch(Q){this.emitter.emit("playlistitemerror",{index:j,error:Q})}})}}}),this.trackManager.setTrackChangeListener((O)=>{this.state.updateSelectedTracks(O.type,O.newTrackId),this.emit("trackchange",{type:O.type,trackId:O.newTrackId})}),this.playbackController.setWaitingCallback(()=>{this.state.updateWaitingState(!0),this.emit("waiting",void 0)}),this.playbackController.setPlayingCallback(()=>{if(this.getState().waiting)this.state.updateWaitingState(!1),this.emit("playing",void 0)}),this.playbackController.setRendererChangeCallback((O)=>{this.state.updateRendererType(O),this.emit("rendererchange",O)}),this.playbackController.setRendererFallbackCallback((O,$)=>{this.emit("rendererfallback",{from:O,to:$})}),this.playbackController.setRotationChangeCallback((O,$)=>{this.store.updateRotation(O,$),this.emit("rotationchange",{rotation:O,displaySize:$})}),this.state.subscribe((O)=>{this.emit("statechange",O)})}async load(O,$={}){this.checkDisposed();let K=this.getState();if(K.playlist.length===0||$.replacePlaylist){await this.playlistManager.loadPlaylist([{mediaSource:O}],{autoplay:$.autoplay??this.options.autoplay,startTime:$.startTime});return}else if(K.currentPlaylistIndex!==null&&K.playlist.length>0){let j=K.currentPlaylistIndex,V={...K.playlist[j],mediaSource:O,savedPosition:0,duration:null},J=[...K.playlist];J[j]=V,this.store.updatePlaylist(J,j),this.emitter.emit("playlistchange",{playlist:J}),await this.core.load(O,{startTime:$.startTime??0,autoplay:$.autoplay??this.options.autoplay});return}await this.core.load(O,{autoplay:$.autoplay??this.options.autoplay,startTime:$.startTime})}async play(){return this.checkDisposed(),this.core.play()}pause(){this.checkDisposed(),this.core.pause()}async seek(O,$={}){return this.checkDisposed(),this.core.seek(O)}async stop(){return this.checkDisposed(),this.core.stop()}get currentTime(){return this.playbackController.getCurrentTime()}set currentTime(O){this.seek(O)}get duration(){return this.state.getState().duration}get volume(){return this.playbackController.getVolume()}set volume(O){this.checkDisposed();let $=Math.max(0,Math.min(1,O));this.playbackController.setVolume($),this.state.updateVolume($,this.muted),this.emit("volumechange",{volume:$,muted:this.muted})}get muted(){return this.playbackController.isMuted()}set muted(O){this.checkDisposed(),this.playbackController.setMuted(O),this.state.updateVolume(this.volume,O),this.emit("volumechange",{volume:this.volume,muted:O})}get playbackRate(){return this.playbackController.getPlaybackRate()}set playbackRate(O){this.checkDisposed();let $=Math.max(0.25,Math.min(4,O));this.playbackController.setPlaybackRate($),this.state.updatePlaybackRate($),this.emit("ratechange",{playbackRate:$})}get paused(){return!this.playbackController.isPlaying()}get ended(){return this.state.getState().ended}get seeking(){return this.state.getState().seeking}get waiting(){return this.state.getState().waiting}get rotation(){return this.playbackController.getRotation()}set rotation(O){this.checkDisposed(),this.playbackController.setRotation(O)}get displaySize(){return this.playbackController.getDisplaySize()}getVideoTracks(){return this.trackManager.getVideoTracks()}getAudioTracks(){return this.trackManager.getAudioTracks()}getSubtitleTracks(){return this.trackManager.getSubtitleTracks()}async selectVideoTrack(O){this.checkDisposed(),await this.trackSwitcher.selectVideoTrack(this.trackManager,O)}async selectAudioTrack(O){this.checkDisposed(),await this.trackSwitcher.selectAudioTrack(this.trackManager,O)}selectSubtitleTrack(O){if(this.checkDisposed(),!this.trackManager.selectSubtitleTrack(O))throw Error(`Invalid subtitle track ID: ${O}`)}registerSubtitleTracks(O,$){this.trackManager.registerSubtitleTracks(O,$),this.state.updateTracks(void 0,void 0,this.trackManager.getSubtitleTracks());let K=this.state.getState().mediaInfo;if(K)this.state.updateMediaInfo({...K,hasSubtitles:this.trackManager.hasSubtitles()})}unregisterSubtitleTracks(O){this.trackManager.unregisterSubtitleTracks(O),this.state.updateTracks(void 0,void 0,this.trackManager.getSubtitleTracks());let $=this.state.getState().mediaInfo;if($)this.state.updateMediaInfo({...$,hasSubtitles:this.trackManager.hasSubtitles()})}async getSubtitleTrackResource(O){return this.trackManager.getSubtitleTrackResource(O)}async screenshot(O={}){return this.checkDisposed(),this.playbackController.screenshot(O)}async setRenderTarget(O){this.checkDisposed(),await this.playbackController.setCanvas(O)}getRenderTarget(){return this.playbackController.getCanvas()}refreshOverlays(){this.playbackController.refreshOverlays()}async loadPlaylist(O,$){this.checkDisposed(),await this.playlistManager.loadPlaylist(O,$)}addToPlaylist(O,$){this.checkDisposed(),this.playlistManager.addToPlaylist(O,$)}async removeFromPlaylist(O){this.checkDisposed(),await this.playlistManager.removeFromPlaylist(O)}clearPlaylist(){this.checkDisposed(),this.playlistManager.clearPlaylist()}async next(){this.checkDisposed(),await this.playlistManager.next()}async prev(){this.checkDisposed(),await this.playlistManager.prev()}async jumpTo(O){this.checkDisposed(),await this.playlistManager.jumpTo(O)}get playlist(){return this.playlistManager.playlist}get playlistIndex(){return this.playlistManager.currentIndex}get nowPlaying(){return this.playlistManager.currentItem}get playlistMode(){return this.playlistManager.mode}set playlistMode(O){this.checkDisposed(),this.playlistManager.setMode(O)}getRendererType(){return this.playbackController.getRendererType()}async switchRenderer(O){this.checkDisposed(),await this.playbackController.switchRenderer(O)}updateCanvasDimensions(){this.checkDisposed(),this.playbackController.updateCanvasDimensions()}static getSupportedRenderers(){return H.getSupportedRenderers()}getState(){return this.state.getState()}subscribe(O){return{unsubscribe:this.state.subscribe(O)}}on(O,$){return this.emitter.on(O,$)}once(O,$){return this.emitter.once(O,$)}off(O,$){this.emitter.off(O,$)}async use(O){if(this.checkDisposed(),await this.pluginManager.install(O),O.hooks?.audio)this.playbackController.rebuildAudioGraph()}async unuse(O){this.checkDisposed(),await this.pluginManager.uninstall(O),this.playbackController.rebuildAudioGraph()}emit(O,$){let K=this.pluginManager.executeBeforeEvent(O,$);if(K?.cancel)return;let j=K?.data??$;this.emitter.emit(O,j),this.pluginManager.executeAfterEvent(O,j)}checkDisposed(){if(this.disposed)throw Error("Player has been disposed")}dispose(){if(this.disposed)return;this.disposed=!0,this.pluginManager.dispose(),this.playbackController.dispose(),this.trackManager.dispose(),this.playlistManager?.dispose(),this.sourceManager.dispose(),this.state.reset(),this.emitter.removeAllListeners()}destroy(){this.dispose(),this.playbackController.destroy()}}var oO={fromUrl(O,$={}){return{mediaSource:O,title:$.title,poster:$.poster}},fromFile(O,$={}){return{mediaSource:O,title:$.title||O.name,poster:$.poster}},fromBlob(O,$={}){return{mediaSource:O,title:$.title,poster:$.poster}},fromBuffer(O,$={}){return{mediaSource:O,title:$.title,poster:$.poster}},fromUint8Array(O,$={}){return{mediaSource:O,title:$.title,poster:$.poster}},fromStream(O,$={}){return{mediaSource:O,title:$.title,poster:$.poster}}};var zO;((L)=>{L.MEDIA_NOT_SUPPORTED="MEDIA_NOT_SUPPORTED";L.MEDIA_LOAD_FAILED="MEDIA_LOAD_FAILED";L.DECODE_ERROR="DECODE_ERROR";L.NETWORK_ERROR="NETWORK_ERROR";L.PERMISSION_DENIED="PERMISSION_DENIED";L.PLAYBACK_ERROR="PLAYBACK_ERROR";L.TRACK_NOT_FOUND="TRACK_NOT_FOUND";L.INVALID_STATE="INVALID_STATE";L.UNKNOWN_ERROR="UNKNOWN_ERROR"})(zO||={});class E extends Error{code;details;constructor(O,$,K){super($);this.name="MediaFoxError",this.code=O,this.details=K}static mediaNotSupported(O="Media format not supported",$){return new E("MEDIA_NOT_SUPPORTED",O,$)}static mediaLoadFailed(O="Failed to load media",$){return new E("MEDIA_LOAD_FAILED",O,$)}static decodeError(O="Failed to decode media",$){return new E("DECODE_ERROR",O,$)}static networkError(O="Network error occurred",$){return new E("NETWORK_ERROR",O,$)}static permissionDenied(O="Permission denied",$){return new E("PERMISSION_DENIED",O,$)}static playbackError(O="Playback error occurred",$){return new E("PLAYBACK_ERROR",O,$)}static trackNotFound(O="Track not found",$){return new E("TRACK_NOT_FOUND",O,$)}static invalidState(O="Invalid player state",$){return new E("INVALID_STATE",O,$)}static unknownError(O="Unknown error occurred",$){return new E("UNKNOWN_ERROR",O,$)}}function dO(O,$){if(O instanceof E)return O;if(O instanceof Error)return new E("UNKNOWN_ERROR",`${$}: ${O.message}`,{originalError:O});return new E("UNKNOWN_ERROR",`${$}: ${String(O)}`,{originalError:O})}function nO(O,$=!1){let K=Math.abs(O),j=Math.floor(K/3600),Q=Math.floor(K%3600/60),V=Math.floor(K%60),J=Math.floor(K%1*1000),U="";if(O<0)U="-";if(j>0)U+=`${j}:${Q.toString().padStart(2,"0")}:${V.toString().padStart(2,"0")}`;else U+=`${Q}:${V.toString().padStart(2,"0")}`;if($)U+=`.${J.toString().padStart(3,"0")}`;return U}function sO(O){let $=O.trim().split(":").map(Number);if($.some(Number.isNaN))throw Error("Invalid time string");let K=0;if($.length===3)K=$[0]*3600+$[1]*60+$[2];else if($.length===2)K=$[0]*60+$[1];else if($.length===1)K=$[0];else throw Error("Invalid time format");return K}function iO(O,$){return Math.floor(O*$)}function aO(O,$){return O/$}function rO(O,$,K){return Math.max($,Math.min(K,O))}function tO(O,$){return O.start<$.end&&$.start<O.end}function eO(O){if(O.length===0)return[];let $=[...O].sort((j,Q)=>j.start-Q.start),K=[$[0]];for(let j=1;j<$.length;j++){let Q=K[K.length-1],V=$[j];if(V.start<=Q.end)Q.end=Math.max(Q.end,V.end);else K.push(V)}return K}function O$(O){return O.reduce(($,K)=>$+(K.end-K.start),0)}function $$(O,$){for(let K of O)if($>=K.start&&$<K.end)return K;return null}var NK="0.1.0",IK=d;export{dO as wrapError,O$ as totalBufferedDuration,iO as timeToFrame,tO as timeRangesOverlap,sO as parseTime,eO as mergeTimeRanges,aO as frameToTime,nO as formatTime,$$ as findBufferedRange,IK as default,rO as clamp,v as VideoRenderer,NK as VERSION,o as TrackManager,c as Store,x as SourcePool,u as SourceManager,oO as Source,H as RendererFactory,g as PlaybackController,E as MediaFoxError,d as MediaFox,I as EventEmitter,zO as ErrorCode,a as Compositor,p as AudioManager};
40
+ `;constructor(O){this.canvas=O.canvas,this.powerPreference=O.powerPreference||"high-performance",this.rotation=O.rotation??0,this.initialize().catch(($)=>{console.error("WebGPU initialization failed:",$)})}async initialize(){try{let O=navigator;if(!O.gpu)return console.log("WebGPU not available in navigator"),!1;let $=await O.gpu.requestAdapter({powerPreference:this.powerPreference});if(!$)return console.log("WebGPU adapter not available"),!1;if(this.device=await $.requestDevice(),!this.device)return console.log("WebGPU device not available"),!1;if("getContext"in this.canvas)this.context=this.canvas.getContext("webgpu");if(!this.context)return console.log("WebGPU context not available on canvas"),!1;let K=O.gpu.getPreferredCanvasFormat();return this.context.configure({device:this.device,format:K,usage:GPUTextureUsage.RENDER_ATTACHMENT,alphaMode:"opaque"}),await this.createRenderPipeline(),this.createVertexBuffer(),this.isInitialized=!0,console.log("WebGPU renderer initialized successfully"),!0}catch(O){return console.error("WebGPU initialization error:",O),!1}}async createRenderPipeline(){if(!this.device)return;let O=navigator;if(!O.gpu)return;let $=this.device.createShaderModule({code:this.vertexShaderSource}),K=this.device.createShaderModule({code:this.fragmentShaderSource});this.pipeline=this.device.createRenderPipeline({layout:"auto",vertex:{module:$,entryPoint:"vs_main",buffers:[{arrayStride:16,attributes:[{shaderLocation:0,offset:0,format:"float32x2"},{shaderLocation:1,offset:8,format:"float32x2"}]}]},fragment:{module:K,entryPoint:"fs_main",targets:[{format:O.gpu.getPreferredCanvasFormat()}]},primitive:{topology:"triangle-strip"}})}createVertexBuffer(){if(!this.device)return;this.vertexBuffer=this.device.createBuffer({size:64,usage:GPUBufferUsage.VERTEX|GPUBufferUsage.COPY_DST})}createTexture(O,$){if(!this.device)return;if(this.texture)this.texture.destroy();if(this.texture=this.device.createTexture({size:{width:O,height:$},format:"rgba8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT}),!this.sampler)this.sampler=this.device.createSampler({magFilter:"linear",minFilter:"linear",addressModeU:"clamp-to-edge",addressModeV:"clamp-to-edge"});this.createBindGroup()}createBindGroup(){if(!this.device||!this.texture||!this.sampler||!this.pipeline)return;this.bindGroup=this.device.createBindGroup({layout:this.pipeline.getBindGroupLayout(0),entries:[{binding:0,resource:this.sampler},{binding:1,resource:this.texture.createView()}]})}isReady(){return this.isInitialized&&this.device!==null&&this.context!==null&&this.pipeline!==null}render(O){if(!this.isReady()||!this.device||!this.context||!this.pipeline)return!1;try{let{width:$,height:K}=O;if($===0||K===0)return console.warn(`WebGPU: Source canvas has zero dimensions (${$}x${K})`),!1;let j=this.canvas.width,Q=this.canvas.height;if(j===0||Q===0)return console.warn(`WebGPU: Output canvas has zero dimensions (${j}x${Q})`),!1;if($!==this.textureWidth||K!==this.textureHeight)this.createTexture($,K),this.textureWidth=$,this.textureHeight=K;if(!this.texture)return!1;try{this.device.queue.copyExternalImageToTexture({source:O},{texture:this.texture},{width:$,height:K})}catch{let n=O.getContext("2d");if(!n)return!1;if(!("getImageData"in n))return!1;let XO=n.getImageData(0,0,$,K),YO=new Uint8Array(XO.data.buffer);this.device.queue.writeTexture({texture:this.texture,origin:{x:0,y:0,z:0}},YO,{bytesPerRow:$*4,rowsPerImage:K},{width:$,height:K,depthOrArrayLayers:1})}let V=this.device.createCommandEncoder(),J=this.context.getCurrentTexture().createView(),U=V.beginRenderPass({colorAttachments:[{view:J,clearValue:{r:0,g:0,b:0,a:1},loadOp:"clear",storeOp:"store"}]});if(U.setPipeline(this.pipeline),this.bindGroup)U.setBindGroup(0,this.bindGroup);let G=this.rotation===90||this.rotation===270,Z=G?this.textureHeight:this.textureWidth,L=G?this.textureWidth:this.textureHeight,z=Math.min(j/Z,Q/L),Y=Math.round(Z*z),A=Math.round(L*z),N=Math.round((j-Y)/2),C=Math.round((Q-A)/2),_=N/j*2-1,E=(N+Y)/j*2-1,W=1-C/Q*2,R=1-(C+A)/Q*2,F=(_+E)/2,b=(W+R)/2,w=(E-_)/2,S=(W-R)/2,q=this.rotation*Math.PI/180,X=Math.cos(q),P=Math.sin(q),B=G?S:w,T=G?w:S,D=this.quadArray;if(D[0]=-B*X- -T*P+F,D[1]=-B*P+-T*X+b,D[2]=0,D[3]=1,D[4]=B*X- -T*P+F,D[5]=B*P+-T*X+b,D[6]=1,D[7]=1,D[8]=-B*X-T*P+F,D[9]=-B*P+T*X+b,D[10]=0,D[11]=0,D[12]=B*X-T*P+F,D[13]=B*P+T*X+b,D[14]=1,D[15]=0,this.vertexBuffer)this.device.queue.writeBuffer(this.vertexBuffer,0,D),U.setVertexBuffer(0,this.vertexBuffer);return U.draw(4,1,0,0),U.end(),this.device.queue.submit([V.finish()]),!0}catch{return!1}}clear(){if(!this.isReady()||!this.device||!this.context)return;try{let O=this.device.createCommandEncoder(),$=this.context.getCurrentTexture().createView();O.beginRenderPass({colorAttachments:[{view:$,clearValue:{r:0,g:0,b:0,a:1},loadOp:"clear",storeOp:"store"}]}).end(),this.device.queue.submit([O.finish()])}catch{}}setRotation(O){this.rotation=O}getRotation(){return this.rotation}dispose(){try{if(this.texture)this.texture.destroy(),this.texture=null;if(this.vertexBuffer)this.vertexBuffer.destroy(),this.vertexBuffer=null;this.device=null,this.context=null,this.pipeline=null,this.sampler=null,this.bindGroup=null,this.isInitialized=!1}catch{}}}class H{canvas;powerPreference;constructor(O){this.canvas=O.canvas,this.powerPreference=O.powerPreference||"high-performance"}async createRenderer(O){try{switch(O){case"webgpu":return await this.createWebGPURenderer();case"webgl":return this.createWebGLRenderer();case"canvas2d":return this.createCanvas2DRenderer();default:return null}}catch{return null}}async createRendererWithFallback(O){let $=[O];if(O!=="webgl")$.push("webgl");if(O!=="canvas2d")$.push("canvas2d");for(let j of $){let Q=await this.createRenderer(j);if(Q?.isReady())return{renderer:Q,actualType:j};if(Q)Q.dispose()}return{renderer:this.createCanvas2DRenderer(),actualType:"canvas2d"}}async createWebGPURenderer(){if(!navigator.gpu)return null;if(!("getContext"in this.canvas))return console.log("WebGPU requires HTMLCanvasElement, not OffscreenCanvas"),null;let $=new t({canvas:this.canvas,powerPreference:this.powerPreference}),K=1000,j=performance.now();if(await(async()=>{while(!$.isReady()){if(performance.now()-j>K)return console.log("WebGPU renderer initialization timed out"),!1;if("requestIdleCallback"in window)await new Promise((J)=>requestIdleCallback(()=>J(void 0)));else await new Promise((J)=>requestAnimationFrame(()=>J(void 0)))}return!0})())return console.log("WebGPU renderer initialized successfully"),$;return $.isReady()?$:null}createWebGLRenderer(){try{let O=new r({canvas:this.canvas,powerPreference:this.powerPreference,preserveDrawingBuffer:!1,antialias:!1,alpha:!1});return O.isReady()?O:null}catch{return null}}createCanvas2DRenderer(){return new y({canvas:this.canvas})}static getSupportedRenderers(){let O=[];if(navigator.gpu)O.push("webgpu");try{let K=document.createElement("canvas");if(K.getContext("webgl")||K.getContext("experimental-webgl"))O.push("webgl")}catch{}return O.push("canvas2d"),O}static getRendererDisplayName(O){switch(O){case"canvas2d":return"Canvas 2D";case"webgl":return"WebGL";case"webgpu":return"WebGPU";default:return"Unknown"}}static isRendererSupported(O){if(O==="canvas2d")return!0;return H.getSupportedRenderers().includes(O)}}var e=new WeakMap;function LO(O,$){e.set(O,$)}function FO(O){let $=e.get(O);if($)e.delete(O);return $}class v{canvas=null;seekDebounceTimer=null;pendingSeekTime=null;canvasSink=null;sampleSink=null;options;frameIterator=null;currentFrame=null;nextFrame=null;disposed=!1;renderingId=0;currentSeekId=0;renderer=null;rendererType="canvas2d";onRendererChange;onRendererFallback;onRotationChange;initPromise=null;resizeObserver=null;lastObservedWidth=0;lastObservedHeight=0;videoAspectRatio=null;debug=!1;pluginManager=null;overlayCanvas=null;overlayCtx=null;lastOverlayTime=0;rotation=0;sourceWidth=0;sourceHeight=0;updateFrameResult={frameUpdated:!1,isStarving:!1};constructor(O={}){if(this.options={poolSize:O.poolSize??2,rendererType:O.rendererType??"webgpu",...O},this.rendererType=this.options.rendererType??"webgpu",this.debug=O.debug??!1,this.initPromise=null,O.canvas){if(this.canvas=O.canvas,this.options.width!==void 0)O.canvas.width=this.options.width;if(this.options.height!==void 0)O.canvas.height=this.options.height;this.initPromise=this.initializeRenderer(O.canvas,this.rendererType).catch(($)=>{if(this.debug)console.error("Failed to initialize renderer:",$)}),this.setupResizeObserver(O.canvas)}}setupResizeObserver(O){if(!("getBoundingClientRect"in O)||typeof ResizeObserver>"u")return;if(this.options.width!==void 0||this.options.height!==void 0)return;this.cleanupResizeObserver();let $=O;this.resizeObserver=new ResizeObserver((K)=>{if(this.disposed||!this.resizeObserver)return;for(let j of K){let{width:Q,height:V}=this.getCanvasDimensionsFromEntry(j,$);if(Q!==this.lastObservedWidth||V!==this.lastObservedHeight){if(this.lastObservedWidth=Q,this.lastObservedHeight=V,$.width!==Q||$.height!==V){if($.width=Q,$.height=V,this.updateCanvasAspectRatio(),this.currentFrame&&this.renderer&&this.renderer.isReady())this.renderFrame(this.currentFrame)}}}});try{this.resizeObserver.observe($,{box:"device-pixel-content-box"})}catch{try{this.resizeObserver.observe($,{box:"content-box"})}catch{this.resizeObserver.observe($)}}requestAnimationFrame(()=>{if(this.disposed||!this.resizeObserver)return;let{width:K,height:j}=this.getCanvasDimensionsFromCanvas($);if(this.lastObservedWidth=K,this.lastObservedHeight=j,$.width!==K||$.height!==j){if($.width=K,$.height=j,this.updateCanvasAspectRatio(),this.currentFrame&&this.renderer&&this.renderer.isReady())this.renderFrame(this.currentFrame)}})}getCanvasDimensionsFromEntry(O,$){let K=0,j=0,Q=window.devicePixelRatio||1;if(O.devicePixelContentBoxSize?.length)K=O.devicePixelContentBoxSize[0].inlineSize,j=O.devicePixelContentBoxSize[0].blockSize;else if(O.contentBoxSize?.length)K=Math.round(O.contentBoxSize[0].inlineSize*Q),j=Math.round(O.contentBoxSize[0].blockSize*Q);else if(O.contentRect)K=Math.round(O.contentRect.width*Q),j=Math.round(O.contentRect.height*Q);if(K===0||j===0)return this.getCanvasDimensionsFromCanvas($);return{width:Math.max(1,K),height:Math.max(1,j)}}getCanvasDimensionsFromCanvas(O){let $=0,K=0,j=window.devicePixelRatio||1,Q=O.getBoundingClientRect();if($=Math.round(Q.width*j),K=Math.round(Q.height*j),$===0||K===0)$=Math.round(O.clientWidth*j)||$,K=Math.round(O.clientHeight*j)||K;if($===0||K===0)console.warn("Canvas has zero dimensions after all fallbacks, using 1x1");return{width:Math.max(1,$),height:Math.max(1,K)}}cleanupResizeObserver(){if(this.resizeObserver)this.resizeObserver.disconnect(),this.resizeObserver=null,this.lastObservedWidth=0,this.lastObservedHeight=0}retryUntilCanvasReady(O,$,K=60){let j=0,Q=()=>{if(j++,O.canvas.width>0&&O.canvas.height>0)$();else if(j<K)requestAnimationFrame(Q);else{if(this.debug)console.warn("Canvas dimensions timeout, forcing action");$()}};requestAnimationFrame(Q)}updateCanvasAspectRatio(){if(!this.canvas||!this.videoAspectRatio||!("style"in this.canvas))return;this.canvas.style.aspectRatio=this.videoAspectRatio}updateCanvasBackingBuffer(O){let{width:$,height:K}=this.getCanvasDimensionsFromCanvas(O);if(O.width!==$||O.height!==K)return O.width=$,O.height=K,!0;return!1}async initializeRenderer(O,$){if(this.debug)console.log(`Initializing renderer: ${$}`);let j=await new H({canvas:O}).createRendererWithFallback($);if(this.debug)console.log(`Renderer factory result: ${j.actualType}`);if(!j.renderer.isReady()){if(this.debug)console.warn(`VideoRenderer: Renderer (${j.actualType}) not ready`);throw j.renderer.dispose(),Error(`Failed to initialize renderer: ${j.actualType}`)}if(this.renderer=j.renderer,this.rendererType=j.actualType,this.debug)console.log(`Initialized renderer: ${this.rendererType}`);if(j.actualType!==$){if(this.onRendererFallback)this.onRendererFallback($,j.actualType)}if(this.onRendererChange){if(this.debug)console.log(`Emitting renderer change: ${this.rendererType}`);this.onRendererChange(this.rendererType)}if(this.currentFrame&&this.renderer&&this.renderer.isReady()){if(this.debug)console.log(`Rendering initial frame with ${this.rendererType}`);if(this.currentFrame.canvas.width===0||this.currentFrame.canvas.height===0){if(this.debug)console.log("Initial frame has zero dimensions, scheduling render when ready...");this.retryUntilCanvasReady(this.currentFrame,()=>{if(this.currentFrame&&this.debug)console.log(`Canvas ready (${this.currentFrame.canvas.width}x${this.currentFrame.canvas.height}), rendering initial frame`);if(this.currentFrame)this.renderFrame(this.currentFrame)})}else this.renderFrame(this.currentFrame)}}async setCanvas(O){if(this.cleanupOverlayCanvas(),this.canvas=O,this.renderer)this.renderer.dispose(),this.renderer=null;if(this.options.width!==void 0)O.width=this.options.width;if(this.options.height!==void 0)O.height=this.options.height;this.setupResizeObserver(O);try{await this.initializeRenderer(O,this.rendererType)}catch($){if(this.debug)console.error("Failed to initialize renderer:",$);if(!this.renderer){if(this.renderer=new y({canvas:O}),this.rendererType="canvas2d",this.onRendererChange)this.onRendererChange("canvas2d")}}}async setVideoTrack(O){if(await this.disposeVideoResources(),O.codec===null)throw Error("Unsupported video codec");if(!await O.canDecode())throw Error(`Cannot decode video track with codec: ${O.codec}`);let K=FO(O);if(this.sourceWidth=O.displayWidth,this.sourceHeight=O.displayHeight,!this.videoAspectRatio&&O.displayWidth&&O.displayHeight){let j=(U,G)=>G===0?U:j(G,U%G),Q=j(O.displayWidth,O.displayHeight),V=O.displayWidth/Q,J=O.displayHeight/Q;this.videoAspectRatio=`${V}/${J}`,this.updateCanvasAspectRatio()}if(this.notifyRotationChange(),this.initPromise)try{await this.initPromise}catch(j){if(this.debug)console.error("Renderer initialization failed:",j)}if(!this.renderer){if(this.debug)console.warn("Renderer not ready, creating Canvas2D fallback");if(this.canvas){if(this.renderer=new y({canvas:this.canvas}),this.rendererType="canvas2d",this.onRendererChange)this.onRendererChange("canvas2d")}}if(this.canvas){if(this.options.width!==void 0||this.options.height!==void 0){let j=this.options.width??O.displayWidth,Q=this.options.height??O.displayHeight;if(this.canvas.width!==j||this.canvas.height!==Q)this.canvas.width=j,this.canvas.height=Q,this.updateCanvasAspectRatio()}else if(!this.resizeObserver){if(this.canvas.width===0||this.canvas.height===0)this.canvas.width=O.displayWidth,this.canvas.height=O.displayHeight,this.updateCanvasAspectRatio()}}if(K?.canvasSink)this.canvasSink=K.canvasSink;else this.canvasSink=new SO(O,{rotation:this.options.rotation,poolSize:this.options.poolSize});if(this.sampleSink=new WO(O),this.disposed=!1,K?.firstFrame){if(this.currentFrame=K.firstFrame,this.currentFrame.canvas.width>0&&this.currentFrame.canvas.height>0)this.renderFrame(this.currentFrame);else this.retryUntilCanvasReady(this.currentFrame,()=>{if(this.currentFrame)this.renderFrame(this.currentFrame)},30);this.frameIterator=this.canvasSink.canvases(0),this.frameIterator.next().then(()=>{this.fetchNextFrame()})}else try{await this.seek(0)}catch(j){if(this.debug)console.error("Initial seek failed:",j)}requestAnimationFrame(()=>{if(this.resizeObserver&&this.canvas&&"getBoundingClientRect"in this.canvas)this.updateCanvasBackingBuffer(this.canvas);if(this.currentFrame&&this.renderer&&this.renderer.isReady())this.renderFrame(this.currentFrame)})}async seek(O){if(this.cancelPendingDebouncedSeek(),!this.canvasSink)return;this.renderingId++;let $=this.renderingId;this.currentSeekId++;let K=this.currentSeekId;if(this.frameIterator){try{await this.frameIterator.return()}catch{}this.frameIterator=null}this.currentFrame=null,this.nextFrame=null;try{let j=null,Q=null,V=0.001,J=Math.max(0,O-2),U=this.canvasSink.canvases(J);try{let G=null;for await(let Z of U){if(K!==this.currentSeekId)return;if(Z.timestamp<=O)G=Z;else{Q=Z;break}if(Z.timestamp>O+5)break}j=G}catch{}finally{try{await U.return()}catch{}}if(K!==this.currentSeekId)return;if(!j){let G=this.canvasSink.canvases(O);try{let Z=await G.next();if(K!==this.currentSeekId)return;if(Z.value)j=Z.value}catch{}finally{try{await G.return()}catch{}}}if($!==this.renderingId||this.disposed)return;if(K!==this.currentSeekId)return;if(j){if(this.currentFrame=j,this.nextFrame=Q,j.canvas.width>0&&j.canvas.height>0)this.renderFrame(j);else this.retryUntilCanvasReady(j,()=>this.renderFrame(j),30);let G=this.canvasSink.canvases(j.timestamp);this.frameIterator=G;let Z=null;try{let L=await G.next();if(K!==this.currentSeekId){try{await G.return()}catch{}if(this.frameIterator===G)this.frameIterator=null;return}Z=L.value??null}catch{}if($!==this.renderingId||this.disposed){try{await G.return()}catch{}if(this.frameIterator===G)this.frameIterator=null;return}if(Z&&Z.timestamp>j.timestamp+V&&(!this.nextFrame||Z.timestamp<this.nextFrame.timestamp))this.nextFrame=Z;if(!this.nextFrame)this.fetchNextFrame()}}catch{}}updateFrame(O,$=!1){let K=this.updateFrameResult;if(this.disposed)return K.frameUpdated=!1,K.isStarving=!1,K;if(this.currentFrame&&this.currentFrame.timestamp>O+0.1)return K.frameUpdated=!1,K.isStarving=!1,K;if(!this.nextFrame){if(this.frameIterator)this.fetchNextFrame();return K.frameUpdated=!1,K.isStarving=!0,K}if(this.nextFrame.timestamp<O-1){if(this.pendingSeekTime=O,this.seekDebounceTimer===null&&!$)this.seekDebounceTimer=window.setTimeout(()=>{let Q=this.pendingSeekTime;if(this.seekDebounceTimer=null,this.pendingSeekTime=null,Q!==null&&!this.disposed)this.seek(Q)},100);return K.frameUpdated=!1,K.isStarving=!1,K}let j=0.016;if(this.nextFrame.timestamp<=O+j){if(this.currentFrame=this.nextFrame,this.nextFrame=null,this.renderFrame(this.currentFrame),this.frameIterator)this.fetchNextFrame();return K.frameUpdated=!0,K.isStarving=!1,K}return K.frameUpdated=!1,K.isStarving=!1,K}async fetchNextFrame(O){let $=this.frameIterator;if(!$||this.disposed)return;let K=this.renderingId;try{let j=null,Q=await $.next();if(j=Q.value??null,!j||K!==this.renderingId||this.disposed)return;if(O!==void 0)while(j&&j.timestamp<O-0.1){Q=await $.next();let J=Q.value??null;if(!J||K!==this.renderingId||this.disposed)break;j=J}this.nextFrame=j}catch{}}renderFrame(O){if(this.currentFrame=O,!this.renderer||!this.canvas){if(this.initPromise)this.initPromise.then(()=>{if(this.currentFrame===O&&this.renderer&&this.renderer.isReady()){if(this.debug)console.log("Rendering frame after renderer initialization");this.renderFrameWithPlugins(O)}});return}if(!this.renderer.isReady()){if(this.debug)console.warn(`VideoRenderer: Renderer (${this.rendererType}) not ready, skipping frame`);return}this.renderFrameWithPlugins(O)}renderFrameWithPlugins(O){if(!this.renderer||!this.canvas)return;let $=O.timestamp;if(this.pluginManager){if(this.pluginManager.executeBeforeRender(O,$)?.skip)return}let K=O;if(this.pluginManager)K=this.pluginManager.executeTransformFrame(O);if(!this.renderer.render(K.canvas)){if(this.debug)console.warn(`Failed to render frame with ${this.rendererType} (canvas: ${K.canvas.width}x${K.canvas.height})`);if(K.canvas.width===0||K.canvas.height===0)this.retryUntilCanvasReady(K,()=>{if(this.currentFrame===O&&this.renderer&&this.renderer.isReady()){if(!this.renderer.render(K.canvas)&&this.debug)console.warn("Retry render also failed")}},1);return}if(this.executeOverlays($),this.pluginManager)this.pluginManager.executeAfterRender(this.canvas)}executeOverlays(O){if(!this.pluginManager||!this.canvas)return;this.lastOverlayTime=O;let $={width:this.canvas.width,height:this.canvas.height};if(this.rendererType==="canvas2d"){let K=this.canvas.getContext("2d");if(!K)return;this.pluginManager.executeOverlays(K,O,$)}else{if(this.ensureOverlayCanvas(),!this.overlayCanvas||!this.overlayCtx)return;this.overlayCtx.clearRect(0,0,this.overlayCanvas.width,this.overlayCanvas.height),this.pluginManager.executeOverlays(this.overlayCtx,O,$)}}refreshOverlays(){if(!this.canvas)return;if(this.rendererType==="canvas2d"){if(this.currentFrame&&this.renderer?.isReady())this.renderer.render(this.currentFrame.canvas),this.executeOverlays(this.lastOverlayTime)}else if(this.overlayCanvas&&this.overlayCtx){if(this.overlayCtx.clearRect(0,0,this.overlayCanvas.width,this.overlayCanvas.height),this.pluginManager){let O={width:this.canvas.width,height:this.canvas.height};this.pluginManager.executeOverlays(this.overlayCtx,this.lastOverlayTime,O)}}}ensureOverlayCanvas(){if(!this.canvas||!(this.canvas instanceof HTMLCanvasElement))return;if(!this.overlayCanvas){this.overlayCanvas=document.createElement("canvas"),this.overlayCanvas.style.position="absolute",this.overlayCanvas.style.top="0",this.overlayCanvas.style.left="0",this.overlayCanvas.style.width="100%",this.overlayCanvas.style.height="100%",this.overlayCanvas.style.pointerEvents="none",this.overlayCanvas.style.zIndex="1",this.overlayCtx=this.overlayCanvas.getContext("2d");let O=this.canvas.parentElement;if(O){if(getComputedStyle(O).position==="static")O.style.position="relative";O.insertBefore(this.overlayCanvas,this.canvas.nextSibling)}}if(this.overlayCanvas.width!==this.canvas.width||this.overlayCanvas.height!==this.canvas.height)this.overlayCanvas.width=this.canvas.width,this.overlayCanvas.height=this.canvas.height}cleanupOverlayCanvas(){if(this.overlayCanvas)this.overlayCanvas.remove(),this.overlayCanvas=null,this.overlayCtx=null}async getFrameAt(O){if(!this.canvasSink)return null;return this.canvasSink.getCanvas(O)}async getSampleAt(O){if(!this.sampleSink)return null;return this.sampleSink.getSample(O)}async extractFrames(O,$,K=1){if(!this.canvasSink)return[];let j=[],Q=[];for(let V=O;V<=$;V+=K)Q.push(V);for await(let V of this.canvasSink.canvasesAtTimestamps(Q))if(V)j.push(V);return j}async screenshot(O,$={}){if(!this.canvas)return null;if(O!==void 0&&this.canvasSink){let K=await this.canvasSink.getCanvas(O);if(K)this.renderFrame(K)}if("toBlob"in this.canvas)return new Promise((K)=>{this.canvas.toBlob((j)=>K(j),`image/${$.format??"png"}`,$.quality)});else return this.canvas.convertToBlob({type:`image/${$.format??"png"}`,quality:$.quality})}getCurrentFrame(){return this.currentFrame}getNextFrame(){return this.nextFrame}getRendererType(){return this.rendererType}getCanvas(){return this.canvas}updateCanvasDimensions(){if(!this.canvas||!("getBoundingClientRect"in this.canvas))return;let O=this.canvas;if(this.updateCanvasBackingBuffer(O)&&this.currentFrame&&this.renderer&&this.renderer.isReady())this.renderFrame(this.currentFrame)}async switchRenderer(O){if(!this.canvas)throw Error("Cannot switch renderer: No canvas set");let $=this.rendererType;if(O===$)return;if(this.debug)console.warn(`Switching renderer from ${$} to ${O}. This will recreate the canvas element.`);if(this.canvas instanceof HTMLCanvasElement){let K=this.canvas,j=K.parentElement;if(!j)throw Error("Cannot switch renderer: Canvas has no parent element");let Q=document.createElement("canvas");if(Q.width=K.width,Q.height=K.height,Q.className=K.className,Q.id=K.id,Q.style.cssText=K.style.cssText,Array.from(K.attributes).forEach((V)=>{if(V.name!=="id"&&V.name!=="class"&&V.name!=="style")Q.setAttribute(V.name,V.value)}),this.renderer)this.renderer.dispose(),this.renderer=null;j.replaceChild(Q,K),this.canvas=Q;try{await this.initializeRenderer(Q,O)}catch(V){if(this.debug)console.error(`Failed to switch to ${O}:`,V);if(!this.renderer){if(this.renderer=new y({canvas:Q}),this.rendererType="canvas2d",this.onRendererChange)this.onRendererChange("canvas2d")}}}else{if(this.debug)console.warn("Runtime switching for OffscreenCanvas may not work if context is already set");if(this.renderer)this.renderer.dispose(),this.renderer=null;try{await this.initializeRenderer(this.canvas,O)}catch(K){if(this.debug)console.error(`Failed to switch to ${O}:`,K);if(!this.renderer){if(this.renderer=new y({canvas:this.canvas}),this.rendererType="canvas2d",this.onRendererChange)this.onRendererChange("canvas2d")}}}if(this.currentFrame&&this.renderer&&this.renderer.isReady()){if(this.debug)console.log(`Re-rendering after switch to ${this.rendererType}`);queueMicrotask(()=>{if(this.currentFrame&&this.renderer&&this.renderer.isReady())this.renderFrame(this.currentFrame)})}}setRendererChangeCallback(O){if(this.onRendererChange=O,this.renderer&&this.rendererType){if(this.debug)console.log(`Renderer already initialized as ${this.rendererType}, emitting change event`);O(this.rendererType)}}setRendererFallbackCallback(O){this.onRendererFallback=O}setRotationChangeCallback(O){this.onRotationChange=O}setRotation(O){if(this.rotation===O)return;if(this.rotation=O,this.renderer)this.renderer.setRotation(O);if(this.notifyRotationChange(),this.currentFrame&&this.renderer&&this.renderer.isReady())this.renderFrame(this.currentFrame)}getRotation(){return this.rotation}getDisplaySize(){let O=this.rotation===90||this.rotation===270;return{width:O?this.sourceHeight:this.sourceWidth,height:O?this.sourceWidth:this.sourceHeight}}notifyRotationChange(){if(this.onRotationChange&&this.sourceWidth>0&&this.sourceHeight>0)this.onRotationChange(this.rotation,this.getDisplaySize())}setPluginManager(O){this.pluginManager=O}static getSupportedRenderers(){return H.getSupportedRenderers()}async clearIterators(){if(this.renderingId++,this.cancelPendingDebouncedSeek(),this.frameIterator){try{await this.frameIterator.return()}catch{}this.frameIterator=null}this.currentFrame=null,this.nextFrame=null}async disposeVideoResources(){if(this.disposed=!0,this.renderingId++,this.cancelPendingDebouncedSeek(),this.frameIterator){try{await this.frameIterator.return()}catch{}this.frameIterator=null}this.currentFrame=null,this.nextFrame=null,this.canvasSink=null,this.sampleSink=null,this.videoAspectRatio=null}dispose(){if(this.disposed=!0,this.renderingId++,this.cancelPendingDebouncedSeek(),this.frameIterator)this.frameIterator.return(),this.frameIterator=null;if(this.renderer)this.renderer.dispose(),this.renderer=null;this.cleanupResizeObserver(),this.cleanupOverlayCanvas(),this.currentFrame=null,this.nextFrame=null,this.canvasSink=null,this.sampleSink=null,this.onRendererChange=void 0,this.onRendererFallback=void 0}cancelPendingDebouncedSeek(){if(this.seekDebounceTimer!==null)clearTimeout(this.seekDebounceTimer);this.seekDebounceTimer=null,this.pendingSeekTime=null}}var f=2,h="[MediaFox]";function HO(O){f=O}function bO(O,...$){if(f<=0)console.debug(`${h} ${O}`,...$)}function wO(O,...$){if(f<=1)console.info(`${h} ${O}`,...$)}function TO(O,...$){if(f<=2)console.warn(`${h} ${O}`,...$)}function yO(O,...$){if(f<=3)console.error(`${h} ${O}`,...$)}var k={setLevel:HO,debug:bO,info:wO,warn:TO,error:yO};class OO{deps;constructor(O){this.deps=O}async load(O,$={}){try{let K=await this.deps.pluginManager.executeBeforeLoad(O);if(K?.cancel)return;if(K?.data!==void 0)O=K.data;await this.deps.playbackController.reset(),this.deps.sourceManager.disposeCurrent();let j=this.deps.state.getState();if(!$.replacePlaylist)this.deps.state.setState({...j,state:"loading",currentTime:$.startTime??0,playing:!1,paused:!0,ended:!1,seeking:!1,error:null,mediaInfo:null,videoTracks:[],audioTracks:[],subtitleTracks:[],selectedVideoTrack:null,selectedAudioTrack:null,selectedSubtitleTrack:null,buffered:[],canPlay:!1,canPlayThrough:!1});else this.deps.state.reset(),this.deps.state.updateLoadingState();this.deps.emit("loadstart",void 0);let Q=$.playlistItemId?this.deps.sourceManager.promoteQueuedSource($.playlistItemId):null;if(!Q)Q=await this.deps.sourceManager.createSource(O);let V=Q.input;if(!V)throw Error("Failed to create input from source");await this.deps.trackManager.initialize(V);let[J,U,G,Z]=await Promise.all([V.computeDuration(),V.getFormat(),V.getMimeType(),V.getMetadataTags()]),L={duration:J,format:U.name,mimeType:G,metadata:Z,hasVideo:this.deps.trackManager.hasVideo(),hasAudio:this.deps.trackManager.hasAudio(),hasSubtitles:this.deps.trackManager.hasSubtitles()};this.deps.state.updateDuration(J),this.deps.state.updateMediaInfo(L),this.deps.state.updateTracks(this.deps.trackManager.getVideoTracks(),this.deps.trackManager.getAudioTracks(),this.deps.trackManager.getSubtitleTracks()),this.deps.playbackController.setDuration(J);let z=Q.prefetchedData,Y=z?.videoTrack??this.deps.trackManager.getPrimaryVideoTrack(),A=z?.audioTrack??this.deps.trackManager.getPrimaryAudioTrack();if(Y&&z?.canvasSink&&z?.firstFrame)LO(Y,{canvasSink:z.canvasSink,firstFrame:z.firstFrame});let N="",C=!1,_=!1;if(Y||A){let E=await this.deps.trackSwitcher.setupInitialTracks(Y,A);N+=E.warningMessage,C=E.videoSupported,_=E.audioSupported}if(!C&&!_){if(!N)N="No audio or video track found.";throw Error(N)}if(N&&(C||_))this.deps.emit("warning",{type:"codec-warning",message:N.trim(),error:void 0});if(this.deps.state.updateReadyState(!0,!0),this.deps.emit("loadedmetadata",L),this.deps.emit("loadeddata",void 0),this.deps.emit("canplay",void 0),this.deps.emit("canplaythrough",void 0),this.updateCurrentPlaylistItemDuration(J),await this.deps.pluginManager.executeAfterLoad(L),$.autoplay)await this.play();if($.startTime!==void 0)await this.seek($.startTime)}catch(K){throw this.handleError(K),K}}async play(){try{if(this.deps.state.getState().state==="idle")throw Error("No media loaded");if((await this.deps.pluginManager.executeBeforePlay())?.cancel)return;await this.deps.playbackController.play(),this.deps.state.updatePlaybackState(!0),this.deps.emit("play",void 0),this.deps.emit("playing",void 0),this.deps.pluginManager.executeAfterPlay()}catch(O){throw this.handleError(O),O}}async pause(){if((await this.deps.pluginManager.executeBeforePause())?.cancel)return;this.deps.playbackController.pause(),this.deps.state.updatePlaybackState(!1),this.deps.emit("pause",void 0),this.deps.pluginManager.executeAfterPause()}async seek(O){try{if(this.deps.state.getState().state==="idle")throw Error("No media loaded");let K=await this.deps.pluginManager.executeBeforeSeek(O);if(K?.cancel)return;if(K?.data!==void 0)O=K.data;this.deps.state.updateSeekingState(!0),this.deps.emit("seeking",{currentTime:O}),await this.deps.playbackController.seek(O),this.deps.state.updateSeekingState(!1),this.deps.state.updateTime(this.deps.playbackController.getCurrentTime()),this.deps.emit("seeked",{currentTime:this.deps.playbackController.getCurrentTime()}),this.deps.pluginManager.executeAfterSeek(this.deps.playbackController.getCurrentTime())}catch($){throw this.deps.state.updateSeekingState(!1),this.handleError($),$}}async stop(){try{if((await this.deps.pluginManager.executeBeforeStop())?.cancel)return;await this.pause(),await this.seek(0),this.deps.pluginManager.executeAfterStop()}catch(O){throw this.handleError(O),O}}handleError(O){if(this.deps.pluginManager.executeOnError(O))return;this.deps.state.updateError(O),this.deps.emit("error",O),k.error("Player error:",O)}updateCurrentPlaylistItemDuration(O){let $=this.deps.state.getState(),K=$.currentPlaylistIndex;if(K!==null&&$.playlist.length>0){let j=[...$.playlist],Q=j[K];if(Q)j[K]={...Q,duration:O},this.deps.state.updatePlaylist(j,K)}}}class $O{store;constructor(O){this.store=O}getState(){return this.store.getState()}subscribe(O){return this.store.subscribe(O)}setState(O){this.store.setState(O)}reset(){this.store.reset()}applyInitial(O,$,K){this.store.setState({volume:O,muted:$,playbackRate:K})}updateLoadingState(){this.store.updateLoadingState()}updateReadyState(O,$){this.store.updateReadyState(O,$)}updatePlaybackState(O){this.store.updatePlaybackState(O)}updateSeekingState(O){this.store.updateSeekingState(O)}updateWaitingState(O){this.store.updateWaitingState(O)}updateEndedState(O){this.store.updateEndedState(O)}updateTime(O){this.store.updateTime(O)}updateDuration(O){this.store.updateDuration(O)}updateVolume(O,$){this.store.updateVolume(O,$)}updatePlaybackRate(O){this.store.updatePlaybackRate(O)}updateMediaInfo(O){this.store.updateMediaInfo(O)}updateTracks(O,$,K){this.store.updateTracks(O,$,K)}updateSelectedTracks(O,$){this.store.updateSelectedTracks(O,$)}updateError(O){this.store.updateError(O)}updateRendererType(O){this.store.updateRendererType(O)}updatePlaylist(O,$=null){this.store.updatePlaylist(O,$)}}class KO{chains=new Map;async run(O,$){let K=this.chains.get(O)??Promise.resolve(),j,Q=new Promise((V)=>{j=V});this.chains.set(O,K.then(()=>Q));try{return await K,await $()}finally{j?.()}}}class jO{deps;locks=new KO;constructor(O){this.deps=O}async setupInitialTracks(O,$){let K=!1,j=!1,Q="";if(O)try{if(K=await this.locks.run("video",async()=>{if(O.codec!==null&&await O.canDecode())return await this.deps.playbackController.trySetVideoTrack(O);return!1}),!K)Q+="Unsupported video codec. "}catch(V){Q+="Failed to set up video track. ",k.warn("Video track error:",V)}if($)try{if(j=await this.locks.run("audio",async()=>{if($.codec!==null&&await $.canDecode())return await this.deps.playbackController.trySetAudioTrack($);return!1}),!j)Q+="Unsupported audio codec. "}catch(V){Q+="Failed to set up audio track. ",k.warn("Audio track error:",V)}if(!K&&!j&&!Q)Q="No audio or video track found.";return{videoSupported:K,audioSupported:j,warningMessage:Q}}async selectVideoTrack(O,$){if(!O.selectVideoTrack($))throw Error(`Invalid video track ID: ${$}`);let K=O.getSelectedVideoTrack();if(!K){await this.deps.playbackController.setVideoTrack(null);return}if(!await this.locks.run("video",async()=>{if(K.codec!==null&&await K.canDecode())return await this.deps.playbackController.trySetVideoTrack(K);return!1}))this.deps.emit("warning",{type:"video-codec-unsupported",message:"Video codec not supported.",error:void 0}),await this.deps.playbackController.setVideoTrack(null)}async selectAudioTrack(O,$){if(!O.selectAudioTrack($))throw Error(`Invalid audio track ID: ${$}`);let K=O.getSelectedAudioTrack();if(!K){await this.deps.playbackController.setAudioTrack(null);return}if(!await this.locks.run("audio",async()=>{if(K.codec!==null&&await K.canDecode())return await this.deps.playbackController.trySetAudioTrack(K);return!1}))this.deps.emit("warning",{type:"audio-codec-unsupported",message:"Audio codec not supported. Continuing without audio.",error:void 0}),await this.deps.playbackController.setAudioTrack(null)}}import{AudioBufferSink as xO,AudioSampleSink as IO}from"mediabunny";class p{audioContext;gainNode=null;outputNode=null;bufferSink=null;sampleSink=null;bufferIterator=null;queuedNodes=new Set;startContextTime=0;startMediaTime=0;pauseTime=0;playing=!1;volume=1;muted=!1;disposed=!1;playbackId=0;playbackRate=1;pluginManager=null;constructor(O={}){if(O.audioContext)this.audioContext=O.audioContext;else{let $=window,K=$.AudioContext||$.webkitAudioContext;this.audioContext=new K}this.volume=O.volume??1,this.muted=O.muted??!1,this.setupAudioGraph()}setupAudioGraph(){if(this.gainNode=this.audioContext.createGain(),this.pluginManager){let O=this.pluginManager.executeOnAudioNode(this.audioContext,this.gainNode);this.outputNode=O}else this.outputNode=this.gainNode;this.outputNode.connect(this.audioContext.destination),this.updateGain()}setPluginManager(O){this.pluginManager=O,this.rebuildAudioGraph()}rebuildAudioGraph(){if(!this.gainNode)return;if(this.outputNode?.disconnect(),this.pluginManager){let O=this.pluginManager.executeOnAudioNode(this.audioContext,this.gainNode);this.outputNode=O}else this.outputNode=this.gainNode;this.outputNode.connect(this.audioContext.destination)}async setAudioTrack(O){if(this.dispose(),O.codec===null)throw Error("Unsupported audio codec");if(!await O.canDecode())throw Error(`Cannot decode audio track with codec: ${O.codec}`);this.bufferSink=new xO(O),this.sampleSink=new IO(O),this.disposed=!1}async play(O=this.pauseTime){if(this.playing||!this.bufferSink)return;if(this.audioContext.state==="suspended")await this.audioContext.resume();this.playbackId++;let $=this.playbackId;this.playing=!0,this.startContextTime=this.audioContext.currentTime,this.startMediaTime=O,this.pauseTime=O,this.bufferIterator=this.bufferSink.buffers(O),this.scheduleAudioBuffers($)}async scheduleAudioBuffers(O){let $=this.bufferIterator;if(!$||!this.gainNode)return;try{for await(let{buffer:K,timestamp:j}of $){if(O!==this.playbackId||this.disposed||!this.playing)break;let Q=this.audioContext.createBufferSource();Q.buffer=K,Q.connect(this.gainNode),Q.playbackRate.value=this.playbackRate,Q.playbackRate.setValueAtTime(this.playbackRate,this.audioContext.currentTime);let V=this.startContextTime+(j-this.startMediaTime)/this.playbackRate;if(V>=this.audioContext.currentTime)Q.start(V);else{let J=Math.max(0,(this.audioContext.currentTime-V)*this.playbackRate);if(J<K.duration)Q.start(this.audioContext.currentTime,J);else continue}if(this.queuedNodes.add(Q),Q.onended=()=>{this.queuedNodes.delete(Q)},j-this.getCurrentTime()>=1)await this.waitForCatchup(j)}}catch{}}async waitForCatchup(O){return new Promise(($)=>{let K=setInterval(()=>{if(O-this.getCurrentTime()<1||!this.playing)clearInterval(K),$()},100)})}pause(){if(!this.playing)return;let O=this.getCurrentTime();if(this.playing=!1,this.pauseTime=O,this.stopQueuedNodes(),this.bufferIterator)this.bufferIterator.return(),this.bufferIterator=null}stop(){this.pause(),this.pauseTime=0,this.startContextTime=0,this.startMediaTime=0}async seek(O){let $=this.playing;if($)this.pause();if(this.pauseTime=O,$)await this.play(O)}getCurrentTime(){if(this.playing){let O=this.audioContext.currentTime-this.startContextTime;return this.startMediaTime+O*this.playbackRate}return this.pauseTime}setVolume(O){this.volume=Math.max(0,Math.min(1,O)),this.updateGain()}setMuted(O){this.muted=O,this.updateGain()}updateGain(){if(!this.gainNode)return;let O=this.muted?0:this.volume;this.gainNode.gain.value=O*O}getVolume(){return this.volume}isMuted(){return this.muted}isPlaying(){return this.playing}setPlaybackRate(O){let $=Math.max(0.25,Math.min(4,O));if(this.playbackRate===$)return;let K=this.playing,j=this.getCurrentTime();if(this.playbackRate=$,K)this.pause(),this.pauseTime=j,this.play(j)}getAudioContext(){return this.audioContext}async getBufferAt(O){if(!this.bufferSink)return null;return this.bufferSink.getBuffer(O)}async getSampleAt(O){if(!this.sampleSink)return null;return this.sampleSink.getSample(O)}stopQueuedNodes(){for(let O of this.queuedNodes)try{O.stop()}catch{}this.queuedNodes.clear()}async clearIterators(){if(this.playbackId++,this.stop(),this.bufferIterator){try{await this.bufferIterator.return()}catch{}this.bufferIterator=null}}dispose(){if(this.disposed=!0,this.playbackId++,this.stop(),this.bufferIterator)this.bufferIterator.return(),this.bufferIterator=null;this.bufferSink=null,this.sampleSink=null}destroy(){if(this.dispose(),this.gainNode)this.gainNode.disconnect(),this.gainNode=null;if(this.audioContext.state!=="closed")this.audioContext.close()}}var fO=100,kO=250;class g{videoRenderer;audioManager;playing=!1;currentTime=0;duration=0;playbackRate=1;animationFrameId=null;lastFrameTime=0;syncIntervalId=null;renderIntervalId=null;isWaiting=!1;onTimeUpdate;onEnded;onWaiting;onPlaying;pendingSeekTime=null;isSeeking=!1;seekRequestId=0;constructor(O={}){this.videoRenderer=new v({canvas:O.canvas,rendererType:O.rendererType}),this.audioManager=new p({audioContext:O.audioContext,volume:O.volume,muted:O.muted}),this.playbackRate=O.playbackRate??1}async setVideoTrack(O){if(!O){this.videoRenderer.dispose();return}await this.videoRenderer.setVideoTrack(O);let $=await O.computeDuration();this.duration=Math.max(this.duration,$)}async trySetVideoTrack(O){try{return await this.setVideoTrack(O),!0}catch{return!1}}async setAudioTrack(O){let $=this.playing,K=this.getCurrentTime();if(!O){this.audioManager.dispose();return}let j=await O.computeDuration(),Q=Math.max(0,Math.min(K,j));if(await this.audioManager.setAudioTrack(O),await this.audioManager.seek(Q),$)await this.audioManager.play(Q);this.currentTime=Q,this.duration=Math.max(this.duration,j)}async trySetAudioTrack(O){try{return await this.setAudioTrack(O),!0}catch{return!1}}async setCanvas(O){await this.videoRenderer.setCanvas(O)}async play(){if(this.playing)return;if(this.playing=!0,this.lastFrameTime=performance.now(),this.currentTime>=this.duration)this.currentTime=0,await this.videoRenderer.seek(0);await this.audioManager.play(this.currentTime),this.startRenderLoop(),this.startSyncInterval()}pause(){if(!this.playing)return;if(this.playing=!1,this.isWaiting=!1,this.audioManager.pause(),this.stopRenderLoop(),this.stopSyncInterval(),this.audioManager.isPlaying())this.currentTime=this.audioManager.getCurrentTime()}async seek(O){let $=Math.max(0,Math.min(O,this.duration));if(this.currentTime=$,this.onTimeUpdate)this.onTimeUpdate(this.currentTime);if(this.seekRequestId++,this.pendingSeekTime=$,!this.isSeeking)await this.processPendingSeeks()}async processPendingSeeks(){if(this.isSeeking)return;this.isSeeking=!0;try{while(this.pendingSeekTime!==null){let O=this.pendingSeekTime;this.pendingSeekTime=null;let $=this.seekRequestId;if(await this.videoRenderer.seek(O),$!==this.seekRequestId)continue;await this.audioManager.seek(O)}}finally{this.isSeeking=!1}if(this.pendingSeekTime!==null)await this.processPendingSeeks()}startRenderLoop(){if(this.animationFrameId!==null||this.renderIntervalId!==null)return;let O=($=!0)=>{if(!this.playing)return;if(this.isSeeking);else if(this.audioManager.isPlaying())this.currentTime=this.audioManager.getCurrentTime();else{let j=performance.now(),Q=(j-this.lastFrameTime)/1000;this.lastFrameTime=j,this.currentTime+=Q*this.playbackRate}if(this.currentTime>=this.duration){this.handleEnded();return}let{isStarving:K}=this.videoRenderer.updateFrame(this.currentTime,this.isSeeking);if(K&&!this.isWaiting){if(this.isWaiting=!0,this.onWaiting)this.onWaiting()}else if(!K&&this.isWaiting){if(this.isWaiting=!1,this.onPlaying)this.onPlaying()}if($)this.animationFrameId=requestAnimationFrame(()=>O())};if(this.animationFrameId=requestAnimationFrame(()=>O()),this.renderIntervalId===null)this.renderIntervalId=window.setInterval(()=>O(!1),fO)}stopRenderLoop(){if(this.animationFrameId!==null)cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null;if(this.renderIntervalId!==null)clearInterval(this.renderIntervalId),this.renderIntervalId=null}startSyncInterval(){if(this.syncIntervalId!==null)return;this.syncIntervalId=window.setInterval(()=>{if(this.playing&&this.onTimeUpdate)this.onTimeUpdate(this.currentTime)},kO)}stopSyncInterval(){if(this.syncIntervalId!==null)clearInterval(this.syncIntervalId),this.syncIntervalId=null}handleEnded(){if(this.pause(),this.currentTime=this.duration,this.onEnded)this.onEnded()}getCurrentTime(){if(this.playing&&!this.isSeeking&&this.audioManager.isPlaying())return this.audioManager.getCurrentTime();return this.currentTime}getDuration(){return this.duration}setDuration(O){this.duration=O}isPlaying(){return this.playing}setVolume(O){this.audioManager.setVolume(O)}getVolume(){return this.audioManager.getVolume()}setMuted(O){this.audioManager.setMuted(O)}isMuted(){return this.audioManager.isMuted()}setPlaybackRate(O){let $=Math.max(0.25,Math.min(4,O));if(this.playbackRate===$)return;this.playbackRate=$,this.audioManager.setPlaybackRate($),this.lastFrameTime=performance.now()}getPlaybackRate(){return this.playbackRate}setTimeUpdateCallback(O){this.onTimeUpdate=O}setEndedCallback(O){this.onEnded=O}setWaitingCallback(O){this.onWaiting=O}setPlayingCallback(O){this.onPlaying=O}isBuffering(){return this.isWaiting}async screenshot(O){return this.videoRenderer.screenshot(this.currentTime,O)}getVideoRenderer(){return this.videoRenderer}getAudioManager(){return this.audioManager}async switchRenderer(O){await this.videoRenderer.switchRenderer(O)}getRendererType(){return this.videoRenderer.getRendererType()}updateCanvasDimensions(){this.videoRenderer.updateCanvasDimensions()}setRendererChangeCallback(O){this.videoRenderer.setRendererChangeCallback(O)}setRendererFallbackCallback(O){this.videoRenderer.setRendererFallbackCallback(O)}setRotationChangeCallback(O){this.videoRenderer.setRotationChangeCallback(O)}setRotation(O){this.videoRenderer.setRotation(O)}getRotation(){return this.videoRenderer.getRotation()}getDisplaySize(){return this.videoRenderer.getDisplaySize()}setPluginManager(O){this.videoRenderer.setPluginManager(O),this.audioManager.setPluginManager(O)}getCanvas(){return this.videoRenderer.getCanvas()}refreshOverlays(){this.videoRenderer.refreshOverlays()}rebuildAudioGraph(){this.audioManager.rebuildAudioGraph()}async reset(){this.pause(),this.stopRenderLoop(),this.stopSyncInterval(),this.currentTime=0,this.duration=0,await Promise.all([this.videoRenderer.clearIterators(),this.audioManager.clearIterators()]),this.playbackRate=1,this.lastFrameTime=0,this.seekRequestId++,this.pendingSeekTime=null,this.isSeeking=!1}dispose(){this.pause(),this.seekRequestId++,this.pendingSeekTime=null,this.isSeeking=!1,this.videoRenderer.dispose(),this.audioManager.dispose(),this.onTimeUpdate=void 0,this.onEnded=void 0,this.onWaiting=void 0,this.onPlaying=void 0}destroy(){this.dispose(),this.audioManager.destroy()}}function m(){return crypto?.randomUUID?.()??Date.now().toString(36)+Math.random().toString(36).substr(2)}class QO{store;emitter;switchSource;sourceManager;constructor(O,$,K,j){this.store=O,this.emitter=$,this.switchSource=K,this.sourceManager=j}async loadPlaylist(O,$={}){let K=O.map((j)=>{if(j&&typeof j==="object"&&"mediaSource"in j)return{id:m(),mediaSource:j.mediaSource,title:j.title,poster:j.poster,savedPosition:null,duration:null};else return{id:m(),mediaSource:j,savedPosition:null,duration:null}});if(this.store.updatePlaylist(K,K.length>0?0:null),this.emitter.emit("playlistchange",{playlist:K}),K.length>0&&this.switchSource){let j=K[0];if($.startTime!==void 0)j.savedPosition=$.startTime;await this.switchSource(j,$.autoplay??!1)}}addToPlaylist(O,$){let K=this.createPlaylistItem(O);this.store.addToPlaylist(K,$),this.emitter.emit("playlistadd",{item:K,index:$??this.store.getState().playlist.length-1})}async removeFromPlaylist(O){let $=this.store.getState(),K=$.currentPlaylistIndex,j=$.playing;this.store.removeFromPlaylist(O),this.emitter.emit("playlistremove",{index:O}),this.sourceManager?.disposeQueued($.playlist[O]?.id||"");let Q=this.store.getState(),V=Q.currentPlaylistIndex;if(Q.playlist.length===0)this.sourceManager?.disposeAll(),this.emitter.emit("playlistchange",{playlist:Q.playlist}),this.emitter.emit("playlistend",void 0);if(K===O&&V!==null&&V!==K&&this.switchSource){let J=Q.playlist[V];try{await this.switchSource(J,j)}catch(U){this.emitter.emit("playlistitemerror",{index:V,error:U})}}}clearPlaylist(){this.store.clearPlaylist(),this.emitter.emit("playlistchange",{playlist:[]}),this.emitter.emit("playlistend",void 0),this.sourceManager?.disposeAll()}async next(){let O=this.store.getState(),$=O.currentPlaylistIndex??0,K=O.playlist,j=O.playlistMode,Q=null;if(j==="repeat-one")Q=$;else if(j==="sequential"||j==="repeat")if($<K.length-1)Q=$+1;else if(j==="repeat")Q=0;else{this.emitter.emit("playlistend",void 0);return}else if($<K.length-1)Q=$+1;if(Q!==null)await this.switchTo(Q)}async prev(){let $=this.store.getState().currentPlaylistIndex??0;if($>0)await this.switchTo($-1)}async jumpTo(O){let K=this.store.getState().playlist;if(O>=0&&O<K.length)await this.switchTo(O);else if(O>=K.length)this.emitter.emit("playlistend",void 0)}setMode(O){let $=["sequential","manual","repeat","repeat-one",null];if(!$.includes(O))throw Error(`Invalid playlist mode: ${O}. Valid modes: ${$.filter((K)=>K!==null).join(", ")}, null`);this.store.updatePlaylistMode(O)}async switchTo(O){let $=this.store.getState(),K=$.currentPlaylistIndex,j=$.playing,Q=[...$.playlist];if(K!==null&&K!==O){let U=Q[K];Q[K]={...U,savedPosition:$.currentTime}}this.store.updatePlaylist(Q,O);let V=Q[O];if(this.emitter.emit("playlistitemchange",{index:O,item:V,previousIndex:K??void 0}),this.switchSource)await this.switchSource(V,j);if($.playlistMode==="sequential"&&O<Q.length-1){let U=Q[O+1];this.sourceManager?.preloadSource(U.mediaSource,U.id)}}createPlaylistItem(O){if(O&&typeof O==="object"&&"mediaSource"in O)return{id:m(),mediaSource:O.mediaSource,title:O.title,poster:O.poster,savedPosition:null,duration:null};else return{id:m(),mediaSource:O,savedPosition:null,duration:null}}get playlist(){return this.store.getState().playlist}get currentIndex(){return this.store.getState().currentPlaylistIndex}get currentItem(){let O=this.currentIndex;return O!==null?this.playlist[O]:null}get mode(){return this.store.getState().playlistMode}dispose(){if(this.sourceManager)this.sourceManager=void 0;this.switchSource=void 0}}function zO(O,$,K,j){let Q=$.name;return{player:O,getState(){return O.getState()},subscribe(V){let J=O.subscribe(V),U=()=>J.unsubscribe();return K.stateUnsubscribes.push(U),U},getPluginState(){return K.pluginState},setPluginState(V){K.pluginState=V},on(V,J){O.on(V,J);let U=K.eventListeners.get(V);if(!U)U=new Set,K.eventListeners.set(V,U);U.add(J)},off(V,J){O.off(V,J);let U=K.eventListeners.get(V);if(U)U.delete(J)},getCanvas(){return O.getRenderTarget()},getPlugin(V){return j().get(V)?.plugin},hasPlugin(V){return j().has(V)},log(...V){console.log(`[MediaFox:${Q}]`,...V)},warn(...V){console.warn(`[MediaFox:${Q}]`,...V)},error(...V){console.error(`[MediaFox:${Q}]`,...V)}}}class VO{player;plugins=new Map;overlays=[];overlaysSorted=!1;registrationCounter=0;constructor(O){this.player=O}async install(O){let{name:$}=O;if(this.plugins.has($))throw Error(`Plugin "${$}" is already installed`);if(O.dependencies){for(let j of O.dependencies)if(!this.plugins.has(j))throw Error(`Plugin "${$}" requires plugin "${j}" to be installed first`)}let K={plugin:O,context:null,eventListeners:new Map,stateUnsubscribes:[],pluginState:void 0};K.context=zO(this.player,O,K,()=>this.plugins),this.plugins.set($,K);try{await O.install(K.context)}catch(j){throw this.plugins.delete($),j}if(O.hooks?.render?.onOverlay)this.overlays.push({pluginName:$,zIndex:O.hooks.render.onOverlay.zIndex??0,registrationOrder:this.registrationCounter++,render:O.hooks.render.onOverlay}),this.overlaysSorted=!1,this.player.refreshOverlays()}async uninstall(O){let $=this.plugins.get(O);if(!$)throw Error(`Plugin "${O}" is not installed`);try{await $.plugin.uninstall?.()}catch(j){console.error(`Error uninstalling plugin "${O}":`,j)}for(let[j,Q]of $.eventListeners)for(let V of Q)this.player.off(j,V);for(let j of $.stateUnsubscribes)j();let K=this.overlays.some((j)=>j.pluginName===O);if(this.overlays=this.overlays.filter((j)=>j.pluginName!==O),this.plugins.delete(O),K)this.player.refreshOverlays()}has(O){return this.plugins.has(O)}get size(){return this.plugins.size}async executeBeforeLoad(O){for(let[,$]of this.plugins){let K=$.plugin.hooks?.lifecycle?.beforeLoad;if(!K)continue;try{let j=await K.call($.plugin,O);if(j?.cancel)return j;if(j?.data!==void 0)O=j.data}catch(j){console.error(`[MediaFox:${$.plugin.name}] Error in beforeLoad hook:`,j)}}return{data:O}}async executeAfterLoad(O){for(let[,$]of this.plugins){let K=$.plugin.hooks?.lifecycle?.afterLoad;if(!K)continue;try{await K.call($.plugin,O)}catch(j){console.error(`[MediaFox:${$.plugin.name}] Error in afterLoad hook:`,j)}}}async executeBeforePlay(){for(let[,O]of this.plugins){let $=O.plugin.hooks?.lifecycle?.beforePlay;if(!$)continue;try{let K=await $.call(O.plugin);if(K?.cancel)return K}catch(K){console.error(`[MediaFox:${O.plugin.name}] Error in beforePlay hook:`,K)}}return}executeAfterPlay(){for(let[,O]of this.plugins){let $=O.plugin.hooks?.lifecycle?.afterPlay;if(!$)continue;try{$.call(O.plugin)}catch(K){console.error(`[MediaFox:${O.plugin.name}] Error in afterPlay hook:`,K)}}}async executeBeforePause(){for(let[,O]of this.plugins){let $=O.plugin.hooks?.lifecycle?.beforePause;if(!$)continue;try{let K=await $.call(O.plugin);if(K?.cancel)return K}catch(K){console.error(`[MediaFox:${O.plugin.name}] Error in beforePause hook:`,K)}}return}executeAfterPause(){for(let[,O]of this.plugins){let $=O.plugin.hooks?.lifecycle?.afterPause;if(!$)continue;try{$.call(O.plugin)}catch(K){console.error(`[MediaFox:${O.plugin.name}] Error in afterPause hook:`,K)}}}async executeBeforeSeek(O){for(let[,$]of this.plugins){let K=$.plugin.hooks?.lifecycle?.beforeSeek;if(!K)continue;try{let j=await K.call($.plugin,O);if(j?.cancel)return j;if(j?.data!==void 0)O=j.data}catch(j){console.error(`[MediaFox:${$.plugin.name}] Error in beforeSeek hook:`,j)}}return{data:O}}executeAfterSeek(O){for(let[,$]of this.plugins){let K=$.plugin.hooks?.lifecycle?.afterSeek;if(!K)continue;try{K.call($.plugin,O)}catch(j){console.error(`[MediaFox:${$.plugin.name}] Error in afterSeek hook:`,j)}}}async executeBeforeStop(){for(let[,O]of this.plugins){let $=O.plugin.hooks?.lifecycle?.beforeStop;if(!$)continue;try{let K=await $.call(O.plugin);if(K?.cancel)return K}catch(K){console.error(`[MediaFox:${O.plugin.name}] Error in beforeStop hook:`,K)}}return}executeAfterStop(){for(let[,O]of this.plugins){let $=O.plugin.hooks?.lifecycle?.afterStop;if(!$)continue;try{$.call(O.plugin)}catch(K){console.error(`[MediaFox:${O.plugin.name}] Error in afterStop hook:`,K)}}}executeOnError(O){let $=!1;for(let[,K]of this.plugins){let j=K.plugin.hooks?.lifecycle?.onError;if(!j)continue;try{if(j.call(K.plugin,O)?.handled)$=!0}catch(Q){console.error(`[MediaFox:${K.plugin.name}] Error in onError hook:`,Q)}}return $}executeOnEnded(){for(let[,O]of this.plugins){let $=O.plugin.hooks?.lifecycle?.onEnded;if(!$)continue;try{$.call(O.plugin)}catch(K){console.error(`[MediaFox:${O.plugin.name}] Error in onEnded hook:`,K)}}}executeBeforeRender(O,$){for(let[,K]of this.plugins){let j=K.plugin.hooks?.render?.beforeRender;if(!j)continue;try{let Q=j.call(K.plugin,O,$);if(Q?.skip)return Q}catch(Q){console.error(`[MediaFox:${K.plugin.name}] Error in beforeRender hook:`,Q)}}return}executeTransformFrame(O){for(let[,$]of this.plugins){let K=$.plugin.hooks?.render?.transformFrame;if(!K)continue;try{let j=K.call($.plugin,O);if(j)O=j}catch(j){console.error(`[MediaFox:${$.plugin.name}] Error in transformFrame hook:`,j)}}return O}executeAfterRender(O){for(let[,$]of this.plugins){let K=$.plugin.hooks?.render?.afterRender;if(!K)continue;try{K.call($.plugin,O)}catch(j){console.error(`[MediaFox:${$.plugin.name}] Error in afterRender hook:`,j)}}}executeOverlays(O,$,K){if(this.overlays.length===0)return;if(!this.overlaysSorted)this.overlays.sort((j,Q)=>{if(j.zIndex!==Q.zIndex)return j.zIndex-Q.zIndex;return j.registrationOrder-Q.registrationOrder}),this.overlaysSorted=!0;for(let j of this.overlays)try{j.render?.render(O,$,K)}catch(Q){console.error(`[MediaFox:${j.pluginName}] Error in onOverlay hook:`,Q)}}executeBeforeStateUpdate(O){for(let[,$]of this.plugins){let K=$.plugin.hooks?.state?.beforeStateUpdate;if(!K)continue;try{let j=K.call($.plugin,O);if(j===null)return null;if(j!==void 0)O=j}catch(j){console.error(`[MediaFox:${$.plugin.name}] Error in beforeStateUpdate hook:`,j)}}return O}executeOnStateChange(O,$){for(let[,K]of this.plugins){let j=K.plugin.hooks?.state?.onStateChange;if(!j)continue;try{j.call(K.plugin,O,$)}catch(Q){console.error(`[MediaFox:${K.plugin.name}] Error in onStateChange hook:`,Q)}}}executeBeforeEvent(O,$){for(let[,K]of this.plugins){let j=K.plugin.hooks?.event?.beforeEvent;if(!j)continue;try{let Q=j.call(K.plugin,O,$);if(Q?.cancel)return Q;if(Q?.data!==void 0)$=Q.data}catch(Q){console.error(`[MediaFox:${K.plugin.name}] Error in beforeEvent hook:`,Q)}}return{data:$}}executeAfterEvent(O,$){for(let[,K]of this.plugins){let j=K.plugin.hooks?.event?.afterEvent;if(!j)continue;try{j.call(K.plugin,O,$)}catch(Q){console.error(`[MediaFox:${K.plugin.name}] Error in afterEvent hook:`,Q)}}}executeOnAudioNode(O,$){let K=$;for(let[,j]of this.plugins){let Q=j.plugin.hooks?.audio?.onAudioNode;if(!Q)continue;try{let V=Q.call(j.plugin,O,$);if(V)K=V}catch(V){console.error(`[MediaFox:${j.plugin.name}] Error in onAudioNode hook:`,V)}}return K}async dispose(){let O=Array.from(this.plugins.keys()).reverse();for(let $ of O)try{await this.uninstall($)}catch(K){console.error(`Error disposing plugin "${$}":`,K)}}}import{ALL_FORMATS as vO,BlobSource as hO,BufferSource as pO,CanvasSink as gO,FilePathSource as mO,Input as uO,ReadableStreamSource as lO,UrlSource as cO}from"mediabunny";class u{currentSource=null;queuedSources=new Map;options;constructor(O={}){this.options={maxCacheSize:O.maxCacheSize??16777216,crossOrigin:O.crossOrigin,requestInit:O.requestInit}}async createSource(O,$){if(this.currentSource&&!$)this.disposeCurrent();let K,j;if(O instanceof File||O instanceof Blob)K=new hO(O,{maxCacheSize:this.options.maxCacheSize}),j="blob";else if(O instanceof ArrayBuffer||O instanceof Uint8Array)K=new pO(O),j="buffer";else if(typeof O==="string"||O instanceof URL){let J=O instanceof URL?O.href:O;if(typeof window>"u"&&!J.startsWith("http"))K=new mO(J,{maxCacheSize:this.options.maxCacheSize}),j="file";else K=new cO(J,{maxCacheSize:this.options.maxCacheSize,requestInit:this.options.requestInit}),j="url"}else if(typeof ReadableStream<"u"&&O instanceof ReadableStream)K=new lO(O,{maxCacheSize:this.options.maxCacheSize}),j="stream";else throw TypeError("Unsupported media source type");let Q=new uO({source:K,formats:vO}),V={source:K,input:Q,type:j,originalSource:O};if($)this.queuedSources.set($,V);else this.currentSource=V;return V}getCurrentSource(){return this.currentSource}getQueuedSource(O){return this.queuedSources.get(O)||null}async preloadSource(O,$){if(this.queuedSources.has($))return;let K=await this.createSource(O,$);if(K.input)try{let j=await this.prefetchTrackData(K.input);K.prefetchedData=j}catch{}}async prefetchTrackData(O){let $=await O.getVideoTracks(),K=await O.getAudioTracks(),j=$.length>0?$[0]:null,Q=K.length>0?K[0]:null,V=null,J=null,U=0;if(j){if(j.codec!==null&&await j.canDecode()){V=new gO(j,{poolSize:2});let G=V.canvases(0);J=(await G.next()).value??null,await G.return(),U=await j.computeDuration()}}if(!U&&Q)U=await Q.computeDuration();return{videoTrack:j,audioTrack:Q,canvasSink:V,firstFrame:J,duration:U}}promoteQueuedSource(O){let $=this.queuedSources.get(O);if(!$)return null;if(this.queuedSources.delete(O),this.currentSource)this.currentSource.input?.dispose();return this.currentSource=$,$}getOriginalSource(){return this.currentSource?.originalSource??null}disposeCurrent(){if(this.currentSource)this.currentSource.input?.dispose(),this.currentSource=null}disposeQueued(O){let $=this.queuedSources.get(O);if($)$.input?.dispose(),this.queuedSources.delete(O)}disposeAll(){this.disposeCurrent(),this.queuedSources.forEach((O,$)=>{this.disposeQueued($)}),this.queuedSources.clear()}dispose(){this.disposeAll()}static isStreamingSource(O){return O instanceof ReadableStream||typeof O==="string"&&O.startsWith("http")}static isLocalSource(O){return O instanceof File||O instanceof Blob||O instanceof ArrayBuffer||O instanceof Uint8Array||typeof O==="string"&&!O.startsWith("http")}static getSourceType(O){if(O instanceof File)return"file";if(O instanceof Blob)return"blob";if(O instanceof ArrayBuffer||O instanceof Uint8Array)return"buffer";if(O instanceof ReadableStream)return"stream";if(typeof O==="string"||O instanceof URL)return(O instanceof URL?O.href:O).startsWith("http")?"url":"file";return"unknown"}static async fromFetch(O,$){let K=await fetch(O,$);if(!K.ok)throw Error(`Failed to fetch: ${K.status} ${K.statusText}`);return K.blob()}static fromStreamingFetch(O,$){return new ReadableStream({async start(K){let j=await fetch(O,$);if(!j.ok){K.error(Error(`Failed to fetch: ${j.status} ${j.statusText}`));return}let Q=j.body?.getReader();if(!Q){K.error(Error("Response body is not readable"));return}try{while(!0){let{done:V,value:J}=await Q.read();if(V)break;K.enqueue(J)}K.close()}catch(V){K.error(V)}}})}}function l(O,$){if(Object.is(O,$))return!0;if(typeof O!==typeof $)return!1;if(O===null||$===null)return O===$;if(Array.isArray(O)&&Array.isArray($)){if(O.length!==$.length)return!1;for(let K=0;K<O.length;K++)if(!l(O[K],$[K]))return!1;return!0}if(PO(O)&&PO($)){let K=Object.keys(O),j=Object.keys($);if(K.length!==j.length)return!1;for(let Q of K){if(!Object.hasOwn($,Q))return!1;if(!l(O[Q],$[Q]))return!1}return!0}return!1}function PO(O){return typeof O==="object"&&O!==null&&O.constructor===Object}class c{state;previousState;listeners=new Set;updateScheduled=!1;pendingUpdates={};pendingKeys=[];pluginManager=null;listenerCache=[];constructor(){this.state=this.getInitialState(),this.previousState={...this.state}}setPluginManager(O){this.pluginManager=O}getInitialState(){let $=H.getSupportedRenderers()[0]||"canvas2d";return{state:"idle",currentTime:0,duration:0,buffered:[],volume:1,muted:!1,playbackRate:1,playing:!1,paused:!0,ended:!1,seeking:!1,waiting:!1,error:null,mediaInfo:null,videoTracks:[],audioTracks:[],subtitleTracks:[],selectedVideoTrack:null,selectedAudioTrack:null,selectedSubtitleTrack:null,canPlay:!1,canPlayThrough:!1,isLive:!1,rendererType:$,playlist:[],currentPlaylistIndex:null,playlistMode:null,rotation:0,displaySize:{width:0,height:0}}}getState(){return this.state}setState(O){if(this.pluginManager){let K=this.pluginManager.executeBeforeStateUpdate(O);if(K===null)return;O=K}let $=Object.keys(O);for(let K=0;K<$.length;K++){let j=$[K];if(this.pendingUpdates[j]===void 0)this.pendingKeys.push(j);this.setPendingValue(j,O[j])}if(!this.updateScheduled)this.updateScheduled=!0,queueMicrotask(()=>this.flushUpdates())}setPendingValue(O,$){this.pendingUpdates[O]=$}flushUpdates(){let O=this.pendingKeys;if(O.length===0){this.updateScheduled=!1;return}let $=!1;for(let K=0;K<O.length;K++){let j=O[K];if(!l(this.pendingUpdates[j],this.state[j])){$=!0;break}}for(let K=0;K<O.length;K++){let j=O[K];this.copyStateKey(j)}if(this.pendingUpdates={},this.pendingKeys.length=0,this.updateScheduled=!1,$){if(this.notifyListeners(),this.pluginManager)this.pluginManager.executeOnStateChange(this.state,this.previousState)}}copyStateKey(O){if(this.previousState[O]=this.state[O],O in this.pendingUpdates)this.state[O]=this.pendingUpdates[O]}subscribe(O){return this.listeners.add(O),O(this.getState()),()=>{this.listeners.delete(O)}}reset(){this.state=this.getInitialState(),this.pendingUpdates={},this.pendingKeys.length=0,this.updateScheduled=!1,this.notifyListeners()}notifyListeners(){let O=this.state,$=this.listenerCache;$.length=0;for(let K of this.listeners)$.push(K);for(let K=0;K<$.length;K++)try{$[K](O)}catch(j){console.error("Error in state listener:",j)}}updatePlaybackState(O){let $=O?"playing":"paused";this.setState({state:$,playing:O,paused:!O,ended:!1})}updateTime(O){this.setState({currentTime:O})}updateDuration(O){this.setState({duration:O})}updateBuffered(O){this.setState({buffered:O})}updateVolume(O,$){this.setState({volume:O,muted:$})}updatePlaybackRate(O){this.setState({playbackRate:O})}updateMediaInfo(O){this.setState({mediaInfo:O})}updateTracks(O,$,K){let j={};if(O)j.videoTracks=O;if($)j.audioTracks=$;if(K)j.subtitleTracks=K;this.setState(j)}updateSelectedTracks(O,$){switch(O){case"video":this.setState({selectedVideoTrack:$});break;case"audio":this.setState({selectedAudioTrack:$});break;case"subtitle":this.setState({selectedSubtitleTrack:$});break}}updateError(O){this.setState({error:O,state:O?"error":this.state.state})}updateSeekingState(O){this.setState({seeking:O})}updateWaitingState(O){this.setState({waiting:O})}updateReadyState(O,$){this.setState({canPlay:O,canPlayThrough:$,state:O?"ready":this.state.state})}updateEndedState(O){this.setState({ended:O,playing:!1,paused:!0,state:O?"ended":this.state.state})}updateLoadingState(){this.setState({state:"loading",playing:!1,paused:!0,ended:!1,error:null})}updateRendererType(O){this.setState({rendererType:O})}updateRotation(O,$){this.setState({rotation:O,displaySize:$})}updatePlaylist(O,$=null){this.setState({playlist:O,currentPlaylistIndex:$})}updateCurrentPlaylistIndex(O){this.setState({currentPlaylistIndex:O})}updatePlaylistMode(O){this.setState({playlistMode:O})}addToPlaylist(O,$){let K=this.state.playlist,j,Q=this.state.currentPlaylistIndex;if($!==void 0&&$>=0&&$<=K.length){if(j=[...K.slice(0,$),O,...K.slice($)],Q!==null&&Q>=$)Q+=1}else j=[...K,O];this.setState({playlist:j,currentPlaylistIndex:Q})}removeFromPlaylist(O){let $=this.state.playlist;if(O<0||O>=$.length)return;let K=$.filter((Q,V)=>V!==O),j=this.state.currentPlaylistIndex;if(j===O)j=K.length>0?0:null;else if(j!==null&&j>O)j-=1;if(K.length===0)this.setState({playlist:K,currentPlaylistIndex:null,state:"idle",currentTime:0,duration:0,mediaInfo:null,videoTracks:[],audioTracks:[],subtitleTracks:[],selectedVideoTrack:null,selectedAudioTrack:null,selectedSubtitleTrack:null});else this.setState({playlist:K,currentPlaylistIndex:j})}clearPlaylist(){this.setState({playlist:[],currentPlaylistIndex:null,state:"idle",currentTime:0,duration:0,mediaInfo:null,videoTracks:[],audioTracks:[],subtitleTracks:[],selectedVideoTrack:null,selectedAudioTrack:null,selectedSubtitleTrack:null})}}class o{input=null;videoTracks=new Map;audioTracks=new Map;videoTrackInfos=[];audioTrackInfos=[];subtitleTrackInfos=[];subtitleProviders=new Map;subtitleTrackResolvers=new Map;selectedVideoTrack=null;selectedAudioTrack=null;selectedSubtitleTrack=null;onTrackChange;async initialize(O){this.videoTracks.clear(),this.audioTracks.clear(),this.videoTrackInfos=[],this.audioTrackInfos=[],this.selectedVideoTrack=null,this.selectedAudioTrack=null,this.input=O,await this.loadTracks()}async loadTracks(){if(!this.input)return;let O=await this.input.getVideoTracks();this.videoTrackInfos=await Promise.all(O.map(async(K)=>{let j=`video-${K.id}`;this.videoTracks.set(j,K);let Q=0,V=0;try{let U=await K.computePacketStats(100);Q=U.averagePacketRate,V=U.averageBitrate}catch{}return{id:j,codec:K.codec,language:K.languageCode,name:K.name,width:K.codedWidth,height:K.codedHeight,frameRate:Q,bitrate:V,rotation:K.rotation,selected:!1,decodable:await K.canDecode()}}));let $=await this.input.getAudioTracks();if(this.audioTrackInfos=await Promise.all($.map(async(K)=>{let j=`audio-${K.id}`;this.audioTracks.set(j,K);let Q=0;try{Q=(await K.computePacketStats(100)).averageBitrate}catch{}return{id:j,codec:K.codec,language:K.languageCode,name:K.name,channels:K.numberOfChannels,sampleRate:K.sampleRate,bitrate:Q,selected:!1,decodable:await K.canDecode()}})),this.videoTrackInfos.length>0){let K=this.videoTrackInfos.find((j)=>j.decodable);if(K)this.selectVideoTrack(K.id)}if(this.audioTrackInfos.length>0){let K=this.audioTrackInfos.find((j)=>j.decodable);if(K)this.selectAudioTrack(K.id)}}getVideoTracks(){return[...this.videoTrackInfos]}getAudioTracks(){return[...this.audioTrackInfos]}getSubtitleTracks(){return[...this.subtitleTrackInfos]}getSelectedVideoTrack(){if(!this.selectedVideoTrack)return null;return this.videoTracks.get(this.selectedVideoTrack)??null}getSelectedAudioTrack(){if(!this.selectedAudioTrack)return null;return this.audioTracks.get(this.selectedAudioTrack)??null}getSelectedVideoTrackInfo(){if(!this.selectedVideoTrack)return null;return this.videoTrackInfos.find((O)=>O.id===this.selectedVideoTrack)??null}getSelectedAudioTrackInfo(){if(!this.selectedAudioTrack)return null;return this.audioTrackInfos.find((O)=>O.id===this.selectedAudioTrack)??null}getSelectedSubtitleTrackInfo(){if(!this.selectedSubtitleTrack)return null;return this.subtitleTrackInfos.find((O)=>O.id===this.selectedSubtitleTrack)??null}selectVideoTrack(O){if(O===this.selectedVideoTrack)return!0;if(O&&!this.videoTracks.has(O))return!1;let $=this.selectedVideoTrack;if(this.videoTrackInfos.forEach((K)=>{K.selected=K.id===O}),this.selectedVideoTrack=O,this.onTrackChange)this.onTrackChange({type:"video",previousTrackId:$,newTrackId:O});return!0}selectAudioTrack(O){if(O===this.selectedAudioTrack)return!0;if(O&&!this.audioTracks.has(O))return!1;let $=this.selectedAudioTrack;if(this.audioTrackInfos.forEach((K)=>{K.selected=K.id===O}),this.selectedAudioTrack=O,this.onTrackChange)this.onTrackChange({type:"audio",previousTrackId:$,newTrackId:O});return!0}selectSubtitleTrack(O){if(O===this.selectedSubtitleTrack)return!0;if(O&&!this.subtitleTrackResolvers.has(O))return!1;let $=this.selectedSubtitleTrack;if(this.subtitleTrackInfos.forEach((K)=>{K.selected=K.id===O}),this.selectedSubtitleTrack=O,this.onTrackChange)this.onTrackChange({type:"subtitle",previousTrackId:$,newTrackId:O});return!0}registerSubtitleTracks(O,$){this.subtitleProviders.set(O,$),this.rebuildSubtitleTracks()}unregisterSubtitleTracks(O){if(!this.subtitleProviders.delete(O))return;this.rebuildSubtitleTracks()}async getSubtitleTrackResource(O){if(!O)return null;let $=this.subtitleTrackResolvers.get(O);if(!$)return null;return $()}rebuildSubtitleTracks(){let O=this.selectedSubtitleTrack;this.subtitleTrackInfos=[],this.subtitleTrackResolvers.clear();for(let K of this.subtitleProviders.values())for(let j of K){let Q={...j.info,selected:!1};this.subtitleTrackInfos.push(Q),this.subtitleTrackResolvers.set(Q.id,j.resolver)}let $=O;if(!$||!this.subtitleTrackResolvers.has($))$=this.subtitleTrackInfos[0]?.id??null;if(this.selectedSubtitleTrack=$,this.subtitleTrackInfos.forEach((K)=>{K.selected=K.id===this.selectedSubtitleTrack}),O!==this.selectedSubtitleTrack&&this.onTrackChange)this.onTrackChange({type:"subtitle",previousTrackId:O,newTrackId:this.selectedSubtitleTrack})}setTrackChangeListener(O){this.onTrackChange=O}getState(){return{videoTracks:this.getVideoTracks(),audioTracks:this.getAudioTracks(),subtitleTracks:this.getSubtitleTracks(),selectedVideoTrack:this.selectedVideoTrack,selectedAudioTrack:this.selectedAudioTrack,selectedSubtitleTrack:this.selectedSubtitleTrack}}getPrimaryVideoTrack(){if(this.videoTracks.size===0)return null;return this.selectedVideoTrack?this.videoTracks.get(this.selectedVideoTrack)??null:this.videoTracks.values().next().value??null}getPrimaryAudioTrack(){if(this.audioTracks.size===0)return null;return this.selectedAudioTrack?this.audioTracks.get(this.selectedAudioTrack)??null:this.audioTracks.values().next().value??null}hasVideo(){return this.videoTrackInfos.length>0}hasAudio(){return this.audioTrackInfos.length>0}hasSubtitles(){return this.subtitleTrackInfos.length>0}dispose(){this.videoTracks.clear(),this.audioTracks.clear(),this.videoTrackInfos=[],this.audioTrackInfos=[],this.subtitleTrackInfos=[],this.subtitleProviders.clear(),this.subtitleTrackResolvers.clear(),this.selectedVideoTrack=null,this.selectedAudioTrack=null,this.selectedSubtitleTrack=null,this.input=null,this.onTrackChange=void 0}async replaceAudioTrackByInputId(O,$){let K=null;for(let[Q,V]of this.audioTracks.entries())if(V.id===O){K=Q;break}if(!K)return;this.audioTracks.set(K,$);let j=this.audioTrackInfos.findIndex((Q)=>Q.id===K);if(j!==-1){let Q=0;try{Q=(await $.computePacketStats(100)).averageBitrate}catch{}this.audioTrackInfos[j]={...this.audioTrackInfos[j],codec:$.codec,channels:$.numberOfChannels,sampleRate:$.sampleRate,bitrate:Q,decodable:await $.canDecode()}}}async replaceVideoTrackByInputId(O,$){let K=null;for(let[Q,V]of this.videoTracks.entries())if(V.id===O){K=Q;break}if(!K)return;this.videoTracks.set(K,$);let j=this.videoTrackInfos.findIndex((Q)=>Q.id===K);if(j!==-1){let Q=0,V=0;try{let J=await $.computePacketStats(100);Q=J.averagePacketRate,V=J.averageBitrate}catch{}this.videoTrackInfos[j]={...this.videoTrackInfos[j],codec:$.codec,width:$.codedWidth,height:$.codedHeight,rotation:$.rotation,frameRate:Q,bitrate:V,decodable:await $.canDecode()}}}}class d{emitter;store;state;sourceManager;playbackController;trackManager;playlistManager;pluginManager;options;disposed=!1;getCurrentInput=()=>this.sourceManager.getCurrentSource()?.input??null;trackSwitcher;core;constructor(O={}){this.options={volume:1,muted:!1,playbackRate:1,autoplay:!1,preload:"metadata",...O},this.emitter=new x({maxListeners:100}),this.store=new c,this.state=new $O(this.store),this.sourceManager=new u({maxCacheSize:O.maxCacheSize,crossOrigin:O.crossOrigin}),this.playbackController=new g({canvas:O.renderTarget,audioContext:O.audioContext,volume:this.options.volume,muted:this.options.muted,playbackRate:this.options.playbackRate,rendererType:this.options.renderer}),this.trackManager=new o,this.playlistManager=new QO(this.store,this.emitter,async($,K)=>{await this.core.load($.mediaSource,{startTime:$.savedPosition??0,autoplay:K,playlistItemId:$.id})},this.sourceManager),this.trackSwitcher=new jO({sourceManager:this.sourceManager,trackManager:this.trackManager,playbackController:this.playbackController,emit:this.emit.bind(this),store:this.store,getCurrentInput:this.getCurrentInput}),this.pluginManager=new VO(this),this.core=new OO({state:this.state,sourceManager:this.sourceManager,trackManager:this.trackManager,playbackController:this.playbackController,trackSwitcher:this.trackSwitcher,emit:this.emit.bind(this),pluginManager:this.pluginManager}),this.playbackController.setPluginManager(this.pluginManager),this.store.setPluginManager(this.pluginManager),this.setupInternalListeners(),this.state.applyInitial(this.options.volume??1,this.options.muted??!1,this.options.playbackRate??1),this.state.updateRendererType(this.options.renderer||"webgpu")}setupInternalListeners(){this.playbackController.setTimeUpdateCallback((O)=>{this.state.updateTime(O),this.emit("timeupdate",{currentTime:O})}),this.playbackController.setEndedCallback(()=>{this.state.updateEndedState(!0),this.emit("ended",void 0);let O=this.getState();if(O.playlist.length>0&&O.currentPlaylistIndex!==null){let{playlistMode:$,currentPlaylistIndex:K}=O;if($==="repeat-one"){let j=K;queueMicrotask(async()=>{try{await this.seek(0),await this.play()}catch(Q){this.emitter.emit("playlistitemerror",{index:j,error:Q})}})}else if($==="repeat"){let j=K<O.playlist.length-1?K+1:0;queueMicrotask(async()=>{try{await this.playlistManager.next()}catch(Q){this.emitter.emit("playlistitemerror",{index:j,error:Q})}})}else if($==="sequential"&&K<O.playlist.length-1){let j=K+1;queueMicrotask(async()=>{try{await this.playlistManager.next()}catch(Q){this.emitter.emit("playlistitemerror",{index:j,error:Q})}})}}}),this.trackManager.setTrackChangeListener((O)=>{this.state.updateSelectedTracks(O.type,O.newTrackId),this.emit("trackchange",{type:O.type,trackId:O.newTrackId})}),this.playbackController.setWaitingCallback(()=>{this.state.updateWaitingState(!0),this.emit("waiting",void 0)}),this.playbackController.setPlayingCallback(()=>{if(this.getState().waiting)this.state.updateWaitingState(!1),this.emit("playing",void 0)}),this.playbackController.setRendererChangeCallback((O)=>{this.state.updateRendererType(O),this.emit("rendererchange",O)}),this.playbackController.setRendererFallbackCallback((O,$)=>{this.emit("rendererfallback",{from:O,to:$})}),this.playbackController.setRotationChangeCallback((O,$)=>{this.store.updateRotation(O,$),this.emit("rotationchange",{rotation:O,displaySize:$})}),this.state.subscribe((O)=>{this.emit("statechange",O)})}async load(O,$={}){this.checkDisposed();let K=this.getState();if(K.playlist.length===0||$.replacePlaylist){await this.playlistManager.loadPlaylist([{mediaSource:O}],{autoplay:$.autoplay??this.options.autoplay,startTime:$.startTime});return}else if(K.currentPlaylistIndex!==null&&K.playlist.length>0){let j=K.currentPlaylistIndex,V={...K.playlist[j],mediaSource:O,savedPosition:0,duration:null},J=[...K.playlist];J[j]=V,this.store.updatePlaylist(J,j),this.emitter.emit("playlistchange",{playlist:J}),await this.core.load(O,{startTime:$.startTime??0,autoplay:$.autoplay??this.options.autoplay});return}await this.core.load(O,{autoplay:$.autoplay??this.options.autoplay,startTime:$.startTime})}async play(){return this.checkDisposed(),this.core.play()}pause(){this.checkDisposed(),this.core.pause()}async seek(O,$={}){return this.checkDisposed(),this.core.seek(O)}async stop(){return this.checkDisposed(),this.core.stop()}get currentTime(){return this.playbackController.getCurrentTime()}set currentTime(O){this.seek(O)}get duration(){return this.state.getState().duration}get volume(){return this.playbackController.getVolume()}set volume(O){this.checkDisposed();let $=Math.max(0,Math.min(1,O));this.playbackController.setVolume($),this.state.updateVolume($,this.muted),this.emit("volumechange",{volume:$,muted:this.muted})}get muted(){return this.playbackController.isMuted()}set muted(O){this.checkDisposed(),this.playbackController.setMuted(O),this.state.updateVolume(this.volume,O),this.emit("volumechange",{volume:this.volume,muted:O})}get playbackRate(){return this.playbackController.getPlaybackRate()}set playbackRate(O){this.checkDisposed();let $=Math.max(0.25,Math.min(4,O));this.playbackController.setPlaybackRate($),this.state.updatePlaybackRate($),this.emit("ratechange",{playbackRate:$})}get paused(){return!this.playbackController.isPlaying()}get ended(){return this.state.getState().ended}get seeking(){return this.state.getState().seeking}get waiting(){return this.state.getState().waiting}get rotation(){return this.playbackController.getRotation()}set rotation(O){this.checkDisposed(),this.playbackController.setRotation(O)}get displaySize(){return this.playbackController.getDisplaySize()}getVideoTracks(){return this.trackManager.getVideoTracks()}getAudioTracks(){return this.trackManager.getAudioTracks()}getSubtitleTracks(){return this.trackManager.getSubtitleTracks()}async selectVideoTrack(O){this.checkDisposed(),await this.trackSwitcher.selectVideoTrack(this.trackManager,O)}async selectAudioTrack(O){this.checkDisposed(),await this.trackSwitcher.selectAudioTrack(this.trackManager,O)}selectSubtitleTrack(O){if(this.checkDisposed(),!this.trackManager.selectSubtitleTrack(O))throw Error(`Invalid subtitle track ID: ${O}`)}registerSubtitleTracks(O,$){this.trackManager.registerSubtitleTracks(O,$),this.state.updateTracks(void 0,void 0,this.trackManager.getSubtitleTracks());let K=this.state.getState().mediaInfo;if(K)this.state.updateMediaInfo({...K,hasSubtitles:this.trackManager.hasSubtitles()})}unregisterSubtitleTracks(O){this.trackManager.unregisterSubtitleTracks(O),this.state.updateTracks(void 0,void 0,this.trackManager.getSubtitleTracks());let $=this.state.getState().mediaInfo;if($)this.state.updateMediaInfo({...$,hasSubtitles:this.trackManager.hasSubtitles()})}async getSubtitleTrackResource(O){return this.trackManager.getSubtitleTrackResource(O)}async screenshot(O={}){return this.checkDisposed(),this.playbackController.screenshot(O)}async setRenderTarget(O){this.checkDisposed(),await this.playbackController.setCanvas(O)}getRenderTarget(){return this.playbackController.getCanvas()}refreshOverlays(){this.playbackController.refreshOverlays()}async loadPlaylist(O,$){this.checkDisposed(),await this.playlistManager.loadPlaylist(O,$)}addToPlaylist(O,$){this.checkDisposed(),this.playlistManager.addToPlaylist(O,$)}async removeFromPlaylist(O){this.checkDisposed(),await this.playlistManager.removeFromPlaylist(O)}clearPlaylist(){this.checkDisposed(),this.playlistManager.clearPlaylist()}async next(){this.checkDisposed(),await this.playlistManager.next()}async prev(){this.checkDisposed(),await this.playlistManager.prev()}async jumpTo(O){this.checkDisposed(),await this.playlistManager.jumpTo(O)}get playlist(){return this.playlistManager.playlist}get playlistIndex(){return this.playlistManager.currentIndex}get nowPlaying(){return this.playlistManager.currentItem}get playlistMode(){return this.playlistManager.mode}set playlistMode(O){this.checkDisposed(),this.playlistManager.setMode(O)}getRendererType(){return this.playbackController.getRendererType()}async switchRenderer(O){this.checkDisposed(),await this.playbackController.switchRenderer(O)}updateCanvasDimensions(){this.checkDisposed(),this.playbackController.updateCanvasDimensions()}static getSupportedRenderers(){return H.getSupportedRenderers()}getState(){return this.state.getState()}subscribe(O){return{unsubscribe:this.state.subscribe(O)}}on(O,$){return this.emitter.on(O,$)}once(O,$){return this.emitter.once(O,$)}off(O,$){this.emitter.off(O,$)}async use(O){if(this.checkDisposed(),await this.pluginManager.install(O),O.hooks?.audio)this.playbackController.rebuildAudioGraph()}async unuse(O){this.checkDisposed(),await this.pluginManager.uninstall(O),this.playbackController.rebuildAudioGraph()}emit(O,$){let K=this.pluginManager.executeBeforeEvent(O,$);if(K?.cancel)return;let j=K?.data??$;this.emitter.emit(O,j),this.pluginManager.executeAfterEvent(O,j)}checkDisposed(){if(this.disposed)throw Error("Player has been disposed")}dispose(){if(this.disposed)return;this.disposed=!0,this.pluginManager.dispose(),this.playbackController.dispose(),this.trackManager.dispose(),this.playlistManager?.dispose(),this.sourceManager.dispose(),this.state.reset(),this.emitter.removeAllListeners()}destroy(){this.dispose(),this.playbackController.destroy()}}var oO={fromUrl(O,$={}){return{mediaSource:O,title:$.title,poster:$.poster}},fromFile(O,$={}){return{mediaSource:O,title:$.title||O.name,poster:$.poster}},fromBlob(O,$={}){return{mediaSource:O,title:$.title,poster:$.poster}},fromBuffer(O,$={}){return{mediaSource:O,title:$.title,poster:$.poster}},fromUint8Array(O,$={}){return{mediaSource:O,title:$.title,poster:$.poster}},fromStream(O,$={}){return{mediaSource:O,title:$.title,poster:$.poster}}};var BO;((Z)=>{Z.MEDIA_NOT_SUPPORTED="MEDIA_NOT_SUPPORTED";Z.MEDIA_LOAD_FAILED="MEDIA_LOAD_FAILED";Z.DECODE_ERROR="DECODE_ERROR";Z.NETWORK_ERROR="NETWORK_ERROR";Z.PERMISSION_DENIED="PERMISSION_DENIED";Z.PLAYBACK_ERROR="PLAYBACK_ERROR";Z.TRACK_NOT_FOUND="TRACK_NOT_FOUND";Z.INVALID_STATE="INVALID_STATE";Z.UNKNOWN_ERROR="UNKNOWN_ERROR"})(BO||={});class M extends Error{code;details;constructor(O,$,K){super($);this.name="MediaFoxError",this.code=O,this.details=K}static mediaNotSupported(O="Media format not supported",$){return new M("MEDIA_NOT_SUPPORTED",O,$)}static mediaLoadFailed(O="Failed to load media",$){return new M("MEDIA_LOAD_FAILED",O,$)}static decodeError(O="Failed to decode media",$){return new M("DECODE_ERROR",O,$)}static networkError(O="Network error occurred",$){return new M("NETWORK_ERROR",O,$)}static permissionDenied(O="Permission denied",$){return new M("PERMISSION_DENIED",O,$)}static playbackError(O="Playback error occurred",$){return new M("PLAYBACK_ERROR",O,$)}static trackNotFound(O="Track not found",$){return new M("TRACK_NOT_FOUND",O,$)}static invalidState(O="Invalid player state",$){return new M("INVALID_STATE",O,$)}static unknownError(O="Unknown error occurred",$){return new M("UNKNOWN_ERROR",O,$)}}function dO(O,$){if(O instanceof M)return O;if(O instanceof Error)return new M("UNKNOWN_ERROR",`${$}: ${O.message}`,{originalError:O});return new M("UNKNOWN_ERROR",`${$}: ${String(O)}`,{originalError:O})}function nO(O,$=!1){let K=Math.abs(O),j=Math.floor(K/3600),Q=Math.floor(K%3600/60),V=Math.floor(K%60),J=Math.floor(K%1*1000),U="";if(O<0)U="-";if(j>0)U+=`${j}:${Q.toString().padStart(2,"0")}:${V.toString().padStart(2,"0")}`;else U+=`${Q}:${V.toString().padStart(2,"0")}`;if($)U+=`.${J.toString().padStart(3,"0")}`;return U}function sO(O){let $=O.trim().split(":").map(Number);if($.some(Number.isNaN))throw Error("Invalid time string");let K=0;if($.length===3)K=$[0]*3600+$[1]*60+$[2];else if($.length===2)K=$[0]*60+$[1];else if($.length===1)K=$[0];else throw Error("Invalid time format");return K}function iO(O,$){return Math.floor(O*$)}function aO(O,$){return O/$}function rO(O,$,K){return Math.max($,Math.min(K,O))}function tO(O,$){return O.start<$.end&&$.start<O.end}function eO(O){if(O.length===0)return[];let $=[...O].sort((j,Q)=>j.start-Q.start),K=[$[0]];for(let j=1;j<$.length;j++){let Q=K[K.length-1],V=$[j];if(V.start<=Q.end)Q.end=Math.max(Q.end,V.end);else K.push(V)}return K}function O$(O){return O.reduce(($,K)=>$+(K.end-K.start),0)}function $$(O,$){for(let K of O)if($>=K.start&&$<K.end)return K;return null}var AK="0.1.0",xK=d;export{dO as wrapError,O$ as totalBufferedDuration,iO as timeToFrame,tO as timeRangesOverlap,sO as parseTime,eO as mergeTimeRanges,aO as frameToTime,nO as formatTime,$$ as findBufferedRange,xK as default,rO as clamp,v as VideoRenderer,AK as VERSION,o as TrackManager,c as Store,I as SourcePool,u as SourceManager,oO as Source,H as RendererFactory,g as PlaybackController,M as MediaFoxError,d as MediaFox,x as EventEmitter,BO as ErrorCode,a as Compositor,p as AudioManager};
@@ -27,6 +27,9 @@ export declare class PlaybackController {
27
27
  private onEnded?;
28
28
  private onWaiting?;
29
29
  private onPlaying?;
30
+ private pendingSeekTime;
31
+ private isSeeking;
32
+ private seekRequestId;
30
33
  constructor(options?: PlaybackControllerOptions);
31
34
  setVideoTrack(track: InputVideoTrack | null): Promise<void>;
32
35
  /**
@@ -42,6 +45,7 @@ export declare class PlaybackController {
42
45
  play(): Promise<void>;
43
46
  pause(): void;
44
47
  seek(time: number): Promise<void>;
48
+ private processPendingSeeks;
45
49
  private startRenderLoop;
46
50
  private stopRenderLoop;
47
51
  private startSyncInterval;
@@ -1 +1 @@
1
- {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../src/playback/controller.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../src/playback/controller.ts"],"names":[],"mappings":"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"}
@@ -23,6 +23,8 @@ export interface VideoRendererOptions {
23
23
  }
24
24
  export declare class VideoRenderer {
25
25
  private canvas;
26
+ private seekDebounceTimer;
27
+ private pendingSeekTime;
26
28
  private canvasSink;
27
29
  private sampleSink;
28
30
  private options;
@@ -31,6 +33,7 @@ export declare class VideoRenderer {
31
33
  private nextFrame;
32
34
  private disposed;
33
35
  private renderingId;
36
+ private currentSeekId;
34
37
  private renderer;
35
38
  private rendererType;
36
39
  private onRendererChange?;
@@ -62,7 +65,7 @@ export declare class VideoRenderer {
62
65
  setCanvas(canvas: HTMLCanvasElement | OffscreenCanvas): Promise<void>;
63
66
  setVideoTrack(track: InputVideoTrack): Promise<void>;
64
67
  seek(timestamp: number): Promise<void>;
65
- updateFrame(currentTime: number): {
68
+ updateFrame(currentTime: number, isSeeking?: boolean): {
66
69
  frameUpdated: boolean;
67
70
  isStarving: boolean;
68
71
  };
@@ -118,6 +121,7 @@ export declare class VideoRenderer {
118
121
  clearIterators(): Promise<void>;
119
122
  private disposeVideoResources;
120
123
  dispose(): void;
124
+ private cancelPendingDebouncedSeek;
121
125
  }
122
126
  export {};
123
127
  //# sourceMappingURL=renderer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/playback/renderer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/playback/renderer.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mediafox/core",
3
- "version": "1.2.13",
3
+ "version": "1.2.14",
4
4
  "description": "Framework-agnostic media player library powered by MediaBunny",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -436,8 +436,7 @@ export class Compositor {
436
436
  const transform = layer.transform;
437
437
  const sourceWidth = layer.source.width ?? this.width;
438
438
  const sourceHeight = layer.source.height ?? this.height;
439
- const effectiveFitMode =
440
- layer.fitMode === undefined || layer.fitMode === 'auto' ? this.fitMode : layer.fitMode;
439
+ const effectiveFitMode = layer.fitMode === undefined || layer.fitMode === 'auto' ? this.fitMode : layer.fitMode;
441
440
 
442
441
  let fittedWidth = sourceWidth;
443
442
  let fittedHeight = sourceHeight;
@@ -33,6 +33,9 @@ export class PlaybackController {
33
33
  private onEnded?: () => void;
34
34
  private onWaiting?: () => void;
35
35
  private onPlaying?: () => void;
36
+ private pendingSeekTime: number | null = null;
37
+ private isSeeking = false;
38
+ private seekRequestId = 0;
36
39
 
37
40
  constructor(options: PlaybackControllerOptions = {}) {
38
41
  this.videoRenderer = new VideoRenderer({
@@ -160,16 +163,48 @@ export class PlaybackController {
160
163
  const clampedTime = Math.max(0, Math.min(time, this.duration));
161
164
  this.currentTime = clampedTime;
162
165
 
163
- // Seek video - this will start a new iterator
164
- await this.videoRenderer.seek(clampedTime);
165
-
166
- // Seek audio
167
- await this.audioManager.seek(clampedTime);
168
-
169
- // Notify time update
166
+ // Update UI immediately
170
167
  if (this.onTimeUpdate) {
171
168
  this.onTimeUpdate(this.currentTime);
172
169
  }
170
+
171
+ // Latest-only seek behavior: keep only the newest target.
172
+ this.seekRequestId++;
173
+ this.pendingSeekTime = clampedTime;
174
+
175
+ if (!this.isSeeking) {
176
+ await this.processPendingSeeks();
177
+ }
178
+ }
179
+
180
+ private async processPendingSeeks(): Promise<void> {
181
+ if (this.isSeeking) return;
182
+ this.isSeeking = true;
183
+
184
+ try {
185
+ while (this.pendingSeekTime !== null) {
186
+ const targetTime = this.pendingSeekTime;
187
+ this.pendingSeekTime = null;
188
+ const requestIdAtStart = this.seekRequestId;
189
+
190
+ // Seek video first so frame display responds quickly.
191
+ await this.videoRenderer.seek(targetTime);
192
+
193
+ // If a newer seek arrived while video seek was running, skip this audio seek.
194
+ if (requestIdAtStart !== this.seekRequestId) {
195
+ continue;
196
+ }
197
+
198
+ await this.audioManager.seek(targetTime);
199
+ }
200
+ } finally {
201
+ this.isSeeking = false;
202
+ }
203
+
204
+ // Handle race where a seek arrived after loop exit but before isSeeking was reset.
205
+ if (this.pendingSeekTime !== null) {
206
+ await this.processPendingSeeks();
207
+ }
173
208
  }
174
209
 
175
210
  private startRenderLoop(): void {
@@ -182,7 +217,9 @@ export class PlaybackController {
182
217
  if (!this.playing) return;
183
218
 
184
219
  // Get accurate time from audio manager if available
185
- if (this.audioManager.isPlaying()) {
220
+ if (this.isSeeking) {
221
+ // Keep requested seek time stable while async seek operations settle.
222
+ } else if (this.audioManager.isPlaying()) {
186
223
  this.currentTime = this.audioManager.getCurrentTime();
187
224
  } else {
188
225
  // Fallback to manual time tracking
@@ -199,7 +236,7 @@ export class PlaybackController {
199
236
  }
200
237
 
201
238
  // Update video frame synchronously
202
- const { isStarving } = this.videoRenderer.updateFrame(this.currentTime);
239
+ const { isStarving } = this.videoRenderer.updateFrame(this.currentTime, this.isSeeking);
203
240
 
204
241
  // Handle buffering state changes
205
242
  if (isStarving && !this.isWaiting) {
@@ -267,7 +304,7 @@ export class PlaybackController {
267
304
  }
268
305
 
269
306
  getCurrentTime(): number {
270
- if (this.playing && this.audioManager.isPlaying()) {
307
+ if (this.playing && !this.isSeeking && this.audioManager.isPlaying()) {
271
308
  return this.audioManager.getCurrentTime();
272
309
  }
273
310
  return this.currentTime;
@@ -427,10 +464,16 @@ export class PlaybackController {
427
464
  // Reset playback rate to default
428
465
  this.playbackRate = 1;
429
466
  this.lastFrameTime = 0;
467
+ this.seekRequestId++;
468
+ this.pendingSeekTime = null;
469
+ this.isSeeking = false;
430
470
  }
431
471
 
432
472
  dispose(): void {
433
473
  this.pause();
474
+ this.seekRequestId++;
475
+ this.pendingSeekTime = null;
476
+ this.isSeeking = false;
434
477
  this.videoRenderer.dispose();
435
478
  this.audioManager.dispose();
436
479
  this.onTimeUpdate = undefined;
@@ -40,6 +40,8 @@ export interface VideoRendererOptions {
40
40
 
41
41
  export class VideoRenderer {
42
42
  private canvas: HTMLCanvasElement | OffscreenCanvas | null = null;
43
+ private seekDebounceTimer: number | null = null;
44
+ private pendingSeekTime: number | null = null;
43
45
  private canvasSink: CanvasSink | null = null;
44
46
  private sampleSink: VideoSampleSink | null = null;
45
47
  private options: VideoRendererOptions;
@@ -48,6 +50,7 @@ export class VideoRenderer {
48
50
  private nextFrame: WrappedCanvas | null = null;
49
51
  private disposed = false;
50
52
  private renderingId = 0;
53
+ private currentSeekId = 0;
51
54
  private renderer: IRenderer | null = null;
52
55
  private rendererType: RendererType = 'canvas2d';
53
56
  private onRendererChange?: (type: RendererType) => void;
@@ -546,6 +549,8 @@ export class VideoRenderer {
546
549
  }
547
550
 
548
551
  async seek(timestamp: number): Promise<void> {
552
+ this.cancelPendingDebouncedSeek();
553
+
549
554
  if (!this.canvasSink) {
550
555
  return;
551
556
  }
@@ -553,6 +558,10 @@ export class VideoRenderer {
553
558
  this.renderingId++;
554
559
  const currentRenderingId = this.renderingId;
555
560
 
561
+ // Increment seek ID to cancel any in-progress seek
562
+ this.currentSeekId++;
563
+ const seekId = this.currentSeekId;
564
+
556
565
  // Dispose current iterator
557
566
  if (this.frameIterator) {
558
567
  try {
@@ -563,47 +572,165 @@ export class VideoRenderer {
563
572
  this.frameIterator = null;
564
573
  }
565
574
 
566
- // Create a new iterator starting from the timestamp
567
- const iterator = this.canvasSink.canvases(timestamp);
568
- this.frameIterator = iterator;
575
+ // Clear current frames to ensure we don't show stale data
576
+ this.currentFrame = null;
577
+ this.nextFrame = null;
569
578
 
570
579
  try {
571
- // Get the first two frames
572
- const firstResult = await iterator.next();
573
- const secondResult = await iterator.next();
580
+ // Strategy: Look backwards from the seek time to find the frame that should be displayed
581
+ // Video frames are typically decoded from keyframes, so we need to find the frame
582
+ // whose timestamp is at or just before the seek time
583
+ let targetFrame: WrappedCanvas | null = null;
584
+ let nextFrame: WrappedCanvas | null = null;
585
+ const SEEK_FRAME_MATCH_TOLERANCE = 0.001;
586
+
587
+ // First, try to get a frame slightly before the target to find the correct display frame
588
+ const lookbehindTime = Math.max(0, timestamp - 2);
589
+ const lookbehindIterator = this.canvasSink.canvases(lookbehindTime);
590
+
591
+ try {
592
+ // Iterate through frames until we find the one that should be displayed at target time
593
+ // This is the frame with timestamp <= target and next frame has timestamp > target
594
+ let previousFrame: WrappedCanvas | null = null;
595
+
596
+ for await (const frame of lookbehindIterator) {
597
+ // Check if a new seek has been triggered - if so, abort this one
598
+ if (seekId !== this.currentSeekId) {
599
+ return;
600
+ }
601
+
602
+ if (frame.timestamp <= timestamp) {
603
+ // This frame is at or before the target - it's a candidate
604
+ previousFrame = frame;
605
+ } else {
606
+ // This frame is after the target, so the previous frame is the one we want
607
+ nextFrame = frame;
608
+ break;
609
+ }
610
+
611
+ // Safety limit - don't iterate too far
612
+ if (frame.timestamp > timestamp + 5) {
613
+ break;
614
+ }
615
+ }
616
+
617
+ targetFrame = previousFrame;
618
+ } catch {
619
+ // Iterator error
620
+ } finally {
621
+ try {
622
+ await lookbehindIterator.return();
623
+ } catch {
624
+ // Iterator may already be closed
625
+ }
626
+ }
574
627
 
575
- if (currentRenderingId !== this.renderingId) {
628
+ // Check again if a new seek was triggered during iteration
629
+ if (seekId !== this.currentSeekId) {
576
630
  return;
577
631
  }
578
632
 
579
- const firstFrame = firstResult.value ?? null;
580
- const secondFrame = secondResult.value ?? null;
633
+ // If we didn't find a frame looking backwards, try forward
634
+ if (!targetFrame) {
635
+ const forwardIterator = this.canvasSink.canvases(timestamp);
636
+ try {
637
+ const result = await forwardIterator.next();
638
+ // Check for cancellation
639
+ if (seekId !== this.currentSeekId) {
640
+ return;
641
+ }
642
+ if (result.value) {
643
+ targetFrame = result.value;
644
+ }
645
+ } catch {
646
+ // Iterator error
647
+ } finally {
648
+ try {
649
+ await forwardIterator.return();
650
+ } catch {
651
+ // Iterator may already be closed
652
+ }
653
+ }
654
+ }
581
655
 
582
- // Store the frame first
583
- if (firstFrame) {
584
- this.currentFrame = firstFrame;
656
+ if (currentRenderingId !== this.renderingId || this.disposed) {
657
+ return;
658
+ }
585
659
 
586
- // Draw the first frame immediately if canvas has dimensions
587
- if (firstFrame.canvas.width > 0 && firstFrame.canvas.height > 0) {
588
- this.renderFrame(firstFrame);
660
+ // Final cancellation check before setting up the frame
661
+ if (seekId !== this.currentSeekId) {
662
+ return;
663
+ }
664
+
665
+ // Set up the frame if we found one
666
+ if (targetFrame) {
667
+ this.currentFrame = targetFrame;
668
+ this.nextFrame = nextFrame;
669
+
670
+ // Draw the frame immediately if canvas has dimensions
671
+ if (targetFrame.canvas.width > 0 && targetFrame.canvas.height > 0) {
672
+ this.renderFrame(targetFrame);
589
673
  } else {
590
- this.retryUntilCanvasReady(firstFrame, () => this.renderFrame(firstFrame), 30);
674
+ this.retryUntilCanvasReady(targetFrame, () => this.renderFrame(targetFrame), 30);
675
+ }
676
+
677
+ // Set up iterator for continued playback from current frame position
678
+ const playbackIterator = this.canvasSink.canvases(targetFrame.timestamp);
679
+ this.frameIterator = playbackIterator;
680
+
681
+ let firstFrameAfterRestart: WrappedCanvas | null = null;
682
+ try {
683
+ const first = await playbackIterator.next();
684
+ // Check for cancellation
685
+ if (seekId !== this.currentSeekId) {
686
+ try {
687
+ await playbackIterator.return();
688
+ } catch {
689
+ // Iterator may already be closed
690
+ }
691
+ if (this.frameIterator === playbackIterator) {
692
+ this.frameIterator = null;
693
+ }
694
+ return;
695
+ }
696
+ firstFrameAfterRestart = first.value ?? null;
697
+ } catch {
698
+ // Iterator error
591
699
  }
592
- }
593
700
 
594
- // Store the second frame for later
595
- this.nextFrame = secondFrame;
701
+ if (currentRenderingId !== this.renderingId || this.disposed) {
702
+ try {
703
+ await playbackIterator.return();
704
+ } catch {
705
+ // Iterator may already be closed
706
+ }
707
+ if (this.frameIterator === playbackIterator) {
708
+ this.frameIterator = null;
709
+ }
710
+ return;
711
+ }
596
712
 
597
- // If we don't have a next frame yet, try to fetch one
598
- if (!this.nextFrame) {
599
- void this.fetchNextFrame();
713
+ // Only skip the first iterator frame if it matches the currently rendered frame.
714
+ // If it is already ahead, keep it as the next frame so playback doesn't jump.
715
+ if (
716
+ firstFrameAfterRestart &&
717
+ firstFrameAfterRestart.timestamp > targetFrame.timestamp + SEEK_FRAME_MATCH_TOLERANCE &&
718
+ (!this.nextFrame || firstFrameAfterRestart.timestamp < this.nextFrame.timestamp)
719
+ ) {
720
+ this.nextFrame = firstFrameAfterRestart;
721
+ }
722
+
723
+ // Get next frame if we don't have one
724
+ if (!this.nextFrame) {
725
+ void this.fetchNextFrame();
726
+ }
600
727
  }
601
728
  } catch {
602
729
  // Iterator was closed or disposed during seek
603
730
  }
604
731
  }
605
732
 
606
- updateFrame(currentTime: number): { frameUpdated: boolean; isStarving: boolean } {
733
+ updateFrame(currentTime: number, isSeeking: boolean = false): { frameUpdated: boolean; isStarving: boolean } {
607
734
  const result = this.updateFrameResult;
608
735
 
609
736
  if (this.disposed) {
@@ -612,6 +739,16 @@ export class VideoRenderer {
612
739
  return result;
613
740
  }
614
741
 
742
+ // Special case: If we have a current frame but it's timestamp is far in the future,
743
+ // it means we seeked to a frame that's ahead of playback. Don't advance frames
744
+ // until currentTime catches up to the current frame's timestamp.
745
+ if (this.currentFrame && this.currentFrame.timestamp > currentTime + 0.1) {
746
+ // Current frame is in the future, don't update yet
747
+ result.frameUpdated = false;
748
+ result.isStarving = false;
749
+ return result;
750
+ }
751
+
615
752
  // If we don't have a next frame, request one (if iterator exists)
616
753
  // This is frame starvation - we're playing but have no frame ready
617
754
  if (!this.nextFrame) {
@@ -623,8 +760,32 @@ export class VideoRenderer {
623
760
  return result;
624
761
  }
625
762
 
763
+ // Check if we're way behind (>1 second) - trigger debounced seek to catch up
764
+ if (this.nextFrame.timestamp < currentTime - 1.0) {
765
+ // We're more than 1 second behind - need to seek to catch up
766
+ this.pendingSeekTime = currentTime;
767
+
768
+ if (this.seekDebounceTimer === null && !isSeeking) {
769
+ this.seekDebounceTimer = window.setTimeout(() => {
770
+ const seekTime = this.pendingSeekTime;
771
+ this.seekDebounceTimer = null;
772
+ this.pendingSeekTime = null;
773
+
774
+ if (seekTime !== null && !this.disposed) {
775
+ void this.seek(seekTime);
776
+ }
777
+ }, 100); // Wait 100ms before seeking to batch multiple "behind" detections
778
+ }
779
+
780
+ result.frameUpdated = false;
781
+ result.isStarving = false;
782
+ return result;
783
+ }
784
+
626
785
  // Check if the current playback time has caught up to the next frame
627
- if (this.nextFrame.timestamp <= currentTime) {
786
+ // Use a small tolerance to handle timing precision issues
787
+ const FRAME_DISPLAY_TOLERANCE = 0.016; // ~1 frame at 60fps
788
+ if (this.nextFrame.timestamp <= currentTime + FRAME_DISPLAY_TOLERANCE) {
628
789
  // Store the frame first
629
790
  this.currentFrame = this.nextFrame;
630
791
  this.nextFrame = null;
@@ -646,22 +807,37 @@ export class VideoRenderer {
646
807
  return result;
647
808
  }
648
809
 
649
- private async fetchNextFrame(): Promise<void> {
810
+ private async fetchNextFrame(currentTime?: number): Promise<void> {
650
811
  const iterator = this.frameIterator;
651
812
  if (!iterator || this.disposed) return;
652
813
 
653
814
  const currentRenderingId = this.renderingId;
654
815
 
655
816
  try {
656
- // Get the next frame from iterator
657
- const result = await iterator.next();
658
- const frame = result.value ?? null;
817
+ let frame: WrappedCanvas | null = null;
818
+ let result = await iterator.next();
819
+ frame = result.value ?? null;
659
820
 
660
821
  if (!frame || currentRenderingId !== this.renderingId || this.disposed) {
661
822
  return;
662
823
  }
663
824
 
664
- // Store the frame for later use
825
+ // If we have currentTime and this frame is way behind, skip frames
826
+ if (currentTime !== undefined) {
827
+ const SKIP_THRESHOLD = 0.1; // Skip if more than 100ms behind
828
+
829
+ while (frame && frame.timestamp < currentTime - SKIP_THRESHOLD) {
830
+ result = await iterator.next();
831
+ const nextFrame = result.value ?? null;
832
+
833
+ if (!nextFrame || currentRenderingId !== this.renderingId || this.disposed) {
834
+ break;
835
+ }
836
+
837
+ frame = nextFrame;
838
+ }
839
+ }
840
+
665
841
  this.nextFrame = frame;
666
842
  } catch {
667
843
  // Iterator was closed or disposed during fetch
@@ -1110,6 +1286,7 @@ export class VideoRenderer {
1110
1286
  */
1111
1287
  async clearIterators(): Promise<void> {
1112
1288
  this.renderingId++;
1289
+ this.cancelPendingDebouncedSeek();
1113
1290
 
1114
1291
  if (this.frameIterator) {
1115
1292
  try {
@@ -1127,6 +1304,7 @@ export class VideoRenderer {
1127
1304
  private async disposeVideoResources(): Promise<void> {
1128
1305
  this.disposed = true;
1129
1306
  this.renderingId++;
1307
+ this.cancelPendingDebouncedSeek();
1130
1308
 
1131
1309
  if (this.frameIterator) {
1132
1310
  try {
@@ -1147,6 +1325,7 @@ export class VideoRenderer {
1147
1325
  dispose(): void {
1148
1326
  this.disposed = true;
1149
1327
  this.renderingId++;
1328
+ this.cancelPendingDebouncedSeek();
1150
1329
 
1151
1330
  if (this.frameIterator) {
1152
1331
  // fire-and-forget – safe cleanup without throwing
@@ -1173,4 +1352,13 @@ export class VideoRenderer {
1173
1352
  this.onRendererFallback = undefined;
1174
1353
  // Track reference cleared through dispose of iterators
1175
1354
  }
1355
+
1356
+ private cancelPendingDebouncedSeek(): void {
1357
+ if (this.seekDebounceTimer !== null) {
1358
+ clearTimeout(this.seekDebounceTimer);
1359
+ }
1360
+
1361
+ this.seekDebounceTimer = null;
1362
+ this.pendingSeekTime = null;
1363
+ }
1176
1364
  }