From 7bf0984698e43b9aa2dd879f65951318ed410390 Mon Sep 17 00:00:00 2001 From: Maze <167211895+mazeincoding@users.noreply.github.com> Date: Sat, 31 Jan 2026 00:20:04 +0100 Subject: codebase overhaul (#697) --- apps/web/src/lib/video-cache.ts | 186 ---------------------------------------- 1 file changed, 186 deletions(-) delete mode 100644 apps/web/src/lib/video-cache.ts (limited to 'apps/web/src/lib/video-cache.ts') diff --git a/apps/web/src/lib/video-cache.ts b/apps/web/src/lib/video-cache.ts deleted file mode 100644 index aeb62d1c..00000000 --- a/apps/web/src/lib/video-cache.ts +++ /dev/null @@ -1,186 +0,0 @@ -import { - Input, - ALL_FORMATS, - BlobSource, - CanvasSink, - WrappedCanvas, -} from "mediabunny"; - -interface VideoSinkData { - sink: CanvasSink; - iterator: AsyncGenerator | null; - currentFrame: WrappedCanvas | null; - lastTime: number; -} -export class VideoCache { - private sinks = new Map(); - private initPromises = new Map>(); - - async getFrameAt( - mediaId: string, - file: File, - time: number - ): Promise { - await this.ensureSink(mediaId, file); - - const sinkData = this.sinks.get(mediaId); - if (!sinkData) return null; - - if ( - sinkData.currentFrame && - this.isFrameValid(sinkData.currentFrame, time) - ) { - return sinkData.currentFrame; - } - - if ( - sinkData.iterator && - sinkData.currentFrame && - time >= sinkData.lastTime && - time < sinkData.lastTime + 2.0 - ) { - const frame = await this.iterateToTime(sinkData, time); - if (frame) return frame; - } - - return await this.seekToTime(sinkData, time); - } - - private isFrameValid(frame: WrappedCanvas, time: number): boolean { - return time >= frame.timestamp && time < frame.timestamp + frame.duration; - } - private async iterateToTime( - sinkData: VideoSinkData, - targetTime: number - ): Promise { - if (!sinkData.iterator) return null; - - try { - while (true) { - const { value: frame, done } = await sinkData.iterator.next(); - - if (done || !frame) break; - - sinkData.currentFrame = frame; - sinkData.lastTime = frame.timestamp; - - if (this.isFrameValid(frame, targetTime)) { - return frame; - } - - if (frame.timestamp > targetTime + 1.0) break; - } - } catch (error) { - console.warn("Iterator failed, will restart:", error); - sinkData.iterator = null; - } - - return null; - } - private async seekToTime( - sinkData: VideoSinkData, - time: number - ): Promise { - try { - if (sinkData.iterator) { - await sinkData.iterator.return(); - sinkData.iterator = null; - } - - sinkData.iterator = sinkData.sink.canvases(time); - sinkData.lastTime = time; - - const { value: frame } = await sinkData.iterator.next(); - - if (frame) { - sinkData.currentFrame = frame; - return frame; - } - } catch (error) { - console.warn("Failed to seek video:", error); - } - - return null; - } - private async ensureSink(mediaId: string, file: File): Promise { - if (this.sinks.has(mediaId)) return; - - if (this.initPromises.has(mediaId)) { - await this.initPromises.get(mediaId); - return; - } - - const initPromise = this.initializeSink(mediaId, file); - this.initPromises.set(mediaId, initPromise); - - try { - await initPromise; - } finally { - this.initPromises.delete(mediaId); - } - } - private async initializeSink(mediaId: string, file: File): Promise { - try { - const input = new Input({ - source: new BlobSource(file), - formats: ALL_FORMATS, - }); - - const videoTrack = await input.getPrimaryVideoTrack(); - if (!videoTrack) { - throw new Error("No video track found"); - } - - const canDecode = await videoTrack.canDecode(); - if (!canDecode) { - throw new Error("Video codec not supported for decoding"); - } - - const sink = new CanvasSink(videoTrack, { - poolSize: 3, - fit: "contain", - }); - - this.sinks.set(mediaId, { - sink, - iterator: null, - currentFrame: null, - lastTime: -1, - }); - } catch (error) { - console.error(`Failed to initialize video sink for ${mediaId}:`, error); - throw error; - } - } - - clearVideo(mediaId: string): void { - const sinkData = this.sinks.get(mediaId); - if (sinkData) { - if (sinkData.iterator) { - sinkData.iterator.return(); - } - - this.sinks.delete(mediaId); - } - - this.initPromises.delete(mediaId); - } - - clearAll(): void { - for (const [mediaId] of this.sinks) { - this.clearVideo(mediaId); - } - } - - getStats() { - return { - totalSinks: this.sinks.size, - activeSinks: Array.from(this.sinks.values()).filter((s) => s.iterator) - .length, - cachedFrames: Array.from(this.sinks.values()).filter( - (s) => s.currentFrame - ).length, - }; - } -} -export const videoCache = new VideoCache(); -- cgit v1.3.1