@mediafox/core 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +326 -0
- package/dist/core/player-core.d.ts +27 -0
- package/dist/core/player-core.d.ts.map +1 -0
- package/dist/core/state-facade.d.ts +25 -0
- package/dist/core/state-facade.d.ts.map +1 -0
- package/dist/core/track-switcher.d.ts +29 -0
- package/dist/core/track-switcher.d.ts.map +1 -0
- package/dist/events/emitter.d.ts +18 -0
- package/dist/events/emitter.d.ts.map +1 -0
- package/dist/events/types.d.ts +16 -0
- package/dist/events/types.d.ts.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +40 -0
- package/dist/mediafox.d.ts +72 -0
- package/dist/mediafox.d.ts.map +1 -0
- package/dist/playback/audio.d.ts +47 -0
- package/dist/playback/audio.d.ts.map +1 -0
- package/dist/playback/controller.d.ts +70 -0
- package/dist/playback/controller.d.ts.map +1 -0
- package/dist/playback/renderer.d.ts +53 -0
- package/dist/playback/renderer.d.ts.map +1 -0
- package/dist/playback/renderers/canvas2d.d.ts +16 -0
- package/dist/playback/renderers/canvas2d.d.ts.map +1 -0
- package/dist/playback/renderers/factory.d.ts +25 -0
- package/dist/playback/renderers/factory.d.ts.map +1 -0
- package/dist/playback/renderers/index.d.ts +6 -0
- package/dist/playback/renderers/index.d.ts.map +1 -0
- package/dist/playback/renderers/types.d.ts +40 -0
- package/dist/playback/renderers/types.d.ts.map +1 -0
- package/dist/playback/renderers/webgl.d.ts +32 -0
- package/dist/playback/renderers/webgl.d.ts.map +1 -0
- package/dist/playback/renderers/webgpu.d.ts +32 -0
- package/dist/playback/renderers/webgpu.d.ts.map +1 -0
- package/dist/sources/manager.d.ts +17 -0
- package/dist/sources/manager.d.ts.map +1 -0
- package/dist/sources/types.d.ts +14 -0
- package/dist/sources/types.d.ts.map +1 -0
- package/dist/state/store.d.ts +32 -0
- package/dist/state/store.d.ts.map +1 -0
- package/dist/state/types.d.ts +10 -0
- package/dist/state/types.d.ts.map +1 -0
- package/dist/tracks/manager.d.ts +45 -0
- package/dist/tracks/manager.d.ts.map +1 -0
- package/dist/tracks/types.d.ts +26 -0
- package/dist/tracks/types.d.ts.map +1 -0
- package/dist/types.d.ts +196 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils/async-lock.d.ts +5 -0
- package/dist/utils/async-lock.d.ts.map +1 -0
- package/dist/utils/dispose.d.ts +11 -0
- package/dist/utils/dispose.d.ts.map +1 -0
- package/dist/utils/equal.d.ts +2 -0
- package/dist/utils/equal.d.ts.map +1 -0
- package/dist/utils/errors.d.ts +30 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/logger.d.ts +23 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/time.d.ts +83 -0
- package/dist/utils/time.d.ts.map +1 -0
- package/package.json +61 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
class _{events=new Map;maxListeners;captureRejections;constructor(S={}){this.maxListeners=S.maxListeners??10,this.captureRejections=S.captureRejections??!1}on(S,A){if(!this.events.has(S))this.events.set(S,new Set);let O=this.events.get(S);if(!O)return()=>{};if(O.size>=this.maxListeners)console.warn(`MaxListenersExceededWarning: Possible EventEmitter memory leak detected. ${O.size} ${String(S)} listeners added. Use emitter.setMaxListeners() to increase limit`);let V=A;return O.add(V),()=>{O.delete(V)}}once(S,A){let O=(V)=>{this.off(S,O),A(V)};return this.on(S,O)}off(S,A){let O=this.events.get(S);if(!O)return;if(A){let V=A;O.delete(V)}else O.clear()}emit(S,A){let O=this.events.get(S);if(!O||O.size===0)return;for(let V of O)try{let $=V(A);if(this.captureRejections&&o($))$.catch((P)=>{if(this.events.has("error"))this.emit("error",P);else throw P})}catch($){if(this.captureRejections&&this.events.has("error"))this.emit("error",$);else throw $}}removeAllListeners(S){if(S)this.events.delete(S);else this.events.clear()}setMaxListeners(S){this.maxListeners=S}getMaxListeners(){return this.maxListeners}listeners(S){let A=this.events.get(S);return A?Array.from(A):[]}listenerCount(S){let A=this.events.get(S);return A?A.size:0}eventNames(){return Array.from(this.events.keys())}}function o(S){if(!S||typeof S!=="object"&&typeof S!=="function")return!1;let A=S;return typeof A.then==="function"&&typeof A.catch==="function"}var q=2,M="[MediaFox]";function d(S){q=S}function c(S,...A){if(q<=0)console.debug(`${M} ${S}`,...A)}function n(S,...A){if(q<=1)console.info(`${M} ${S}`,...A)}function i(S,...A){if(q<=2)console.warn(`${M} ${S}`,...A)}function s(S,...A){if(q<=3)console.error(`${M} ${S}`,...A)}var B={setLevel:d,debug:c,info:n,warn:i,error:s};class H{deps;constructor(S){this.deps=S}async load(S,A={}){try{this.deps.state.reset(),this.deps.state.updateLoadingState(),this.deps.emit("loadstart",void 0);let V=(await this.deps.sourceManager.createSource(S)).input;if(!V)throw Error("Failed to create input from source");await this.deps.trackManager.initialize(V);let[$,P,j,D]=await Promise.all([V.computeDuration(),V.getFormat(),V.getMimeType(),V.getMetadataTags()]),J={duration:$,format:P.name,mimeType:j,metadata:D,hasVideo:this.deps.trackManager.hasVideo(),hasAudio:this.deps.trackManager.hasAudio(),hasSubtitles:this.deps.trackManager.hasSubtitles()};this.deps.state.updateDuration($),this.deps.state.updateMediaInfo(J),this.deps.state.updateTracks(this.deps.trackManager.getVideoTracks(),this.deps.trackManager.getAudioTracks(),this.deps.trackManager.getSubtitleTracks()),this.deps.playbackController.setDuration($);let K=this.deps.trackManager.getPrimaryVideoTrack(),Y=this.deps.trackManager.getPrimaryAudioTrack(),Q="",z=!1,X=!1;if(K||Y){let Z=await this.deps.trackSwitcher.setupInitialTracks(K,Y);Q+=Z.warningMessage,z=Z.videoSupported,X=Z.audioSupported}if(!z&&!X){if(!Q)Q="No audio or video track found.";throw Error(Q)}if(Q&&(z||X))this.deps.emit("warning",{type:"codec-warning",message:Q.trim(),error:void 0});if(this.deps.state.updateReadyState(!0,!0),this.deps.emit("loadedmetadata",J),this.deps.emit("loadeddata",void 0),this.deps.emit("canplay",void 0),this.deps.emit("canplaythrough",void 0),A.autoplay)await this.play();if(A.startTime!==void 0)await this.seek(A.startTime)}catch(O){throw this.handleError(O),O}}async play(){try{if(this.deps.state.getState().state==="idle")throw Error("No media loaded");await this.deps.playbackController.play(),this.deps.state.updatePlaybackState(!0),this.deps.emit("play",void 0),this.deps.emit("playing",void 0)}catch(S){throw this.handleError(S),S}}pause(){this.deps.playbackController.pause(),this.deps.state.updatePlaybackState(!1),this.deps.emit("pause",void 0)}async seek(S){try{if(this.deps.state.getState().state==="idle")throw Error("No media loaded");this.deps.state.updateSeekingState(!0),this.deps.emit("seeking",{currentTime:S}),await this.deps.playbackController.seek(S),this.deps.state.updateSeekingState(!1),this.deps.state.updateTime(this.deps.playbackController.getCurrentTime()),this.deps.emit("seeked",{currentTime:this.deps.playbackController.getCurrentTime()})}catch(A){throw this.deps.state.updateSeekingState(!1),this.handleError(A),A}}async stop(){try{this.pause(),await this.seek(0)}catch(S){throw this.handleError(S),S}}handleError(S){this.deps.state.updateError(S),this.deps.emit("error",S),B.error("Player error:",S)}}class W{store;constructor(S){this.store=S}getState(){return this.store.getState()}subscribe(S){return this.store.subscribe(S)}reset(){this.store.reset()}applyInitial(S,A,O){this.store.setState({volume:S,muted:A,playbackRate:O})}updateLoadingState(){this.store.updateLoadingState()}updateReadyState(S,A){this.store.updateReadyState(S,A)}updatePlaybackState(S){this.store.updatePlaybackState(S)}updateSeekingState(S){this.store.updateSeekingState(S)}updateEndedState(S){this.store.updateEndedState(S)}updateTime(S){this.store.updateTime(S)}updateDuration(S){this.store.updateDuration(S)}updateVolume(S,A){this.store.updateVolume(S,A)}updatePlaybackRate(S){this.store.updatePlaybackRate(S)}updateMediaInfo(S){this.store.updateMediaInfo(S)}updateTracks(S,A,O){this.store.updateTracks(S,A,O)}updateSelectedTracks(S,A){this.store.updateSelectedTracks(S,A)}updateError(S){this.store.updateError(S)}updateRendererType(S){this.store.updateRendererType(S)}}class C{chains=new Map;async run(S,A){let O=this.chains.get(S)??Promise.resolve(),V,$=new Promise((P)=>{V=P});this.chains.set(S,O.then(()=>$));try{return await O,await A()}finally{V?.()}}}class T{deps;locks=new C;constructor(S){this.deps=S}async setupInitialTracks(S,A){let O=!1,V=!1,$="";if(S)try{if(O=await this.locks.run("video",async()=>{if(S.codec!==null&&await S.canDecode())return await this.deps.playbackController.trySetVideoTrack(S);return!1}),!O)$+="Unsupported video codec. "}catch(P){$+="Failed to set up video track. ",B.warn("Video track error:",P)}if(A)try{if(V=await this.locks.run("audio",async()=>{if(A.codec!==null&&await A.canDecode())return await this.deps.playbackController.trySetAudioTrack(A);return!1}),!V)$+="Unsupported audio codec. "}catch(P){$+="Failed to set up audio track. ",B.warn("Audio track error:",P)}if(!O&&!V&&!$)$="No audio or video track found.";return{videoSupported:O,audioSupported:V,warningMessage:$}}async selectVideoTrack(S,A){if(!S.selectVideoTrack(A))throw Error(`Invalid video track ID: ${A}`);let O=S.getSelectedVideoTrack();if(!O){await this.deps.playbackController.setVideoTrack(null);return}if(!await this.locks.run("video",async()=>{if(O.codec!==null&&await O.canDecode())return await this.deps.playbackController.trySetVideoTrack(O);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(S,A){if(!S.selectAudioTrack(A))throw Error(`Invalid audio track ID: ${A}`);let O=S.getSelectedAudioTrack();if(!O){await this.deps.playbackController.setAudioTrack(null);return}if(!await this.locks.run("audio",async()=>{if(O.codec!==null&&await O.canDecode())return await this.deps.playbackController.trySetAudioTrack(O);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 t,AudioSampleSink as a}from"mediabunny";class f{audioContext;gainNode=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;constructor(S={}){if(S.audioContext)this.audioContext=S.audioContext;else{let A=window,O=A.AudioContext||A.webkitAudioContext;this.audioContext=new O}this.volume=S.volume??1,this.muted=S.muted??!1,this.setupAudioGraph()}setupAudioGraph(){this.gainNode=this.audioContext.createGain(),this.gainNode.connect(this.audioContext.destination),this.updateGain()}async setAudioTrack(S){if(this.dispose(),S.codec===null)throw Error("Unsupported audio codec");if(!await S.canDecode())throw Error(`Cannot decode audio track with codec: ${S.codec}`);this.bufferSink=new t(S),this.sampleSink=new a(S),this.disposed=!1}async play(S=this.pauseTime){if(this.playing||!this.bufferSink)return;if(this.audioContext.state==="suspended")await this.audioContext.resume();this.playbackId++;let A=this.playbackId;this.playing=!0,this.startContextTime=this.audioContext.currentTime,this.startMediaTime=S,this.pauseTime=S,this.bufferIterator=this.bufferSink.buffers(S),this.scheduleAudioBuffers(A)}async scheduleAudioBuffers(S){if(!this.bufferIterator||!this.gainNode)return;try{for await(let{buffer:A,timestamp:O}of this.bufferIterator){if(S!==this.playbackId||this.disposed||!this.playing)break;let V=this.audioContext.createBufferSource();V.buffer=A,V.connect(this.gainNode),V.playbackRate.value=this.playbackRate,V.playbackRate.setValueAtTime(this.playbackRate,this.audioContext.currentTime);let $=this.startContextTime+(O-this.startMediaTime)/this.playbackRate;if($>=this.audioContext.currentTime)V.start($);else{let P=Math.max(0,(this.audioContext.currentTime-$)*this.playbackRate);if(P<A.duration)V.start(this.audioContext.currentTime,P);else continue}if(this.queuedNodes.add(V),V.onended=()=>{this.queuedNodes.delete(V)},O-this.getCurrentTime()>=1)await this.waitForCatchup(O)}}catch(A){console.error("Error scheduling audio buffers:",A)}}async waitForCatchup(S){return new Promise((A)=>{let O=setInterval(()=>{if(S-this.getCurrentTime()<1||!this.playing)clearInterval(O),A()},100)})}pause(){if(!this.playing)return;let S=this.getCurrentTime();if(this.playing=!1,this.pauseTime=S,this.stopQueuedNodes(),this.bufferIterator)this.bufferIterator.return(),this.bufferIterator=null}stop(){this.pause(),this.pauseTime=0,this.startContextTime=0,this.startMediaTime=0}async seek(S){let A=this.playing;if(A)this.pause();if(this.pauseTime=S,A)await this.play(S)}getCurrentTime(){if(this.playing){let S=this.audioContext.currentTime-this.startContextTime;return this.startMediaTime+S*this.playbackRate}return this.pauseTime}setVolume(S){this.volume=Math.max(0,Math.min(1,S)),this.updateGain()}setMuted(S){this.muted=S,this.updateGain()}updateGain(){if(!this.gainNode)return;let S=this.muted?0:this.volume;this.gainNode.gain.value=S*S}getVolume(){return this.volume}isMuted(){return this.muted}isPlaying(){return this.playing}setPlaybackRate(S){let A=Math.max(0.25,Math.min(4,S));if(this.playbackRate===A)return;let O=this.playing,V=this.getCurrentTime();if(this.playbackRate=A,O)this.pause(),this.pauseTime=V,this.play(V)}getAudioContext(){return this.audioContext}async getBufferAt(S){if(!this.bufferSink)return null;return this.bufferSink.getBuffer(S)}async getSampleAt(S){if(!this.sampleSink)return null;return this.sampleSink.getSample(S)}stopQueuedNodes(){for(let S of this.queuedNodes)try{S.stop()}catch{}this.queuedNodes.clear()}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()}}import{CanvasSink as r,VideoSampleSink as e}from"mediabunny";class G{canvas;ctx=null;isInitialized=!1;constructor(S){this.canvas=S.canvas,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(S){if(!this.isReady()||!this.ctx)return!1;try{let{width:A,height:O}=S;if(A===0||O===0)return!1;let V=this.canvas.width,$=this.canvas.height,P=Math.min(V/A,$/O),j=Math.floor(A*P),D=Math.floor(O*P),J=Math.floor((V-j)/2),K=Math.floor(($-D)/2);return this.ctx.clearRect(0,0,V,$),this.ctx.drawImage(S,0,0,A,O,J,K,j,D),!0}catch{return!1}}clear(){if(!this.isReady()||!this.ctx)return;this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height)}dispose(){this.ctx=null,this.isInitialized=!1}}class I{resources;isInitialized=!1;canvas;textureWidth=0;textureHeight=0;options;boundHandleContextLost=null;boundHandleContextRestored=null;vertexShaderSource=`
|
|
2
|
+
attribute vec2 a_position;
|
|
3
|
+
attribute vec2 a_texCoord;
|
|
4
|
+
varying vec2 v_texCoord;
|
|
5
|
+
|
|
6
|
+
void main() {
|
|
7
|
+
gl_Position = vec4(a_position, 0.0, 1.0);
|
|
8
|
+
v_texCoord = a_texCoord;
|
|
9
|
+
}
|
|
10
|
+
`;fragmentShaderSource=`
|
|
11
|
+
precision mediump float;
|
|
12
|
+
uniform sampler2D u_texture;
|
|
13
|
+
varying vec2 v_texCoord;
|
|
14
|
+
|
|
15
|
+
void main() {
|
|
16
|
+
vec4 color = texture2D(u_texture, v_texCoord);
|
|
17
|
+
gl_FragColor = color;
|
|
18
|
+
}
|
|
19
|
+
`;constructor(S){this.canvas=S.canvas,this.options=S,this.resources={gl:null,program:null,texture:null,vertexBuffer:null,texCoordBuffer:null,positionLocation:-1,texCoordLocation:-1,textureLocation:null},this.initialize()}initialize(){try{let S={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"},A=this.canvas.getContext("webgl",S);if(!A&&"getContext"in this.canvas)A=this.canvas.getContext("experimental-webgl",S);if(!A)return!1;this.resources.gl=A;let O=this.createShader(A,A.VERTEX_SHADER,this.vertexShaderSource),V=this.createShader(A,A.FRAGMENT_SHADER,this.fragmentShaderSource);if(!O||!V)throw Error("Failed to create shaders");let $=A.createProgram();if(!$)throw Error("Failed to create program");if(A.attachShader($,O),A.attachShader($,V),A.linkProgram($),!A.getProgramParameter($,A.LINK_STATUS)){let j=A.getProgramInfoLog($);throw Error(`Failed to link program: ${j}`)}this.resources.program=$,this.resources.positionLocation=A.getAttribLocation($,"a_position"),this.resources.texCoordLocation=A.getAttribLocation($,"a_texCoord"),this.resources.textureLocation=A.getUniformLocation($,"u_texture"),this.setupQuadBuffers(A);let P=A.createTexture();if(!P)throw Error("Failed to create texture");if(A.bindTexture(A.TEXTURE_2D,P),A.texParameteri(A.TEXTURE_2D,A.TEXTURE_WRAP_S,A.CLAMP_TO_EDGE),A.texParameteri(A.TEXTURE_2D,A.TEXTURE_WRAP_T,A.CLAMP_TO_EDGE),A.texParameteri(A.TEXTURE_2D,A.TEXTURE_MIN_FILTER,A.LINEAR),A.texParameteri(A.TEXTURE_2D,A.TEXTURE_MAG_FILTER,A.LINEAR),this.resources.texture=P,A.disable(A.DEPTH_TEST),A.disable(A.CULL_FACE),A.disable(A.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(S,A,O){let V=S.createShader(A);if(!V)return null;if(S.shaderSource(V,O),S.compileShader(V),!S.getShaderParameter(V,S.COMPILE_STATUS))return S.deleteShader(V),null;return V}setupQuadBuffers(S){let A=new Float32Array([-1,-1,1,-1,-1,1,1,1]),O=new Float32Array([0,1,1,1,0,0,1,0]),V=S.createBuffer();S.bindBuffer(S.ARRAY_BUFFER,V),S.bufferData(S.ARRAY_BUFFER,A,S.STATIC_DRAW),this.resources.vertexBuffer=V;let $=S.createBuffer();S.bindBuffer(S.ARRAY_BUFFER,$),S.bufferData(S.ARRAY_BUFFER,O,S.STATIC_DRAW),this.resources.texCoordBuffer=$}isReady(){return this.isInitialized&&this.resources.gl!==null}render(S){if(!this.isInitialized||!this.resources.gl)return!1;let A=this.resources.gl;try{let{width:O,height:V}=S;if(O===0||V===0)return!1;let $=this.canvas.width,P=this.canvas.height;if(A.viewport(0,0,$,P),A.bindTexture(A.TEXTURE_2D,this.resources.texture),O!==this.textureWidth||V!==this.textureHeight)A.texImage2D(A.TEXTURE_2D,0,A.RGBA,A.RGBA,A.UNSIGNED_BYTE,S),this.textureWidth=O,this.textureHeight=V;else A.texSubImage2D(A.TEXTURE_2D,0,0,0,A.RGBA,A.UNSIGNED_BYTE,S);A.clearColor(0,0,0,1),A.clear(A.COLOR_BUFFER_BIT);let j=Math.min($/this.textureWidth,P/this.textureHeight),D=Math.floor(this.textureWidth*j),J=Math.floor(this.textureHeight*j),K=Math.floor(($-D)/2),Y=Math.floor((P-J)/2),Q=K/$*2-1,z=(K+D)/$*2-1,X=1-Y/P*2,Z=1-(Y+J)/P*2,L=new Float32Array([Q,Z,z,Z,Q,X,z,X]);return A.bindBuffer(A.ARRAY_BUFFER,this.resources.vertexBuffer),A.bufferData(A.ARRAY_BUFFER,L,A.DYNAMIC_DRAW),A.useProgram(this.resources.program),A.bindBuffer(A.ARRAY_BUFFER,this.resources.vertexBuffer),A.enableVertexAttribArray(this.resources.positionLocation),A.vertexAttribPointer(this.resources.positionLocation,2,A.FLOAT,!1,0,0),A.bindBuffer(A.ARRAY_BUFFER,this.resources.texCoordBuffer),A.enableVertexAttribArray(this.resources.texCoordLocation),A.vertexAttribPointer(this.resources.texCoordLocation,2,A.FLOAT,!1,0,0),A.uniform1i(this.resources.textureLocation,0),A.drawArrays(A.TRIANGLE_STRIP,0,4),!0}catch{return!1}}clear(){if(!this.resources.gl)return;let S=this.resources.gl;S.clearColor(0,0,0,1),S.clear(S.COLOR_BUFFER_BIT)}handleContextLost(S){S.preventDefault(),this.isInitialized=!1}handleContextRestored(){this.initialize()}cleanup(){let S=this.resources.gl;if(!S)return;if(this.resources.texture)S.deleteTexture(this.resources.texture);if(this.resources.vertexBuffer)S.deleteBuffer(this.resources.vertexBuffer);if(this.resources.texCoordBuffer)S.deleteBuffer(this.resources.texCoordBuffer);if(this.resources.program)S.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}dispose(){if(this.resources.gl){let S=this.resources.gl.getExtension("WEBGL_lose_context");if(S)try{S.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 h{canvas;device=null;context=null;pipeline=null;texture=null;sampler=null;bindGroup=null;vertexBuffer=null;isInitialized=!1;textureWidth=0;textureHeight=0;powerPreference;vertexShaderSource=`
|
|
20
|
+
struct VSOut {
|
|
21
|
+
@builtin(position) pos : vec4f,
|
|
22
|
+
@location(0) uv : vec2f,
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
@vertex
|
|
26
|
+
fn vs_main(@location(0) in_pos: vec2f, @location(1) in_uv: vec2f) -> VSOut {
|
|
27
|
+
var out: VSOut;
|
|
28
|
+
out.pos = vec4f(in_pos, 0.0, 1.0);
|
|
29
|
+
out.uv = in_uv;
|
|
30
|
+
return out;
|
|
31
|
+
}
|
|
32
|
+
`;fragmentShaderSource=`
|
|
33
|
+
@group(0) @binding(0) var texture_sampler: sampler;
|
|
34
|
+
@group(0) @binding(1) var texture_view: texture_2d<f32>;
|
|
35
|
+
|
|
36
|
+
@fragment
|
|
37
|
+
fn fs_main(@location(0) uv: vec2f) -> @location(0) vec4f {
|
|
38
|
+
return textureSample(texture_view, texture_sampler, uv);
|
|
39
|
+
}
|
|
40
|
+
`;constructor(S){this.canvas=S.canvas,this.powerPreference=S.powerPreference||"high-performance",this.initialize().catch((A)=>{console.error("WebGPU initialization failed:",A)})}async initialize(){try{let S=navigator;if(!S.gpu)return console.log("WebGPU not available in navigator"),!1;let A=await S.gpu.requestAdapter({powerPreference:this.powerPreference});if(!A)return console.log("WebGPU adapter not available"),!1;if(this.device=await A.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 O=S.gpu.getPreferredCanvasFormat();return this.context.configure({device:this.device,format:O,usage:GPUTextureUsage.RENDER_ATTACHMENT,alphaMode:"opaque"}),await this.createRenderPipeline(),this.createVertexBuffer(),this.isInitialized=!0,console.log("WebGPU renderer initialized successfully"),!0}catch(S){return console.error("WebGPU initialization error:",S),!1}}async createRenderPipeline(){if(!this.device)return;let S=navigator;if(!S.gpu)return;let A=this.device.createShaderModule({code:this.vertexShaderSource}),O=this.device.createShaderModule({code:this.fragmentShaderSource});this.pipeline=this.device.createRenderPipeline({layout:"auto",vertex:{module:A,entryPoint:"vs_main",buffers:[{arrayStride:16,attributes:[{shaderLocation:0,offset:0,format:"float32x2"},{shaderLocation:1,offset:8,format:"float32x2"}]}]},fragment:{module:O,entryPoint:"fs_main",targets:[{format:S.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(S,A){if(!this.device)return;if(this.texture)this.texture.destroy();if(this.texture=this.device.createTexture({size:{width:S,height:A},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(S){if(!this.isReady()||!this.device||!this.context||!this.pipeline)return!1;try{let{width:A,height:O}=S;if(A===0||O===0)return console.warn(`WebGPU: Source canvas has zero dimensions (${A}x${O})`),!1;let V=this.canvas.width,$=this.canvas.height;if(A!==this.textureWidth||O!==this.textureHeight)this.createTexture(A,O),this.textureWidth=A,this.textureHeight=O;if(!this.texture)return!1;try{this.device.queue.copyExternalImageToTexture({source:S},{texture:this.texture},{width:A,height:O})}catch{let p=S.getContext("2d");if(!p)return!1;let l=p.getImageData(0,0,A,O),m=new Uint8Array(l.data.buffer);this.device.queue.writeTexture({texture:this.texture,origin:{x:0,y:0,z:0}},m,{bytesPerRow:A*4,rowsPerImage:O},{width:A,height:O,depthOrArrayLayers:1})}let P=this.device.createCommandEncoder(),j=this.context.getCurrentTexture().createView(),D=P.beginRenderPass({colorAttachments:[{view:j,clearValue:{r:0,g:0,b:0,a:1},loadOp:"clear",storeOp:"store"}]});if(D.setPipeline(this.pipeline),this.bindGroup)D.setBindGroup(0,this.bindGroup);let J=Math.min(V/this.textureWidth,$/this.textureHeight),K=Math.floor(this.textureWidth*J),Y=Math.floor(this.textureHeight*J),Q=Math.floor((V-K)/2),z=Math.floor(($-Y)/2),X=Q/V*2-1,Z=(Q+K)/V*2-1,L=1-z/$*2,u=1-(z+Y)/$*2,g=new Float32Array([X,u,0,1,Z,u,1,1,X,L,0,0,Z,L,1,0]);if(this.vertexBuffer)this.device.queue.writeBuffer(this.vertexBuffer,0,g),D.setVertexBuffer(0,this.vertexBuffer);return D.draw(4,1,0,0),D.end(),this.device.queue.submit([P.finish()]),!0}catch{return!1}}clear(){if(!this.isReady()||!this.device||!this.context)return;try{let S=this.device.createCommandEncoder(),A=this.context.getCurrentTexture().createView();S.beginRenderPass({colorAttachments:[{view:A,clearValue:{r:0,g:0,b:0,a:1},loadOp:"clear",storeOp:"store"}]}).end(),this.device.queue.submit([S.finish()])}catch{}}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 U{canvas;powerPreference;constructor(S){this.canvas=S.canvas,this.powerPreference=S.powerPreference||"high-performance"}async createRenderer(S){try{switch(S){case"webgpu":return await this.createWebGPURenderer();case"webgl":return this.createWebGLRenderer();case"canvas2d":return this.createCanvas2DRenderer();default:return null}}catch{return null}}async createRendererWithFallback(S){let A=[S];if(S!=="webgl")A.push("webgl");if(S!=="canvas2d")A.push("canvas2d");for(let V of A){let $=await this.createRenderer(V);if($?.isReady())return{renderer:$,actualType:V};if($)$.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 A=new h({canvas:this.canvas,powerPreference:this.powerPreference}),O=1000,V=performance.now();if(await(async()=>{while(!A.isReady()){if(performance.now()-V>O)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"),A;return A.isReady()?A:null}createWebGLRenderer(){try{let S=new I({canvas:this.canvas,powerPreference:this.powerPreference,preserveDrawingBuffer:!1,antialias:!1,alpha:!1});return S.isReady()?S:null}catch{return null}}createCanvas2DRenderer(){return new G({canvas:this.canvas})}static getSupportedRenderers(){let S=[];if(navigator.gpu)S.push("webgpu");try{let O=document.createElement("canvas");if(O.getContext("webgl")||O.getContext("experimental-webgl"))S.push("webgl")}catch{}return S.push("canvas2d"),S}static getRendererDisplayName(S){switch(S){case"canvas2d":return"Canvas 2D";case"webgl":return"WebGL";case"webgpu":return"WebGPU";default:return"Unknown"}}static isRendererSupported(S){if(S==="canvas2d")return!0;return U.getSupportedRenderers().includes(S)}}class R{canvas=null;canvasSink=null;sampleSink=null;options;frameIterator=null;currentFrame=null;nextFrame=null;disposed=!1;renderingId=0;renderer=null;rendererType="canvas2d";onRendererChange;onRendererFallback;initPromise=null;constructor(S={}){if(this.options={poolSize:S.poolSize??2,fit:S.fit??"contain",rendererType:S.rendererType??"webgpu",...S},this.rendererType=this.options.rendererType??"webgpu",this.initPromise=null,S.canvas){if(this.canvas=S.canvas,this.options.width)S.canvas.width=this.options.width;if(this.options.height)S.canvas.height=this.options.height;this.initPromise=this.initializeRenderer(S.canvas,this.rendererType).catch((A)=>{console.error("Failed to initialize renderer:",A)})}}async initializeRenderer(S,A){console.log(`Initializing renderer: ${A}`);let V=await new U({canvas:S}).createRendererWithFallback(A);if(console.log(`Renderer factory result: ${V.actualType}`),!V.renderer.isReady())throw console.warn(`VideoRenderer: Renderer (${V.actualType}) not ready`),V.renderer.dispose(),Error(`Failed to initialize renderer: ${V.actualType}`);if(this.renderer=V.renderer,this.rendererType=V.actualType,console.log(`Initialized renderer: ${this.rendererType}`),V.actualType!==A){if(this.onRendererFallback)this.onRendererFallback(A,V.actualType)}if(this.onRendererChange)console.log(`Emitting renderer change: ${this.rendererType}`),this.onRendererChange(this.rendererType);if(this.currentFrame&&this.renderer&&this.renderer.isReady())if(console.log(`Rendering initial frame with ${this.rendererType}`),this.currentFrame.canvas.width===0||this.currentFrame.canvas.height===0){console.log("Initial frame has zero dimensions, scheduling render when ready...");let $=0,P=()=>{if($++,this.currentFrame&&this.currentFrame.canvas.width>0&&this.currentFrame.canvas.height>0)console.log(`Canvas ready (${this.currentFrame.canvas.width}x${this.currentFrame.canvas.height}), rendering initial frame`),this.renderFrame(this.currentFrame);else if($<60)requestAnimationFrame(P);else if(console.warn("Canvas dimensions timeout, forcing render"),this.currentFrame)this.renderFrame(this.currentFrame)};requestAnimationFrame(P)}else this.renderFrame(this.currentFrame)}async setCanvas(S){if(this.canvas=S,this.renderer)this.renderer.dispose(),this.renderer=null;if(this.options.width)S.width=this.options.width;if(this.options.height)S.height=this.options.height;try{await this.initializeRenderer(S,this.rendererType)}catch(A){if(console.error("Failed to initialize renderer:",A),!this.renderer){if(this.renderer=new G({canvas:S}),this.rendererType="canvas2d",this.onRendererChange)this.onRendererChange("canvas2d")}}}async setVideoTrack(S){if(this.disposeVideoResources(),S.codec===null)throw Error("Unsupported video codec");if(!await S.canDecode())throw Error(`Cannot decode video track with codec: ${S.codec}`);if(this.initPromise)try{await this.initPromise}catch(O){console.error("Renderer initialization failed:",O)}if(!this.renderer){if(console.warn("Renderer not ready, creating Canvas2D fallback"),this.canvas){if(this.renderer=new G({canvas:this.canvas}),this.rendererType="canvas2d",this.onRendererChange)this.onRendererChange("canvas2d")}}if(this.canvasSink=new r(S,{width:this.options.width,height:this.options.height,fit:this.options.fit,rotation:this.options.rotation,poolSize:this.options.poolSize}),this.sampleSink=new e(S),this.canvas){if(!this.options.width)this.canvas.width=S.displayWidth;if(!this.options.height)this.canvas.height=S.displayHeight}this.disposed=!1;try{await this.seek(0)}catch(O){console.error("Initial seek failed:",O)}queueMicrotask(()=>{if(this.currentFrame&&this.renderer&&this.renderer.isReady())this.renderFrame(this.currentFrame)})}async seek(S){if(!this.canvasSink)return;this.renderingId++;let A=this.renderingId;if(this.frameIterator)await this.frameIterator.return(),this.frameIterator=null;this.frameIterator=this.canvasSink.canvases(S);let O=await this.frameIterator.next(),V=await this.frameIterator.next();if(A===this.renderingId){let $=O.value??null,P=V.value??null;if($)if(this.currentFrame=$,await new Promise((j)=>setTimeout(j,0)),$.canvas.width===0||$.canvas.height===0){let j=0,D=()=>{if(j++,$.canvas.width>0&&$.canvas.height>0)this.renderFrame($);else if(j<30)requestAnimationFrame(D);else this.renderFrame($)};requestAnimationFrame(D)}else this.renderFrame($);if(this.nextFrame=P,!this.nextFrame)this.fetchNextFrame(S)}}updateFrame(S){if(this.disposed)return!1;if(!this.nextFrame&&this.frameIterator)return this.fetchNextFrame(S),!1;if(!this.nextFrame)return!1;if(this.nextFrame.timestamp<=S)return this.currentFrame=this.nextFrame,this.nextFrame=null,this.renderFrame(this.currentFrame),this.fetchNextFrame(S),!0;return!1}async fetchNextFrame(S){if(!this.frameIterator||this.disposed)return;let A=this.renderingId;while(!0){let V=(await this.frameIterator.next()).value??null;if(!V||A!==this.renderingId||this.disposed)break;if(V.timestamp<=S)this.currentFrame=V,this.renderFrame(V);else{this.nextFrame=V;break}}}renderFrame(S){if(this.currentFrame=S,!this.renderer||!this.canvas){if(this.initPromise)this.initPromise.then(()=>{if(this.currentFrame===S&&this.renderer&&this.renderer.isReady())console.log("Rendering frame after renderer initialization"),this.renderer.render(S.canvas)});return}if(!this.renderer.isReady()){console.warn(`VideoRenderer: Renderer (${this.rendererType}) not ready, skipping frame`);return}if(!this.renderer.render(S.canvas)){if(console.warn(`Failed to render frame with ${this.rendererType} (canvas: ${S.canvas.width}x${S.canvas.height})`),S.canvas.width===0||S.canvas.height===0)requestAnimationFrame(()=>{if(this.currentFrame===S&&this.renderer&&this.renderer.isReady()){if(!this.renderer.render(S.canvas))console.warn("Retry render also failed")}})}}async getFrameAt(S){if(!this.canvasSink)return null;return this.canvasSink.getCanvas(S)}async getSampleAt(S){if(!this.sampleSink)return null;return this.sampleSink.getSample(S)}async extractFrames(S,A,O=1){if(!this.canvasSink)return[];let V=[],$=[];for(let P=S;P<=A;P+=O)$.push(P);for await(let P of this.canvasSink.canvasesAtTimestamps($))if(P)V.push(P);return V}async screenshot(S,A={}){if(!this.canvas)return null;if(S!==void 0&&this.canvasSink){let O=await this.canvasSink.getCanvas(S);if(O)this.renderFrame(O)}if("toBlob"in this.canvas)return new Promise((O)=>{this.canvas.toBlob((V)=>O(V),`image/${A.format??"png"}`,A.quality)});else return this.canvas.convertToBlob({type:`image/${A.format??"png"}`,quality:A.quality})}getCurrentFrame(){return this.currentFrame}getNextFrame(){return this.nextFrame}getRendererType(){return this.rendererType}getCanvas(){return this.canvas}async switchRenderer(S){if(!this.canvas)throw Error("Cannot switch renderer: No canvas set");let A=this.rendererType;if(S===A)return;if(console.warn(`Switching renderer from ${A} to ${S}. This will recreate the canvas element.`),this.canvas instanceof HTMLCanvasElement){let O=this.canvas,V=O.parentElement;if(!V)throw Error("Cannot switch renderer: Canvas has no parent element");let $=document.createElement("canvas");if($.width=O.width,$.height=O.height,$.className=O.className,$.id=O.id,$.style.cssText=O.style.cssText,Array.from(O.attributes).forEach((P)=>{if(P.name!=="id"&&P.name!=="class"&&P.name!=="style")$.setAttribute(P.name,P.value)}),this.renderer)this.renderer.dispose(),this.renderer=null;V.replaceChild($,O),this.canvas=$;try{await this.initializeRenderer($,S)}catch(P){if(console.error(`Failed to switch to ${S}:`,P),!this.renderer){if(this.renderer=new G({canvas:$}),this.rendererType="canvas2d",this.onRendererChange)this.onRendererChange("canvas2d")}}}else{if(console.warn("Runtime switching for OffscreenCanvas may not work if context is already set"),this.renderer)this.renderer.dispose(),this.renderer=null;try{await this.initializeRenderer(this.canvas,S)}catch(O){if(console.error(`Failed to switch to ${S}:`,O),!this.renderer){if(this.renderer=new G({canvas:this.canvas}),this.rendererType="canvas2d",this.onRendererChange)this.onRendererChange("canvas2d")}}}if(this.currentFrame&&this.renderer&&this.renderer.isReady())console.log(`Re-rendering after switch to ${this.rendererType}`),queueMicrotask(()=>{if(this.currentFrame&&this.renderer&&this.renderer.isReady())this.renderFrame(this.currentFrame)})}setRendererChangeCallback(S){if(this.onRendererChange=S,this.renderer&&this.rendererType)console.log(`Renderer already initialized as ${this.rendererType}, emitting change event`),S(this.rendererType)}setRendererFallbackCallback(S){this.onRendererFallback=S}static getSupportedRenderers(){return U.getSupportedRenderers()}disposeVideoResources(){if(this.disposed=!0,this.renderingId++,this.frameIterator)this.frameIterator.return(),this.frameIterator=null;this.currentFrame=null,this.nextFrame=null,this.canvasSink=null,this.sampleSink=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.currentFrame=null,this.nextFrame=null,this.canvasSink=null,this.sampleSink=null,this.onRendererChange=void 0,this.onRendererFallback=void 0}}var SS=100,AS=250;class E{videoRenderer;audioManager;playing=!1;currentTime=0;duration=0;playbackRate=1;animationFrameId=null;lastFrameTime=0;syncIntervalId=null;renderIntervalId=null;onTimeUpdate;onEnded;constructor(S={}){this.videoRenderer=new R({canvas:S.canvas,rendererType:S.rendererType}),this.audioManager=new f({audioContext:S.audioContext,volume:S.volume,muted:S.muted}),this.playbackRate=S.playbackRate??1}async setVideoTrack(S){if(!S){this.videoRenderer.dispose();return}await this.videoRenderer.setVideoTrack(S);let A=await S.computeDuration();this.duration=Math.max(this.duration,A)}async trySetVideoTrack(S){try{return await this.setVideoTrack(S),!0}catch{return!1}}async setAudioTrack(S){let A=this.playing,O=this.getCurrentTime();if(!S){this.audioManager.dispose();return}let V=await S.computeDuration(),$=Math.max(0,Math.min(O,V));if(await this.audioManager.setAudioTrack(S),await this.audioManager.seek($),A)await this.audioManager.play($);this.currentTime=$,this.duration=Math.max(this.duration,V)}async trySetAudioTrack(S){try{return await this.setAudioTrack(S),!0}catch{return!1}}async setCanvas(S){await this.videoRenderer.setCanvas(S)}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.audioManager.pause(),this.stopRenderLoop(),this.stopSyncInterval(),this.audioManager.isPlaying())this.currentTime=this.audioManager.getCurrentTime()}async seek(S){let A=Math.max(0,Math.min(S,this.duration));if(this.currentTime=A,await this.videoRenderer.seek(A),await this.audioManager.seek(A),this.onTimeUpdate)this.onTimeUpdate(this.currentTime)}startRenderLoop(){if(this.animationFrameId!==null||this.renderIntervalId!==null)return;let S=(A=!0)=>{if(!this.playing)return;if(this.audioManager.isPlaying())this.currentTime=this.audioManager.getCurrentTime();else{let O=performance.now(),V=(O-this.lastFrameTime)/1000;this.lastFrameTime=O,this.currentTime+=V*this.playbackRate}if(this.currentTime>=this.duration){this.handleEnded();return}if(this.videoRenderer.updateFrame(this.currentTime),A)this.animationFrameId=requestAnimationFrame(()=>S())};if(this.animationFrameId=requestAnimationFrame(()=>S()),this.renderIntervalId===null)this.renderIntervalId=window.setInterval(()=>S(!1),SS)}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)},AS)}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(S){this.duration=S}isPlaying(){return this.playing}setVolume(S){this.audioManager.setVolume(S)}getVolume(){return this.audioManager.getVolume()}setMuted(S){this.audioManager.setMuted(S)}isMuted(){return this.audioManager.isMuted()}setPlaybackRate(S){let A=Math.max(0.25,Math.min(4,S));if(this.playbackRate===A)return;this.playbackRate=A,this.audioManager.setPlaybackRate(A),this.lastFrameTime=performance.now()}getPlaybackRate(){return this.playbackRate}setTimeUpdateCallback(S){this.onTimeUpdate=S}setEndedCallback(S){this.onEnded=S}async screenshot(S){return this.videoRenderer.screenshot(this.currentTime,S)}getVideoRenderer(){return this.videoRenderer}getAudioManager(){return this.audioManager}async switchRenderer(S){await this.videoRenderer.switchRenderer(S)}getRendererType(){return this.videoRenderer.getRendererType()}setRendererChangeCallback(S){this.videoRenderer.setRendererChangeCallback(S)}setRendererFallbackCallback(S){this.videoRenderer.setRendererFallbackCallback(S)}dispose(){this.pause(),this.videoRenderer.dispose(),this.audioManager.dispose(),this.onTimeUpdate=void 0,this.onEnded=void 0}destroy(){this.dispose(),this.audioManager.destroy()}}import{ALL_FORMATS as OS,BlobSource as VS,BufferSource as $S,FilePathSource as PS,Input as jS,ReadableStreamSource as DS,UrlSource as KS}from"mediabunny";class F{currentSource=null;options;constructor(S={}){this.options={maxCacheSize:S.maxCacheSize??16777216,crossOrigin:S.crossOrigin,requestInit:S.requestInit}}async createSource(S){this.dispose();let A,O;if(S instanceof File||S instanceof Blob)A=new VS(S,{maxCacheSize:this.options.maxCacheSize}),O="blob";else if(S instanceof ArrayBuffer||S instanceof Uint8Array)A=new $S(S),O="buffer";else if(typeof S==="string"||S instanceof URL){let $=S instanceof URL?S.href:S;if(typeof window>"u"&&!$.startsWith("http"))A=new PS($,{maxCacheSize:this.options.maxCacheSize}),O="file";else A=new KS($,{maxCacheSize:this.options.maxCacheSize,requestInit:this.options.requestInit}),O="url"}else if(typeof ReadableStream<"u"&&S instanceof ReadableStream)A=new DS(S,{maxCacheSize:this.options.maxCacheSize}),O="stream";else throw TypeError("Unsupported media source type");let V=new jS({source:A,formats:OS});return this.currentSource={source:A,input:V,type:O,originalSource:S},this.currentSource}getCurrentSource(){return this.currentSource}getOriginalSource(){return this.currentSource?.originalSource??null}dispose(){this.currentSource=null}static isStreamingSource(S){return S instanceof ReadableStream||typeof S==="string"&&S.startsWith("http")}static isLocalSource(S){return S instanceof File||S instanceof Blob||S instanceof ArrayBuffer||S instanceof Uint8Array||typeof S==="string"&&!S.startsWith("http")}static getSourceType(S){if(S instanceof File)return"file";if(S instanceof Blob)return"blob";if(S instanceof ArrayBuffer||S instanceof Uint8Array)return"buffer";if(S instanceof ReadableStream)return"stream";if(typeof S==="string"||S instanceof URL)return(S instanceof URL?S.href:S).startsWith("http")?"url":"file";return"unknown"}static async fromFetch(S,A){let O=await fetch(S,A);if(!O.ok)throw Error(`Failed to fetch: ${O.status} ${O.statusText}`);return O.blob()}static fromStreamingFetch(S,A){return new ReadableStream({async start(O){let V=await fetch(S,A);if(!V.ok){O.error(Error(`Failed to fetch: ${V.status} ${V.statusText}`));return}let $=V.body?.getReader();if(!$){O.error(Error("Response body is not readable"));return}try{while(!0){let{done:P,value:j}=await $.read();if(P)break;O.enqueue(j)}O.close()}catch(P){O.error(P)}}})}}function w(S,A){if(Object.is(S,A))return!0;if(typeof S!==typeof A)return!1;if(S===null||A===null)return S===A;if(Array.isArray(S)&&Array.isArray(A)){if(S.length!==A.length)return!1;for(let O=0;O<S.length;O++)if(!w(S[O],A[O]))return!1;return!0}if(v(S)&&v(A)){let O=Object.keys(S),V=Object.keys(A);if(O.length!==V.length)return!1;for(let $ of O){if(!Object.hasOwn(A,$))return!1;if(!w(S[$],A[$]))return!1}return!0}return!1}function v(S){return typeof S==="object"&&S!==null&&S.constructor===Object}class y{state;listeners=new Set;updateScheduled=!1;pendingUpdates={};constructor(){this.state=this.getInitialState()}getInitialState(){let A=U.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,error:null,mediaInfo:null,videoTracks:[],audioTracks:[],subtitleTracks:[],selectedVideoTrack:null,selectedAudioTrack:null,selectedSubtitleTrack:null,canPlay:!1,canPlayThrough:!1,isLive:!1,rendererType:A}}getState(){return Object.freeze({...this.state})}setState(S){if(Object.assign(this.pendingUpdates,S),!this.updateScheduled)this.updateScheduled=!0,queueMicrotask(()=>this.flushUpdates())}flushUpdates(){if(Object.keys(this.pendingUpdates).length===0){this.updateScheduled=!1;return}let S={...this.state};this.state={...this.state,...this.pendingUpdates},this.pendingUpdates={},this.updateScheduled=!1;let A=Object.keys(this.pendingUpdates);if((A.length?A:Object.keys(this.state)).some(($)=>!w(this.state[$],S[$])))this.notifyListeners()}subscribe(S){return this.listeners.add(S),S(this.getState()),()=>{this.listeners.delete(S)}}reset(){this.state=this.getInitialState(),this.pendingUpdates={},this.updateScheduled=!1,this.notifyListeners()}notifyListeners(){let S=this.getState();this.listeners.forEach((A)=>{try{A(S)}catch(O){console.error("Error in state listener:",O)}})}updatePlaybackState(S){let A=S?"playing":"paused";this.setState({state:A,playing:S,paused:!S,ended:!1})}updateTime(S){this.setState({currentTime:S})}updateDuration(S){this.setState({duration:S})}updateBuffered(S){this.setState({buffered:S})}updateVolume(S,A){this.setState({volume:S,muted:A})}updatePlaybackRate(S){this.setState({playbackRate:S})}updateMediaInfo(S){this.setState({mediaInfo:S})}updateTracks(S,A,O){let V={};if(S)V.videoTracks=S;if(A)V.audioTracks=A;if(O)V.subtitleTracks=O;this.setState(V)}updateSelectedTracks(S,A){switch(S){case"video":this.setState({selectedVideoTrack:A});break;case"audio":this.setState({selectedAudioTrack:A});break;case"subtitle":this.setState({selectedSubtitleTrack:A});break}}updateError(S){this.setState({error:S,state:S?"error":this.state.state})}updateSeekingState(S){this.setState({seeking:S})}updateReadyState(S,A){this.setState({canPlay:S,canPlayThrough:A,state:S?"ready":this.state.state})}updateEndedState(S){this.setState({ended:S,playing:!1,paused:!0,state:S?"ended":this.state.state})}updateLoadingState(){this.setState({state:"loading",playing:!1,paused:!0,ended:!1,error:null})}updateRendererType(S){this.setState({rendererType:S})}}class x{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(S){this.input=S,await this.loadTracks()}async loadTracks(){if(!this.input)return;let S=await this.input.getVideoTracks();this.videoTrackInfos=await Promise.all(S.map(async(O)=>{let V=`video-${O.id}`;this.videoTracks.set(V,O);let $=0,P=0;try{let D=await O.computePacketStats(100);$=D.averagePacketRate,P=D.averageBitrate}catch{}return{id:V,codec:O.codec,language:O.languageCode,name:O.name,width:O.codedWidth,height:O.codedHeight,frameRate:$,bitrate:P,rotation:O.rotation,selected:!1,decodable:await O.canDecode()}}));let A=await this.input.getAudioTracks();if(this.audioTrackInfos=await Promise.all(A.map(async(O)=>{let V=`audio-${O.id}`;this.audioTracks.set(V,O);let $=0;try{$=(await O.computePacketStats(100)).averageBitrate}catch{}return{id:V,codec:O.codec,language:O.languageCode,name:O.name,channels:O.numberOfChannels,sampleRate:O.sampleRate,bitrate:$,selected:!1,decodable:await O.canDecode()}})),this.videoTrackInfos.length>0){let O=this.videoTrackInfos.find((V)=>V.decodable);if(O)this.selectVideoTrack(O.id)}if(this.audioTrackInfos.length>0){let O=this.audioTrackInfos.find((V)=>V.decodable);if(O)this.selectAudioTrack(O.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((S)=>S.id===this.selectedVideoTrack)??null}getSelectedAudioTrackInfo(){if(!this.selectedAudioTrack)return null;return this.audioTrackInfos.find((S)=>S.id===this.selectedAudioTrack)??null}getSelectedSubtitleTrackInfo(){if(!this.selectedSubtitleTrack)return null;return this.subtitleTrackInfos.find((S)=>S.id===this.selectedSubtitleTrack)??null}selectVideoTrack(S){if(S===this.selectedVideoTrack)return!0;if(S&&!this.videoTracks.has(S))return!1;let A=this.selectedVideoTrack;if(this.videoTrackInfos.forEach((O)=>{O.selected=O.id===S}),this.selectedVideoTrack=S,this.onTrackChange)this.onTrackChange({type:"video",previousTrackId:A,newTrackId:S});return!0}selectAudioTrack(S){if(S===this.selectedAudioTrack)return!0;if(S&&!this.audioTracks.has(S))return!1;let A=this.selectedAudioTrack;if(this.audioTrackInfos.forEach((O)=>{O.selected=O.id===S}),this.selectedAudioTrack=S,this.onTrackChange)this.onTrackChange({type:"audio",previousTrackId:A,newTrackId:S});return!0}selectSubtitleTrack(S){if(S===this.selectedSubtitleTrack)return!0;if(S&&!this.subtitleTrackResolvers.has(S))return!1;let A=this.selectedSubtitleTrack;if(this.subtitleTrackInfos.forEach((O)=>{O.selected=O.id===S}),this.selectedSubtitleTrack=S,this.onTrackChange)this.onTrackChange({type:"subtitle",previousTrackId:A,newTrackId:S});return!0}registerSubtitleTracks(S,A){this.subtitleProviders.set(S,A),this.rebuildSubtitleTracks()}unregisterSubtitleTracks(S){if(!this.subtitleProviders.delete(S))return;this.rebuildSubtitleTracks()}async getSubtitleTrackResource(S){if(!S)return null;let A=this.subtitleTrackResolvers.get(S);if(!A)return null;return A()}rebuildSubtitleTracks(){let S=this.selectedSubtitleTrack;this.subtitleTrackInfos=[],this.subtitleTrackResolvers.clear();for(let O of this.subtitleProviders.values())for(let V of O){let $={...V.info,selected:!1};this.subtitleTrackInfos.push($),this.subtitleTrackResolvers.set($.id,V.resolver)}let A=S;if(!A||!this.subtitleTrackResolvers.has(A))A=this.subtitleTrackInfos[0]?.id??null;if(this.selectedSubtitleTrack=A,this.subtitleTrackInfos.forEach((O)=>{O.selected=O.id===this.selectedSubtitleTrack}),S!==this.selectedSubtitleTrack&&this.onTrackChange)this.onTrackChange({type:"subtitle",previousTrackId:S,newTrackId:this.selectedSubtitleTrack})}setTrackChangeListener(S){this.onTrackChange=S}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(S,A){let O=null;for(let[$,P]of this.audioTracks.entries())if(P.id===S){O=$;break}if(!O)return;this.audioTracks.set(O,A);let V=this.audioTrackInfos.findIndex(($)=>$.id===O);if(V!==-1){let $=0;try{$=(await A.computePacketStats(100)).averageBitrate}catch{}this.audioTrackInfos[V]={...this.audioTrackInfos[V],codec:A.codec,channels:A.numberOfChannels,sampleRate:A.sampleRate,bitrate:$,decodable:await A.canDecode()}}}async replaceVideoTrackByInputId(S,A){let O=null;for(let[$,P]of this.videoTracks.entries())if(P.id===S){O=$;break}if(!O)return;this.videoTracks.set(O,A);let V=this.videoTrackInfos.findIndex(($)=>$.id===O);if(V!==-1){let $=0,P=0;try{let j=await A.computePacketStats(100);$=j.averagePacketRate,P=j.averageBitrate}catch{}this.videoTrackInfos[V]={...this.videoTrackInfos[V],codec:A.codec,width:A.codedWidth,height:A.codedHeight,rotation:A.rotation,frameRate:$,bitrate:P,decodable:await A.canDecode()}}}}class b{emitter;store;state;sourceManager;playbackController;trackManager;options;disposed=!1;getCurrentInput=()=>this.sourceManager.getCurrentSource()?.input??null;trackSwitcher;core;constructor(S={}){this.options={volume:1,muted:!1,playbackRate:1,autoplay:!1,preload:"metadata",...S},this.emitter=new _({maxListeners:100}),this.store=new y,this.state=new W(this.store),this.sourceManager=new F({maxCacheSize:S.maxCacheSize,crossOrigin:S.crossOrigin}),this.playbackController=new E({canvas:S.renderTarget,audioContext:S.audioContext,volume:this.options.volume,muted:this.options.muted,playbackRate:this.options.playbackRate,rendererType:this.options.renderer}),this.trackManager=new x,this.trackSwitcher=new T({sourceManager:this.sourceManager,trackManager:this.trackManager,playbackController:this.playbackController,emit:this.emit.bind(this),store:this.store,getCurrentInput:this.getCurrentInput}),this.core=new H({state:this.state,sourceManager:this.sourceManager,trackManager:this.trackManager,playbackController:this.playbackController,trackSwitcher:this.trackSwitcher,emit:this.emit.bind(this)}),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((S)=>{this.state.updateTime(S),this.emit("timeupdate",{currentTime:S})}),this.playbackController.setEndedCallback(()=>{this.state.updateEndedState(!0),this.emit("ended",void 0)}),this.trackManager.setTrackChangeListener((S)=>{this.state.updateSelectedTracks(S.type,S.newTrackId),this.emit("trackchange",{type:S.type,trackId:S.newTrackId})}),this.playbackController.setRendererChangeCallback((S)=>{this.state.updateRendererType(S),this.emit("rendererchange",S)}),this.playbackController.setRendererFallbackCallback((S,A)=>{this.emit("rendererfallback",{from:S,to:A})}),this.state.subscribe((S)=>{this.emit("statechange",S)})}async load(S,A={}){return this.checkDisposed(),this.core.load(S,{autoplay:A.autoplay??this.options.autoplay,startTime:A.startTime})}async play(){return this.checkDisposed(),this.core.play()}pause(){this.checkDisposed(),this.core.pause()}async seek(S,A={}){return this.checkDisposed(),this.core.seek(S)}async stop(){return this.checkDisposed(),this.core.stop()}get currentTime(){return this.playbackController.getCurrentTime()}set currentTime(S){this.seek(S)}get duration(){return this.state.getState().duration}get volume(){return this.playbackController.getVolume()}set volume(S){this.checkDisposed();let A=Math.max(0,Math.min(1,S));this.playbackController.setVolume(A),this.state.updateVolume(A,this.muted),this.emit("volumechange",{volume:A,muted:this.muted})}get muted(){return this.playbackController.isMuted()}set muted(S){this.checkDisposed(),this.playbackController.setMuted(S),this.state.updateVolume(this.volume,S),this.emit("volumechange",{volume:this.volume,muted:S})}get playbackRate(){return this.playbackController.getPlaybackRate()}set playbackRate(S){this.checkDisposed();let A=Math.max(0.25,Math.min(4,S));this.playbackController.setPlaybackRate(A),this.state.updatePlaybackRate(A),this.emit("ratechange",{playbackRate:A})}get paused(){return!this.playbackController.isPlaying()}get ended(){return this.state.getState().ended}get seeking(){return this.state.getState().seeking}getVideoTracks(){return this.trackManager.getVideoTracks()}getAudioTracks(){return this.trackManager.getAudioTracks()}getSubtitleTracks(){return this.trackManager.getSubtitleTracks()}async selectVideoTrack(S){this.checkDisposed(),await this.trackSwitcher.selectVideoTrack(this.trackManager,S)}async selectAudioTrack(S){this.checkDisposed(),await this.trackSwitcher.selectAudioTrack(this.trackManager,S)}selectSubtitleTrack(S){if(this.checkDisposed(),!this.trackManager.selectSubtitleTrack(S))throw Error(`Invalid subtitle track ID: ${S}`)}registerSubtitleTracks(S,A){this.trackManager.registerSubtitleTracks(S,A),this.state.updateTracks(void 0,void 0,this.trackManager.getSubtitleTracks());let O=this.state.getState().mediaInfo;if(O)this.state.updateMediaInfo({...O,hasSubtitles:this.trackManager.hasSubtitles()})}unregisterSubtitleTracks(S){this.trackManager.unregisterSubtitleTracks(S),this.state.updateTracks(void 0,void 0,this.trackManager.getSubtitleTracks());let A=this.state.getState().mediaInfo;if(A)this.state.updateMediaInfo({...A,hasSubtitles:this.trackManager.hasSubtitles()})}async getSubtitleTrackResource(S){return this.trackManager.getSubtitleTrackResource(S)}async screenshot(S={}){return this.checkDisposed(),this.playbackController.screenshot(S)}async setRenderTarget(S){this.checkDisposed(),await this.playbackController.setCanvas(S)}getRendererType(){return this.playbackController.getRendererType()}async switchRenderer(S){this.checkDisposed(),await this.playbackController.switchRenderer(S)}static getSupportedRenderers(){return U.getSupportedRenderers()}getState(){return this.state.getState()}subscribe(S){return{unsubscribe:this.state.subscribe(S)}}on(S,A){return this.emitter.on(S,A)}once(S,A){return this.emitter.once(S,A)}off(S,A){this.emitter.off(S,A)}emit(S,A){this.emitter.emit(S,A)}checkDisposed(){if(this.disposed)throw Error("Player has been disposed")}dispose(){if(this.disposed)return;this.disposed=!0,this.playbackController.dispose(),this.trackManager.dispose(),this.sourceManager.dispose(),this.state.reset(),this.emitter.removeAllListeners()}destroy(){this.dispose(),this.playbackController.destroy()}}var k;((K)=>{K.MEDIA_NOT_SUPPORTED="MEDIA_NOT_SUPPORTED";K.MEDIA_LOAD_FAILED="MEDIA_LOAD_FAILED";K.DECODE_ERROR="DECODE_ERROR";K.NETWORK_ERROR="NETWORK_ERROR";K.PERMISSION_DENIED="PERMISSION_DENIED";K.PLAYBACK_ERROR="PLAYBACK_ERROR";K.TRACK_NOT_FOUND="TRACK_NOT_FOUND";K.INVALID_STATE="INVALID_STATE";K.UNKNOWN_ERROR="UNKNOWN_ERROR"})(k||={});class N extends Error{code;details;constructor(S,A,O){super(A);this.name="MediaFoxError",this.code=S,this.details=O}static mediaNotSupported(S="Media format not supported",A){return new N("MEDIA_NOT_SUPPORTED",S,A)}static mediaLoadFailed(S="Failed to load media",A){return new N("MEDIA_LOAD_FAILED",S,A)}static decodeError(S="Failed to decode media",A){return new N("DECODE_ERROR",S,A)}static networkError(S="Network error occurred",A){return new N("NETWORK_ERROR",S,A)}static permissionDenied(S="Permission denied",A){return new N("PERMISSION_DENIED",S,A)}static playbackError(S="Playback error occurred",A){return new N("PLAYBACK_ERROR",S,A)}static trackNotFound(S="Track not found",A){return new N("TRACK_NOT_FOUND",S,A)}static invalidState(S="Invalid player state",A){return new N("INVALID_STATE",S,A)}static unknownError(S="Unknown error occurred",A){return new N("UNKNOWN_ERROR",S,A)}}function NS(S,A){if(S instanceof N)return S;if(S instanceof Error)return new N("UNKNOWN_ERROR",`${A}: ${S.message}`,{originalError:S});return new N("UNKNOWN_ERROR",`${A}: ${String(S)}`,{originalError:S})}function QS(S,A=!1){let O=Math.abs(S),V=Math.floor(O/3600),$=Math.floor(O%3600/60),P=Math.floor(O%60),j=Math.floor(O%1*1000),D="";if(S<0)D="-";if(V>0)D+=`${V}:${$.toString().padStart(2,"0")}:${P.toString().padStart(2,"0")}`;else D+=`${$}:${P.toString().padStart(2,"0")}`;if(A)D+=`.${j.toString().padStart(3,"0")}`;return D}function US(S){let A=S.trim().split(":").map(Number);if(A.some(Number.isNaN))throw Error("Invalid time string");let O=0;if(A.length===3)O=A[0]*3600+A[1]*60+A[2];else if(A.length===2)O=A[0]*60+A[1];else if(A.length===1)O=A[0];else throw Error("Invalid time format");return O}function JS(S,A){return Math.floor(S*A)}function zS(S,A){return S/A}function XS(S,A,O){return Math.max(A,Math.min(O,S))}function ZS(S,A){return S.start<A.end&&A.start<S.end}function YS(S){if(S.length===0)return[];let A=[...S].sort((V,$)=>V.start-$.start),O=[A[0]];for(let V=1;V<A.length;V++){let $=O[O.length-1],P=A[V];if(P.start<=$.end)$.end=Math.max($.end,P.end);else O.push(P)}return O}function GS(S){return S.reduce((A,O)=>A+(O.end-O.start),0)}function qS(S,A){for(let O of S)if(A>=O.start&&A<O.end)return O;return null}var XA="0.1.0",yA=b;export{NS as wrapError,GS as totalBufferedDuration,JS as timeToFrame,ZS as timeRangesOverlap,US as parseTime,YS as mergeTimeRanges,zS as frameToTime,QS as formatTime,qS as findBufferedRange,yA as default,XS as clamp,R as VideoRenderer,XA as VERSION,x as TrackManager,y as Store,F as SourceManager,U as RendererFactory,E as PlaybackController,N as MediaFoxError,b as MediaFox,_ as EventEmitter,k as ErrorCode,f as AudioManager};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { UnsubscribeFn } from './events/types';
|
|
2
|
+
import type { SubtitleTrackRegistration, SubtitleTrackResource } from './tracks/types';
|
|
3
|
+
import type { AudioTrackInfo, LoadOptions, MediaSource, PlayerEventListener, PlayerEventMap, PlayerOptions, PlayerStateData, RendererType, ScreenshotOptions, SeekOptions, Subscription, SubtitleTrackInfo, VideoTrackInfo } from './types';
|
|
4
|
+
export declare class MediaFox {
|
|
5
|
+
private emitter;
|
|
6
|
+
private store;
|
|
7
|
+
private state;
|
|
8
|
+
private sourceManager;
|
|
9
|
+
private playbackController;
|
|
10
|
+
private trackManager;
|
|
11
|
+
private options;
|
|
12
|
+
private disposed;
|
|
13
|
+
private getCurrentInput;
|
|
14
|
+
private trackSwitcher;
|
|
15
|
+
private core;
|
|
16
|
+
constructor(options?: PlayerOptions);
|
|
17
|
+
private setupInternalListeners;
|
|
18
|
+
/**
|
|
19
|
+
* Load a media source and prepare playback.
|
|
20
|
+
* Emits: loadstart, loadedmetadata, loadeddata, canplay, canplaythrough (or error)
|
|
21
|
+
*/
|
|
22
|
+
load(source: MediaSource, options?: LoadOptions): Promise<void>;
|
|
23
|
+
/** Start playback. */
|
|
24
|
+
play(): Promise<void>;
|
|
25
|
+
pause(): void;
|
|
26
|
+
/** Seek to a new time (seconds). */
|
|
27
|
+
seek(time: number, _options?: SeekOptions): Promise<void>;
|
|
28
|
+
/** Pause and reset to time 0. */
|
|
29
|
+
stop(): Promise<void>;
|
|
30
|
+
get currentTime(): number;
|
|
31
|
+
/**
|
|
32
|
+
* Sets the current playback time. Note: This is a fire-and-forget operation.
|
|
33
|
+
* Use seek() directly if you need to await the operation.
|
|
34
|
+
*/
|
|
35
|
+
set currentTime(time: number);
|
|
36
|
+
get duration(): number;
|
|
37
|
+
get volume(): number;
|
|
38
|
+
set volume(value: number);
|
|
39
|
+
get muted(): boolean;
|
|
40
|
+
set muted(value: boolean);
|
|
41
|
+
get playbackRate(): number;
|
|
42
|
+
set playbackRate(value: number);
|
|
43
|
+
get paused(): boolean;
|
|
44
|
+
get ended(): boolean;
|
|
45
|
+
get seeking(): boolean;
|
|
46
|
+
getVideoTracks(): VideoTrackInfo[];
|
|
47
|
+
getAudioTracks(): AudioTrackInfo[];
|
|
48
|
+
getSubtitleTracks(): SubtitleTrackInfo[];
|
|
49
|
+
selectVideoTrack(trackId: string | null): Promise<void>;
|
|
50
|
+
selectAudioTrack(trackId: string | null): Promise<void>;
|
|
51
|
+
selectSubtitleTrack(trackId: string | null): void;
|
|
52
|
+
registerSubtitleTracks(sourceId: string, registrations: SubtitleTrackRegistration[]): void;
|
|
53
|
+
unregisterSubtitleTracks(sourceId: string): void;
|
|
54
|
+
getSubtitleTrackResource(trackId: string | null): Promise<SubtitleTrackResource | null>;
|
|
55
|
+
/** Capture a screenshot of the current frame. */
|
|
56
|
+
screenshot(options?: ScreenshotOptions): Promise<Blob | null>;
|
|
57
|
+
setRenderTarget(canvas: HTMLCanvasElement | OffscreenCanvas): Promise<void>;
|
|
58
|
+
getRendererType(): RendererType;
|
|
59
|
+
switchRenderer(type: RendererType): Promise<void>;
|
|
60
|
+
static getSupportedRenderers(): RendererType[];
|
|
61
|
+
getState(): Readonly<PlayerStateData>;
|
|
62
|
+
/** Subscribe to state changes; returns an unsubscribe handle. */
|
|
63
|
+
subscribe(listener: (state: PlayerStateData) => void): Subscription;
|
|
64
|
+
on<K extends keyof PlayerEventMap>(event: K, listener: PlayerEventListener<K>): UnsubscribeFn;
|
|
65
|
+
once<K extends keyof PlayerEventMap>(event: K, listener: PlayerEventListener<K>): UnsubscribeFn;
|
|
66
|
+
off<K extends keyof PlayerEventMap>(event: K, listener?: PlayerEventListener<K>): void;
|
|
67
|
+
private emit;
|
|
68
|
+
private checkDisposed;
|
|
69
|
+
dispose(): void;
|
|
70
|
+
destroy(): void;
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=mediafox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mediafox.d.ts","sourceRoot":"","sources":["../src/mediafox.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAMpD,OAAO,KAAK,EAAE,yBAAyB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AACvF,OAAO,KAAK,EACV,cAAc,EACd,WAAW,EACX,WAAW,EACX,mBAAmB,EACnB,cAAc,EACd,aAAa,EACb,eAAe,EACf,YAAY,EACZ,iBAAiB,EACjB,WAAW,EACX,YAAY,EACZ,iBAAiB,EACjB,cAAc,EACf,MAAM,SAAS,CAAC;AAGjB,qBAAa,QAAQ;IACnB,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,KAAK,CAAc;IAC3B,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,kBAAkB,CAAqB;IAC/C,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,eAAe,CAA8D;IACrF,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,IAAI,CAAa;gBAEb,OAAO,GAAE,aAAkB;IAyDvC,OAAO,CAAC,sBAAsB;IAuC9B;;;OAGG;IACG,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAQzE,sBAAsB;IAChB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAK3B,KAAK,IAAI,IAAI;IAKb,oCAAoC;IAC9B,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,WAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAKnE,iCAAiC;IAC3B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAO3B,IAAI,WAAW,IAAI,MAAM,CAExB;IAED;;;OAGG;IACH,IAAI,WAAW,CAAC,IAAI,EAAE,MAAM,EAE3B;IAED,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,IAAI,MAAM,CAAC,KAAK,EAAE,MAAM,EAMvB;IAED,IAAI,KAAK,IAAI,OAAO,CAEnB;IAED,IAAI,KAAK,CAAC,KAAK,EAAE,OAAO,EAKvB;IAED,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED,IAAI,YAAY,CAAC,KAAK,EAAE,MAAM,EAM7B;IAED,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED,IAAI,KAAK,IAAI,OAAO,CAEnB;IAED,IAAI,OAAO,IAAI,OAAO,CAErB;IAID,cAAc,IAAI,cAAc,EAAE;IAIlC,cAAc,IAAI,cAAc,EAAE;IAIlC,iBAAiB,IAAI,iBAAiB,EAAE;IAIlC,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAKvD,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAK7D,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAQjD,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,yBAAyB,EAAE,GAAG,IAAI;IAa1F,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAa1C,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC;IAM7F,iDAAiD;IAC3C,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAKjE,eAAe,CAAC,MAAM,EAAE,iBAAiB,GAAG,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAKjF,eAAe,IAAI,YAAY;IAIzB,cAAc,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAKvD,MAAM,CAAC,qBAAqB,IAAI,YAAY,EAAE;IAI9C,QAAQ,IAAI,QAAQ,CAAC,eAAe,CAAC;IAIrC,iEAAiE;IACjE,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,GAAG,YAAY;IAOnE,EAAE,CAAC,CAAC,SAAS,MAAM,cAAc,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,mBAAmB,CAAC,CAAC,CAAC,GAAG,aAAa;IAI7F,IAAI,CAAC,CAAC,SAAS,MAAM,cAAc,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,mBAAmB,CAAC,CAAC,CAAC,GAAG,aAAa;IAI/F,GAAG,CAAC,CAAC,SAAS,MAAM,cAAc,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,CAAC,EAAE,mBAAmB,CAAC,CAAC,CAAC,GAAG,IAAI;IAItF,OAAO,CAAC,IAAI;IAIZ,OAAO,CAAC,aAAa;IAQrB,OAAO,IAAI,IAAI;IAaf,OAAO,IAAI,IAAI;CAIhB"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { type AudioSample, type InputAudioTrack, type WrappedAudioBuffer } from 'mediabunny';
|
|
2
|
+
export interface AudioManagerOptions {
|
|
3
|
+
audioContext?: AudioContext;
|
|
4
|
+
volume?: number;
|
|
5
|
+
muted?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare class AudioManager {
|
|
8
|
+
private audioContext;
|
|
9
|
+
private gainNode;
|
|
10
|
+
private bufferSink;
|
|
11
|
+
private sampleSink;
|
|
12
|
+
private bufferIterator;
|
|
13
|
+
private queuedNodes;
|
|
14
|
+
private startContextTime;
|
|
15
|
+
private startMediaTime;
|
|
16
|
+
private pauseTime;
|
|
17
|
+
private playing;
|
|
18
|
+
private volume;
|
|
19
|
+
private muted;
|
|
20
|
+
private disposed;
|
|
21
|
+
private playbackId;
|
|
22
|
+
private playbackRate;
|
|
23
|
+
constructor(options?: AudioManagerOptions);
|
|
24
|
+
private setupAudioGraph;
|
|
25
|
+
setAudioTrack(track: InputAudioTrack): Promise<void>;
|
|
26
|
+
play(fromTime?: number): Promise<void>;
|
|
27
|
+
private scheduleAudioBuffers;
|
|
28
|
+
private waitForCatchup;
|
|
29
|
+
pause(): void;
|
|
30
|
+
stop(): void;
|
|
31
|
+
seek(timestamp: number): Promise<void>;
|
|
32
|
+
getCurrentTime(): number;
|
|
33
|
+
setVolume(volume: number): void;
|
|
34
|
+
setMuted(muted: boolean): void;
|
|
35
|
+
private updateGain;
|
|
36
|
+
getVolume(): number;
|
|
37
|
+
isMuted(): boolean;
|
|
38
|
+
isPlaying(): boolean;
|
|
39
|
+
setPlaybackRate(rate: number): void;
|
|
40
|
+
getAudioContext(): AudioContext;
|
|
41
|
+
getBufferAt(timestamp: number): Promise<WrappedAudioBuffer | null>;
|
|
42
|
+
getSampleAt(timestamp: number): Promise<AudioSample | null>;
|
|
43
|
+
private stopQueuedNodes;
|
|
44
|
+
dispose(): void;
|
|
45
|
+
destroy(): void;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=audio.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audio.d.ts","sourceRoot":"","sources":["../../src/playback/audio.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,WAAW,EAEhB,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACxB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,mBAAmB;IAClC,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAyB;IACzC,OAAO,CAAC,UAAU,CAAgC;IAClD,OAAO,CAAC,UAAU,CAAgC;IAClD,OAAO,CAAC,cAAc,CAAkE;IACxF,OAAO,CAAC,WAAW,CAAyC;IAC5D,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,YAAY,CAAK;gBAEb,OAAO,GAAE,mBAAwB;IAmB7C,OAAO,CAAC,eAAe;IAMjB,aAAa,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAsBpD,IAAI,CAAC,QAAQ,GAAE,MAAuB,GAAG,OAAO,CAAC,IAAI,CAAC;YAuB9C,oBAAoB;YA2CpB,cAAc;IAW5B,KAAK,IAAI,IAAI;IAkBb,IAAI,IAAI,IAAI;IAON,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAc5C,cAAc,IAAI,MAAM;IAQxB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAK/B,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAK9B,OAAO,CAAC,UAAU;IAQlB,SAAS,IAAI,MAAM;IAInB,OAAO,IAAI,OAAO;IAIlB,SAAS,IAAI,OAAO;IAIpB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAkBnC,eAAe,IAAI,YAAY;IAIzB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC;IAKlE,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAKjE,OAAO,CAAC,eAAe;IAWvB,OAAO,IAAI,IAAI;IAef,OAAO,IAAI,IAAI;CAYhB"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { InputAudioTrack, InputVideoTrack } from 'mediabunny';
|
|
2
|
+
import { AudioManager } from './audio';
|
|
3
|
+
import { VideoRenderer } from './renderer';
|
|
4
|
+
export interface PlaybackControllerOptions {
|
|
5
|
+
canvas?: HTMLCanvasElement | OffscreenCanvas;
|
|
6
|
+
audioContext?: AudioContext;
|
|
7
|
+
volume?: number;
|
|
8
|
+
muted?: boolean;
|
|
9
|
+
playbackRate?: number;
|
|
10
|
+
rendererType?: import('./renderers').RendererType;
|
|
11
|
+
}
|
|
12
|
+
export declare class PlaybackController {
|
|
13
|
+
private videoRenderer;
|
|
14
|
+
private audioManager;
|
|
15
|
+
private playing;
|
|
16
|
+
private currentTime;
|
|
17
|
+
private duration;
|
|
18
|
+
private playbackRate;
|
|
19
|
+
private animationFrameId;
|
|
20
|
+
private lastFrameTime;
|
|
21
|
+
private syncIntervalId;
|
|
22
|
+
private renderIntervalId;
|
|
23
|
+
private onTimeUpdate?;
|
|
24
|
+
private onEnded?;
|
|
25
|
+
constructor(options?: PlaybackControllerOptions);
|
|
26
|
+
setVideoTrack(track: InputVideoTrack | null): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Attempt to set video track without throwing. Returns true on success.
|
|
29
|
+
*/
|
|
30
|
+
trySetVideoTrack(track: InputVideoTrack | null): Promise<boolean>;
|
|
31
|
+
setAudioTrack(track: InputAudioTrack | null): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Attempt to set audio track without throwing. Returns true on success.
|
|
34
|
+
*/
|
|
35
|
+
trySetAudioTrack(track: InputAudioTrack | null): Promise<boolean>;
|
|
36
|
+
setCanvas(canvas: HTMLCanvasElement | OffscreenCanvas): Promise<void>;
|
|
37
|
+
play(): Promise<void>;
|
|
38
|
+
pause(): void;
|
|
39
|
+
seek(time: number): Promise<void>;
|
|
40
|
+
private startRenderLoop;
|
|
41
|
+
private stopRenderLoop;
|
|
42
|
+
private startSyncInterval;
|
|
43
|
+
private stopSyncInterval;
|
|
44
|
+
private handleEnded;
|
|
45
|
+
getCurrentTime(): number;
|
|
46
|
+
getDuration(): number;
|
|
47
|
+
setDuration(duration: number): void;
|
|
48
|
+
isPlaying(): boolean;
|
|
49
|
+
setVolume(volume: number): void;
|
|
50
|
+
getVolume(): number;
|
|
51
|
+
setMuted(muted: boolean): void;
|
|
52
|
+
isMuted(): boolean;
|
|
53
|
+
setPlaybackRate(rate: number): void;
|
|
54
|
+
getPlaybackRate(): number;
|
|
55
|
+
setTimeUpdateCallback(callback: (time: number) => void): void;
|
|
56
|
+
setEndedCallback(callback: () => void): void;
|
|
57
|
+
screenshot(options?: {
|
|
58
|
+
format?: 'png' | 'jpeg' | 'webp';
|
|
59
|
+
quality?: number;
|
|
60
|
+
}): Promise<Blob | null>;
|
|
61
|
+
getVideoRenderer(): VideoRenderer;
|
|
62
|
+
getAudioManager(): AudioManager;
|
|
63
|
+
switchRenderer(type: import('./renderers').RendererType): Promise<void>;
|
|
64
|
+
getRendererType(): import('./renderers').RendererType;
|
|
65
|
+
setRendererChangeCallback(callback: (type: import('./renderers').RendererType) => void): void;
|
|
66
|
+
setRendererFallbackCallback(callback: (from: import('./renderers').RendererType, to: import('./renderers').RendererType) => void): void;
|
|
67
|
+
dispose(): void;
|
|
68
|
+
destroy(): void;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=controller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../src/playback/controller.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { type InputVideoTrack, type VideoSample, type WrappedCanvas } from 'mediabunny';
|
|
2
|
+
import type { RendererType } from './renderers';
|
|
3
|
+
export interface VideoRendererOptions {
|
|
4
|
+
canvas?: HTMLCanvasElement | OffscreenCanvas;
|
|
5
|
+
width?: number;
|
|
6
|
+
height?: number;
|
|
7
|
+
fit?: 'fill' | 'contain' | 'cover';
|
|
8
|
+
rotation?: 0 | 90 | 180 | 270;
|
|
9
|
+
poolSize?: number;
|
|
10
|
+
rendererType?: RendererType;
|
|
11
|
+
}
|
|
12
|
+
export declare class VideoRenderer {
|
|
13
|
+
private canvas;
|
|
14
|
+
private canvasSink;
|
|
15
|
+
private sampleSink;
|
|
16
|
+
private options;
|
|
17
|
+
private frameIterator;
|
|
18
|
+
private currentFrame;
|
|
19
|
+
private nextFrame;
|
|
20
|
+
private disposed;
|
|
21
|
+
private renderingId;
|
|
22
|
+
private renderer;
|
|
23
|
+
private rendererType;
|
|
24
|
+
private onRendererChange?;
|
|
25
|
+
private onRendererFallback?;
|
|
26
|
+
private initPromise;
|
|
27
|
+
constructor(options?: VideoRendererOptions);
|
|
28
|
+
private initializeRenderer;
|
|
29
|
+
setCanvas(canvas: HTMLCanvasElement | OffscreenCanvas): Promise<void>;
|
|
30
|
+
setVideoTrack(track: InputVideoTrack): Promise<void>;
|
|
31
|
+
seek(timestamp: number): Promise<void>;
|
|
32
|
+
updateFrame(currentTime: number): boolean;
|
|
33
|
+
private fetchNextFrame;
|
|
34
|
+
private renderFrame;
|
|
35
|
+
getFrameAt(timestamp: number): Promise<WrappedCanvas | null>;
|
|
36
|
+
getSampleAt(timestamp: number): Promise<VideoSample | null>;
|
|
37
|
+
extractFrames(startTime: number, endTime: number, interval?: number): Promise<WrappedCanvas[]>;
|
|
38
|
+
screenshot(timestamp?: number, options?: {
|
|
39
|
+
format?: 'png' | 'jpeg' | 'webp';
|
|
40
|
+
quality?: number;
|
|
41
|
+
}): Promise<Blob | null>;
|
|
42
|
+
getCurrentFrame(): WrappedCanvas | null;
|
|
43
|
+
getNextFrame(): WrappedCanvas | null;
|
|
44
|
+
getRendererType(): RendererType;
|
|
45
|
+
getCanvas(): HTMLCanvasElement | OffscreenCanvas | null;
|
|
46
|
+
switchRenderer(type: RendererType): Promise<void>;
|
|
47
|
+
setRendererChangeCallback(callback: (type: RendererType) => void): void;
|
|
48
|
+
setRendererFallbackCallback(callback: (from: RendererType, to: RendererType) => void): void;
|
|
49
|
+
static getSupportedRenderers(): RendererType[];
|
|
50
|
+
private disposeVideoResources;
|
|
51
|
+
dispose(): void;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/playback/renderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,eAAe,EAAE,KAAK,WAAW,EAAmB,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AACrH,OAAO,KAAK,EAAa,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3D,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,EAAE,iBAAiB,GAAG,eAAe,CAAC;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;IACnC,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,GAAG,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAoD;IAClE,OAAO,CAAC,UAAU,CAA2B;IAC7C,OAAO,CAAC,UAAU,CAAgC;IAClD,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,aAAa,CAA6D;IAClF,OAAO,CAAC,YAAY,CAA8B;IAClD,OAAO,CAAC,SAAS,CAA8B;IAC/C,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,QAAQ,CAA0B;IAC1C,OAAO,CAAC,YAAY,CAA4B;IAChD,OAAO,CAAC,gBAAgB,CAAC,CAA+B;IACxD,OAAO,CAAC,kBAAkB,CAAC,CAAiD;IAC5E,OAAO,CAAC,WAAW,CAA8B;gBAErC,OAAO,GAAE,oBAAyB;YAgChC,kBAAkB;IAkE1B,SAAS,CAAC,MAAM,EAAE,iBAAiB,GAAG,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAiCrE,aAAa,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IA6EpD,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiE5C,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO;YA4B3B,cAAc;IA0B5B,OAAO,CAAC,WAAW;IA4Cb,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAK5D,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAK3D,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAU,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IAiBjG,UAAU,CACd,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,GAAE;QACP,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;QACjC,OAAO,CAAC,EAAE,MAAM,CAAC;KACb,GACL,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IA8BvB,eAAe,IAAI,aAAa,GAAG,IAAI;IAIvC,YAAY,IAAI,aAAa,GAAG,IAAI;IAIpC,eAAe,IAAI,YAAY;IAI/B,SAAS,IAAI,iBAAiB,GAAG,eAAe,GAAG,IAAI;IAIjD,cAAc,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAoGvD,yBAAyB,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,GAAG,IAAI;IAUvE,2BAA2B,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,EAAE,EAAE,YAAY,KAAK,IAAI,GAAG,IAAI;IAI3F,MAAM,CAAC,qBAAqB,IAAI,YAAY,EAAE;IAI9C,OAAO,CAAC,qBAAqB;IAgB7B,OAAO,IAAI,IAAI;CAuBhB"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { IRenderer } from './types';
|
|
2
|
+
export interface Canvas2DRendererOptions {
|
|
3
|
+
canvas: HTMLCanvasElement | OffscreenCanvas;
|
|
4
|
+
}
|
|
5
|
+
export declare class Canvas2DRenderer implements IRenderer {
|
|
6
|
+
private canvas;
|
|
7
|
+
private ctx;
|
|
8
|
+
private isInitialized;
|
|
9
|
+
constructor(options: Canvas2DRendererOptions);
|
|
10
|
+
private initialize;
|
|
11
|
+
isReady(): boolean;
|
|
12
|
+
render(source: HTMLCanvasElement | OffscreenCanvas): boolean;
|
|
13
|
+
clear(): void;
|
|
14
|
+
dispose(): void;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=canvas2d.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canvas2d.d.ts","sourceRoot":"","sources":["../../../src/playback/renderers/canvas2d.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,iBAAiB,GAAG,eAAe,CAAC;CAC7C;AAED,qBAAa,gBAAiB,YAAW,SAAS;IAChD,OAAO,CAAC,MAAM,CAAsC;IACpD,OAAO,CAAC,GAAG,CAA6E;IACxF,OAAO,CAAC,aAAa,CAAS;gBAElB,OAAO,EAAE,uBAAuB;IAK5C,OAAO,CAAC,UAAU;IAqBX,OAAO,IAAI,OAAO;IAIlB,MAAM,CAAC,MAAM,EAAE,iBAAiB,GAAG,eAAe,GAAG,OAAO;IAkC5D,KAAK,IAAI,IAAI;IAOb,OAAO,IAAI,IAAI;CAIvB"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { IRenderer, RendererCreationResult, RendererOptions, RendererType } from './types';
|
|
2
|
+
export declare class RendererFactory {
|
|
3
|
+
private canvas;
|
|
4
|
+
private powerPreference;
|
|
5
|
+
constructor(options: RendererOptions);
|
|
6
|
+
createRenderer(type: RendererType): Promise<IRenderer | null>;
|
|
7
|
+
createRendererWithFallback(preferredType: RendererType): Promise<RendererCreationResult>;
|
|
8
|
+
private createWebGPURenderer;
|
|
9
|
+
private createWebGLRenderer;
|
|
10
|
+
private createCanvas2DRenderer;
|
|
11
|
+
/**
|
|
12
|
+
* Get all available renderer types for the current environment
|
|
13
|
+
* Returns in priority order: WebGPU, WebGL, Canvas2D
|
|
14
|
+
*/
|
|
15
|
+
static getSupportedRenderers(): RendererType[];
|
|
16
|
+
/**
|
|
17
|
+
* Get display name for renderer type
|
|
18
|
+
*/
|
|
19
|
+
static getRendererDisplayName(type: RendererType): string;
|
|
20
|
+
/**
|
|
21
|
+
* Check if a specific renderer type is supported
|
|
22
|
+
*/
|
|
23
|
+
static isRendererSupported(type: RendererType): boolean;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=factory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../src/playback/renderers/factory.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,sBAAsB,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAIhG,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAsC;IACpD,OAAO,CAAC,eAAe,CAAmC;gBAE9C,OAAO,EAAE,eAAe;IAKvB,cAAc,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAiB7D,0BAA0B,CAAC,aAAa,EAAE,YAAY,GAAG,OAAO,CAAC,sBAAsB,CAAC;YAwBvF,oBAAoB;IA6ClC,OAAO,CAAC,mBAAmB;IAgB3B,OAAO,CAAC,sBAAsB;IAI9B;;;OAGG;WACW,qBAAqB,IAAI,YAAY,EAAE;IAsBrD;;OAEG;WACW,sBAAsB,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM;IAahE;;OAEG;WACW,mBAAmB,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO;CAM/D"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/playback/renderers/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export type RendererType = 'webgpu' | 'webgl' | 'canvas2d';
|
|
2
|
+
/**
|
|
3
|
+
* Base interface for video renderers.
|
|
4
|
+
* All renderers must implement this interface.
|
|
5
|
+
*/
|
|
6
|
+
export interface IRenderer {
|
|
7
|
+
/**
|
|
8
|
+
* Check if the renderer is ready to render frames
|
|
9
|
+
*/
|
|
10
|
+
isReady(): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Render a frame from source canvas
|
|
13
|
+
* @param source - Source canvas containing the video frame
|
|
14
|
+
* @returns true if rendering succeeded, false otherwise
|
|
15
|
+
*/
|
|
16
|
+
render(source: HTMLCanvasElement | OffscreenCanvas): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Clear the target canvas
|
|
19
|
+
*/
|
|
20
|
+
clear(): void;
|
|
21
|
+
/**
|
|
22
|
+
* Dispose and clean up renderer resources
|
|
23
|
+
*/
|
|
24
|
+
dispose(): void;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Options for creating a renderer
|
|
28
|
+
*/
|
|
29
|
+
export interface RendererOptions {
|
|
30
|
+
canvas: HTMLCanvasElement | OffscreenCanvas;
|
|
31
|
+
powerPreference?: 'high-performance' | 'low-power';
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Result of renderer creation with fallback
|
|
35
|
+
*/
|
|
36
|
+
export interface RendererCreationResult {
|
|
37
|
+
renderer: IRenderer;
|
|
38
|
+
actualType: RendererType;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/playback/renderers/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,OAAO,GAAG,UAAU,CAAC;AAE3D;;;GAGG;AACH,MAAM,WAAW,SAAS;IACxB;;OAEG;IACH,OAAO,IAAI,OAAO,CAAC;IAEnB;;;;OAIG;IACH,MAAM,CAAC,MAAM,EAAE,iBAAiB,GAAG,eAAe,GAAG,OAAO,CAAC;IAE7D;;OAEG;IACH,KAAK,IAAI,IAAI,CAAC;IAEd;;OAEG;IACH,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,iBAAiB,GAAG,eAAe,CAAC;IAC5C,eAAe,CAAC,EAAE,kBAAkB,GAAG,WAAW,CAAC;CACpD;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,SAAS,CAAC;IACpB,UAAU,EAAE,YAAY,CAAC;CAC1B"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { IRenderer } from './types';
|
|
2
|
+
export interface WebGLRendererOptions {
|
|
3
|
+
canvas: HTMLCanvasElement | OffscreenCanvas;
|
|
4
|
+
alpha?: boolean;
|
|
5
|
+
antialias?: boolean;
|
|
6
|
+
preserveDrawingBuffer?: boolean;
|
|
7
|
+
powerPreference?: 'high-performance' | 'low-power' | 'default';
|
|
8
|
+
}
|
|
9
|
+
export declare class WebGLRenderer implements IRenderer {
|
|
10
|
+
private resources;
|
|
11
|
+
private isInitialized;
|
|
12
|
+
private canvas;
|
|
13
|
+
private textureWidth;
|
|
14
|
+
private textureHeight;
|
|
15
|
+
private options;
|
|
16
|
+
private boundHandleContextLost;
|
|
17
|
+
private boundHandleContextRestored;
|
|
18
|
+
private readonly vertexShaderSource;
|
|
19
|
+
private readonly fragmentShaderSource;
|
|
20
|
+
constructor(options: WebGLRendererOptions);
|
|
21
|
+
private initialize;
|
|
22
|
+
private createShader;
|
|
23
|
+
private setupQuadBuffers;
|
|
24
|
+
isReady(): boolean;
|
|
25
|
+
render(source: HTMLCanvasElement | OffscreenCanvas): boolean;
|
|
26
|
+
clear(): void;
|
|
27
|
+
private handleContextLost;
|
|
28
|
+
private handleContextRestored;
|
|
29
|
+
private cleanup;
|
|
30
|
+
dispose(): void;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=webgl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webgl.d.ts","sourceRoot":"","sources":["../../../src/playback/renderers/webgl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,iBAAiB,GAAG,eAAe,CAAC;IAC5C,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,eAAe,CAAC,EAAE,kBAAkB,GAAG,WAAW,GAAG,SAAS,CAAC;CAChE;AAaD,qBAAa,aAAc,YAAW,SAAS;IAC7C,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,MAAM,CAAsC;IACpD,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,sBAAsB,CAAyC;IACvE,OAAO,CAAC,0BAA0B,CAA6B;IAE/D,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CASjC;IAEF,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CASnC;gBAEU,OAAO,EAAE,oBAAoB;IAiBzC,OAAO,CAAC,UAAU;IAgFlB,OAAO,CAAC,YAAY;IAepB,OAAO,CAAC,gBAAgB;IAgBjB,OAAO,IAAI,OAAO;IAIlB,MAAM,CAAC,MAAM,EAAE,iBAAiB,GAAG,eAAe,GAAG,OAAO;IAsE5D,KAAK,IAAI,IAAI;IAQpB,OAAO,CAAC,iBAAiB;IAKzB,OAAO,CAAC,qBAAqB;IAI7B,OAAO,CAAC,OAAO;IAuBR,OAAO,IAAI,IAAI;CAyBvB"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { IRenderer } from './types';
|
|
2
|
+
export interface WebGPURendererOptions {
|
|
3
|
+
canvas: HTMLCanvasElement | OffscreenCanvas;
|
|
4
|
+
powerPreference?: 'high-performance' | 'low-power';
|
|
5
|
+
}
|
|
6
|
+
export declare class WebGPURenderer implements IRenderer {
|
|
7
|
+
private canvas;
|
|
8
|
+
private device;
|
|
9
|
+
private context;
|
|
10
|
+
private pipeline;
|
|
11
|
+
private texture;
|
|
12
|
+
private sampler;
|
|
13
|
+
private bindGroup;
|
|
14
|
+
private vertexBuffer;
|
|
15
|
+
private isInitialized;
|
|
16
|
+
private textureWidth;
|
|
17
|
+
private textureHeight;
|
|
18
|
+
private powerPreference;
|
|
19
|
+
private readonly vertexShaderSource;
|
|
20
|
+
private readonly fragmentShaderSource;
|
|
21
|
+
constructor(options: WebGPURendererOptions);
|
|
22
|
+
private initialize;
|
|
23
|
+
private createRenderPipeline;
|
|
24
|
+
private createVertexBuffer;
|
|
25
|
+
private createTexture;
|
|
26
|
+
private createBindGroup;
|
|
27
|
+
isReady(): boolean;
|
|
28
|
+
render(source: HTMLCanvasElement | OffscreenCanvas): boolean;
|
|
29
|
+
clear(): void;
|
|
30
|
+
dispose(): void;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=webgpu.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webgpu.d.ts","sourceRoot":"","sources":["../../../src/playback/renderers/webgpu.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,iBAAiB,GAAG,eAAe,CAAC;IAC5C,eAAe,CAAC,EAAE,kBAAkB,GAAG,WAAW,CAAC;CACpD;AAED,qBAAa,cAAe,YAAW,SAAS;IAC9C,OAAO,CAAC,MAAM,CAAsC;IACpD,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,OAAO,CAAiC;IAChD,OAAO,CAAC,QAAQ,CAAkC;IAClD,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,SAAS,CAA6B;IAC9C,OAAO,CAAC,YAAY,CAA0B;IAC9C,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,eAAe,CAAmC;IAE1D,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAajC;IAEF,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAQnC;gBAEU,OAAO,EAAE,qBAAqB;YAQ5B,UAAU;YAoDV,oBAAoB;IAsClC,OAAO,CAAC,kBAAkB;IAS1B,OAAO,CAAC,aAAa;IAuBrB,OAAO,CAAC,eAAe;IAYhB,OAAO,IAAI,OAAO;IAIlB,MAAM,CAAC,MAAM,EAAE,iBAAiB,GAAG,eAAe,GAAG,OAAO;IA+G5D,KAAK,IAAI,IAAI;IAuBb,OAAO,IAAI,IAAI;CAoBvB"}
|