@meframe/core 0.0.32 → 0.0.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/controllers/PlaybackController.d.ts +1 -1
- package/dist/controllers/PlaybackController.d.ts.map +1 -1
- package/dist/controllers/PlaybackController.js +22 -10
- package/dist/controllers/PlaybackController.js.map +1 -1
- package/dist/event/events.d.ts +1 -1
- package/dist/event/events.d.ts.map +1 -1
- package/dist/event/events.js.map +1 -1
- package/dist/model/CompositionModel.d.ts +8 -0
- package/dist/model/CompositionModel.d.ts.map +1 -1
- package/dist/model/CompositionModel.js +18 -0
- package/dist/model/CompositionModel.js.map +1 -1
- package/dist/orchestrator/ExportScheduler.d.ts +4 -0
- package/dist/orchestrator/ExportScheduler.d.ts.map +1 -1
- package/dist/orchestrator/ExportScheduler.js +38 -34
- package/dist/orchestrator/ExportScheduler.js.map +1 -1
- package/dist/orchestrator/GlobalAudioSession.js +2 -2
- package/dist/orchestrator/GlobalAudioSession.js.map +1 -1
- package/dist/orchestrator/Orchestrator.d.ts +10 -2
- package/dist/orchestrator/Orchestrator.d.ts.map +1 -1
- package/dist/orchestrator/Orchestrator.js +41 -20
- package/dist/orchestrator/Orchestrator.js.map +1 -1
- package/dist/stages/load/ResourceLoader.d.ts +29 -21
- package/dist/stages/load/ResourceLoader.d.ts.map +1 -1
- package/dist/stages/load/ResourceLoader.js +179 -70
- package/dist/stages/load/ResourceLoader.js.map +1 -1
- package/dist/stages/load/TaskManager.d.ts +4 -0
- package/dist/stages/load/TaskManager.d.ts.map +1 -1
- package/dist/stages/load/TaskManager.js +11 -0
- package/dist/stages/load/TaskManager.js.map +1 -1
- package/package.json +1 -1
|
@@ -65,7 +65,7 @@ export declare class PlaybackController implements IPlaybackController, PreviewH
|
|
|
65
65
|
private checkAndPreheatWindow;
|
|
66
66
|
/**
|
|
67
67
|
* Preheat next window by decoding from current playback time
|
|
68
|
-
*
|
|
68
|
+
* Supports cross-clip window preheating for seamless playback
|
|
69
69
|
* Preheats both video and audio in parallel
|
|
70
70
|
*/
|
|
71
71
|
private preheatNextWindow;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlaybackController.d.ts","sourceRoot":"","sources":["../../src/controllers/PlaybackController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EAEnB,eAAe,EACf,SAAS,EACT,aAAa,EACb,MAAM,EACP,MAAM,SAAS,CAAC;AAEjB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"PlaybackController.d.ts","sourceRoot":"","sources":["../../src/controllers/PlaybackController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EAEnB,eAAe,EACf,SAAS,EACT,aAAa,EACb,MAAM,EACP,MAAM,SAAS,CAAC;AAEjB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAKpD;;;GAGG;AACH,qBAAa,kBAAmB,YAAW,mBAAmB,EAAE,aAAa;IAC3E,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAY;IAC5B,OAAO,CAAC,MAAM,CAAsC;IACpD,OAAO,CAAC,aAAa,CAA8B;IAGnD,aAAa,EAAE,MAAM,CAAK;IAC1B,OAAO,CAAC,KAAK,CAAyB;IACtC,OAAO,CAAC,YAAY,CAAO;IAC3B,OAAO,CAAC,MAAM,CAAO;IACrB,OAAO,CAAC,IAAI,CAAS;IAGrB,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,WAAW,CAAa;IAGhC,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,GAAG,CAAK;IAChB,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,YAAY,CAAmC;IAGvD,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,oBAAoB,CAAS;IAGrC,OAAO,CAAC,SAAS,CAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAa;IAC7C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAa;IAC9C,OAAO,CAAC,iBAAiB,CAAS;gBAEtB,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,eAAe;IA0C/E,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAKlC,IAAI,IAAI,IAAI;YAYE,aAAa;IAoC3B,KAAK,IAAI,IAAI;IAgBb,IAAI,IAAI,IAAI;IAuBN,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAyDzC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAW3B,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAO/B,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAQ7B,OAAO,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI;IAI5B,IAAI,QAAQ,IAAI,MAAM,CAOrB;IAED,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,eAAe,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI;IAKlD,MAAM,IAAI,IAAI;IAId,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,IAAI,GAAG,IAAI;IAIxD,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,IAAI,GAAG,IAAI;IAKzD,OAAO,CAAC,YAAY;IAqEpB,OAAO,CAAC,UAAU;IAiClB;;;OAGG;IACH,OAAO,CAAC,UAAU;IAQlB;;;;;;;OAOG;IACH,OAAO,CAAC,qBAAqB;IAuB7B;;;;OAIG;YACW,iBAAiB;IA4CzB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAiCzC,uBAAuB;IA2DrC,OAAO,CAAC,SAAS;IAKjB,OAAO,IAAI,IAAI;IAUf,OAAO,CAAC,YAAY,CASlB;IAEF,OAAO,CAAC,UAAU,CAmBhB;IAEF,OAAO,CAAC,mBAAmB;YAKb,kBAAkB;CAOjC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { MeframeEvent } from "../event/events.js";
|
|
2
2
|
import { WaiterReplacedError } from "../utils/errors.js";
|
|
3
3
|
import { VideoComposer } from "../stages/compose/VideoComposer.js";
|
|
4
|
+
import { isVideoClip } from "../model/types.js";
|
|
4
5
|
class PlaybackController {
|
|
5
6
|
orchestrator;
|
|
6
7
|
eventBus;
|
|
@@ -299,20 +300,31 @@ class PlaybackController {
|
|
|
299
300
|
}
|
|
300
301
|
/**
|
|
301
302
|
* Preheat next window by decoding from current playback time
|
|
302
|
-
*
|
|
303
|
+
* Supports cross-clip window preheating for seamless playback
|
|
303
304
|
* Preheats both video and audio in parallel
|
|
304
305
|
*/
|
|
305
306
|
async preheatNextWindow() {
|
|
306
307
|
try {
|
|
307
|
-
const
|
|
308
|
-
const
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
308
|
+
const windowStart = this.currentTimeUs;
|
|
309
|
+
const windowEnd = windowStart + this.WINDOW_DURATION;
|
|
310
|
+
const clipsInWindow = this.orchestrator.compositionModel?.getClipsInRange(windowStart, windowEnd) ?? [];
|
|
311
|
+
const preheatPromises = [];
|
|
312
|
+
for (const clip of clipsInWindow) {
|
|
313
|
+
if (!isVideoClip(clip)) continue;
|
|
314
|
+
const clipWindowStart = Math.max(0, windowStart - clip.startUs);
|
|
315
|
+
const clipWindowEnd = Math.min(clip.durationUs, windowEnd - clip.startUs);
|
|
316
|
+
if (clipWindowStart >= clipWindowEnd) continue;
|
|
317
|
+
preheatPromises.push(
|
|
318
|
+
this.orchestrator.preheatClipWindow(clip.id, clipWindowStart, clipWindowEnd, windowStart)
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
if (this.audioSession) {
|
|
322
|
+
preheatPromises.push(
|
|
323
|
+
this.audioSession.ensureAudioForTime(windowStart, { immediate: false })
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
await Promise.all(preheatPromises);
|
|
327
|
+
this.windowEnd = windowEnd;
|
|
316
328
|
} catch (error) {
|
|
317
329
|
console.warn("[PlaybackController] Preheat failed:", error);
|
|
318
330
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlaybackController.js","sources":["../../src/controllers/PlaybackController.ts"],"sourcesContent":["import type {\n IPlaybackController,\n PlaybackState,\n PlaybackOptions,\n IEventBus,\n PreviewHandle,\n TimeUs,\n} from './types';\nimport { MeframeEvent } from '../event/events';\nimport type { GlobalAudioSession } from '../orchestrator/GlobalAudioSession';\nimport type { Orchestrator } from '../orchestrator';\nimport { WaiterReplacedError } from '../utils/errors';\nimport { VideoComposer } from '../stages/compose/VideoComposer';\n\n/**\n * Playback controller for preview\n * Internal implementation - not exposed directly to external consumers\n */\nexport class PlaybackController implements IPlaybackController, PreviewHandle {\n private orchestrator: Orchestrator;\n private eventBus: IEventBus;\n private canvas: HTMLCanvasElement | OffscreenCanvas;\n private videoComposer: VideoComposer | null = null;\n\n // Playback state\n currentTimeUs: TimeUs = 0;\n private state: PlaybackState = 'idle';\n private playbackRate = 1.0;\n private volume = 1.0;\n private loop = false;\n\n // Animation loop\n private rafId: number | null = null;\n private startTimeUs: TimeUs = 0; // Playback start position in AudioContext timeline (microseconds)\n\n // Frame tracking\n private frameCount = 0;\n private lastFrameTime = 0;\n private fps = 0;\n private audioContext: AudioContext | null = null;\n private audioSession: GlobalAudioSession | null = null;\n\n // Buffering state\n private isBuffering = false;\n private currentSeekId = 0;\n private wasPlayingBeforeSeek = false;\n\n // Unified window management for both video and audio\n private windowEnd: TimeUs = 0;\n private readonly WINDOW_DURATION = 3_000_000; // 3s decode window\n private readonly PREHEAT_DISTANCE = 1_000_000; // 1s preheat trigger distance\n private preheatInProgress = false;\n\n constructor(orchestrator: Orchestrator, eventBus: IEventBus, options: PlaybackOptions) {\n this.orchestrator = orchestrator;\n this.eventBus = eventBus;\n this.canvas = options.canvas;\n\n // Initialize VideoComposer for real-time composition\n // Pass canvas as externalCanvas for direct rendering\n const model = orchestrator.compositionModel;\n\n // FIX: Prioritize model renderConfig over canvas current dimensions\n // The canvas should act as a viewport into the renderConfig resolution\n const width = model?.renderConfig?.width || this.canvas.width || 720;\n const height = model?.renderConfig?.height || this.canvas.height || 1280;\n\n this.videoComposer = new VideoComposer({\n width,\n height,\n fps: model?.fps || 30,\n backgroundColor: model?.renderConfig?.backgroundColor || '#000',\n externalCanvas: this.canvas,\n });\n\n // Set initial time if provided\n if (options.startUs !== undefined) {\n this.currentTimeUs = options.startUs;\n }\n\n if (options.rate !== undefined) {\n this.playbackRate = options.rate;\n }\n\n if (options.loop !== undefined) {\n this.loop = options.loop;\n }\n\n if (options.autoStart) {\n this.play();\n }\n\n this.setupEventListeners();\n }\n\n async renderCover(): Promise<void> {\n await this.renderCurrentFrame(0);\n }\n\n // Playback control\n play(): void {\n if (this.state === 'playing') return;\n\n // If playback has ended, reset audio scheduling states for clean replay\n if (this.state === 'ended') {\n this.audioSession?.resetPlaybackStates();\n }\n\n this.wasPlayingBeforeSeek = true; // User wants to play\n void this.startPlayback();\n }\n\n private async startPlayback(): Promise<void> {\n const wasIdle = this.state === 'idle';\n const seekId = this.currentSeekId;\n\n try {\n // Render first frame (may trigger buffering if cache miss)\n await this.renderCurrentFrame(this.currentTimeUs);\n\n // Check if seek happened during render\n if (seekId !== this.currentSeekId) {\n return;\n }\n\n this.state = 'playing';\n await this.ensureAudioContext();\n\n // Initialize windows BEFORE starting audio playback\n this.initWindow(this.currentTimeUs);\n\n if (this.audioSession && this.audioContext) {\n await this.audioSession.startPlayback(this.currentTimeUs, this.audioContext);\n }\n\n this.startTimeUs =\n this.audioContext!.currentTime * 1_000_000 - this.currentTimeUs / this.playbackRate;\n\n this.playbackLoop();\n\n this.eventBus.emit(MeframeEvent.PlaybackPlay);\n } catch (error) {\n console.error('[PlaybackController] Failed to start playback:', error);\n this.state = wasIdle ? 'idle' : 'paused';\n this.eventBus.emit(MeframeEvent.PlaybackError, error as Error);\n }\n }\n\n pause(): void {\n if (this.state !== 'playing') return;\n\n this.state = 'paused';\n this.wasPlayingBeforeSeek = false; // User explicitly paused\n\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n\n this.audioSession?.stopPlayback();\n\n this.eventBus.emit(MeframeEvent.PlaybackPause);\n }\n\n stop(): void {\n this.pause();\n this.currentTimeUs = 0;\n this.state = 'idle';\n this.wasPlayingBeforeSeek = false; // Reset seek state\n this.frameCount = 0; // Reset frame counter\n this.lastFrameTime = 0; // Reset frame timing\n\n // Clear canvas\n const ctx = this.canvas.getContext('2d') as\n | CanvasRenderingContext2D\n | OffscreenCanvasRenderingContext2D\n | null;\n if (ctx && 'clearRect' in ctx) {\n ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);\n }\n\n this.audioSession?.reset();\n this.audioSession?.resetPlaybackStates();\n\n this.eventBus.emit(MeframeEvent.PlaybackStop);\n }\n\n async seek(timeUs: TimeUs): Promise<void> {\n const previousState = this.state;\n\n // Stop playback without changing wasPlayingBeforeSeek\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n this.audioSession?.stopPlayback();\n\n // Reset audio playback states for all clips\n this.audioSession?.resetPlaybackStates();\n\n const clamped = this.clampTime(timeUs);\n this.currentTimeUs = clamped;\n this.currentSeekId++; // Invalidate previous seek operations\n this.isBuffering = false; // Reset buffering flag\n\n // Initialize window at seek position\n this.initWindow(clamped);\n\n this.state = 'seeking';\n\n const seekId = this.currentSeekId;\n\n try {\n // Ensure audio windows ready for seek position (blocking mode)\n if (this.audioSession) {\n await this.audioSession.ensureAudioForTime(clamped, { immediate: false });\n }\n\n await this.renderCurrentFrame(clamped);\n\n // Check if another seek happened during render\n if (seekId !== this.currentSeekId) {\n return;\n }\n\n this.eventBus.emit(MeframeEvent.PlaybackSeek, { timeUs: this.currentTimeUs });\n\n if (this.wasPlayingBeforeSeek) {\n await this.startPlayback();\n } else {\n this.state = previousState === 'idle' ? 'idle' : 'paused';\n }\n } catch (error) {\n // Check if this seek is still current\n if (seekId !== this.currentSeekId) {\n return;\n }\n console.error('[PlaybackController] Seek error:', error);\n this.eventBus.emit(MeframeEvent.PlaybackError, error as Error);\n this.state = previousState === 'idle' ? 'idle' : 'paused';\n }\n }\n\n // Playback properties\n setRate(rate: number): void {\n // Adjust audio start time to maintain current position\n const currentTimeUs = this.currentTimeUs;\n this.playbackRate = rate;\n this.startTimeUs = this.audioContext!.currentTime * 1_000_000 - currentTimeUs / rate;\n\n this.eventBus.emit(MeframeEvent.PlaybackRateChange, { rate });\n\n this.audioSession?.setPlaybackRate(this.playbackRate);\n }\n\n setVolume(volume: number): void {\n this.volume = Math.max(0, Math.min(1, volume));\n this.eventBus.emit(MeframeEvent.PlaybackVolumeChange, { volume: this.volume });\n\n this.audioSession?.setVolume(this.volume);\n }\n\n setMute(muted: boolean): void {\n if (muted) {\n this.audioSession?.stopPlayback();\n } else if (this.state === 'playing' && this.audioContext) {\n this.audioSession?.startPlayback(this.currentTimeUs, this.audioContext);\n }\n }\n\n setLoop(loop: boolean): void {\n this.loop = loop;\n }\n\n get duration(): TimeUs {\n const modelDuration = this.orchestrator.compositionModel?.durationUs;\n if (modelDuration !== undefined) {\n return modelDuration;\n }\n\n return 0;\n }\n\n get isPlaying(): boolean {\n return this.state === 'playing';\n }\n\n setAudioSession(session: GlobalAudioSession): void {\n this.audioSession = session;\n }\n\n // Resume is just an alias for play\n resume(): void {\n this.play();\n }\n\n on(event: string, handler: (payload: any) => void): void {\n this.eventBus.on(event as MeframeEvent, handler);\n }\n\n off(event: string, handler: (payload: any) => void): void {\n this.eventBus.off(event as MeframeEvent, handler);\n }\n\n // Private methods\n private playbackLoop(): void {\n // State Check #1: Loop entry (from recursive call)\n // Prevents next frame from starting if state changed during previous frame\n // Captures: pause(), stop(), seek() called during frame processing\n if (this.state !== 'playing') {\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n return;\n }\n\n this.rafId = requestAnimationFrame(async () => {\n // State Check #2: RAF callback start (async boundary)\n // Captures state changes during RAF delay (~16ms)\n // Scenario: User pauses/seeks between requestAnimationFrame call and callback execution\n if (this.state !== 'playing') {\n return;\n }\n\n this.updateTime();\n\n // State Check #3: After updateTime (playback end detection)\n // CRITICAL: Prevents ensureAudioForTime/scheduleAudio from polluting cache\n // When playback ends, currentTimeUs is reset to 0 for clean replay\n // Without this check, audio operations would execute with wrong position\n if (this.state !== 'playing') {\n return;\n }\n\n // Ensure audio windows ready (aligned with video architecture)\n // Use immediate mode during playback (non-blocking)\n if (this.audioSession) {\n await this.audioSession.ensureAudioForTime(this.currentTimeUs, { immediate: true });\n }\n\n // Lookahead audio scheduling (OfflineAudioMixer approach)\n if (this.audioContext && this.audioSession) {\n await this.audioSession.scheduleAudio(this.currentTimeUs, this.audioContext);\n }\n\n await this.renderCurrentFrame(this.currentTimeUs);\n\n // State Check #4: After render (buffering detection)\n // Captures: renderCurrentFrame() triggered buffering (cache miss)\n // Optimization: Early exit to avoid unnecessary FPS calculation and setWindow\n // Not strictly required (next loop's Check #1 would catch it), but improves responsiveness\n if (this.state !== 'playing') {\n return;\n }\n\n // Calculate FPS based on actual frame timing\n const now = performance.now();\n if (this.lastFrameTime > 0) {\n const deltaTime = now - this.lastFrameTime;\n const instantFps = 1000 / deltaTime;\n this.fps = this.fps > 0 ? this.fps * 0.9 + instantFps * 0.1 : instantFps;\n }\n this.lastFrameTime = now;\n\n this.frameCount++;\n\n // Update unified window for video and audio\n this.orchestrator.cacheManager.setWindow(this.currentTimeUs);\n\n this.playbackLoop();\n });\n }\n\n private updateTime(): void {\n const elapsedUs =\n (this.audioContext!.currentTime * 1_000_000 - this.startTimeUs) * this.playbackRate;\n this.currentTimeUs = elapsedUs;\n\n // Check if reached end\n if (this.currentTimeUs >= this.duration) {\n if (this.loop) {\n this.currentTimeUs = 0;\n this.startTimeUs = this.audioContext!.currentTime * 1_000_000;\n // Reset audio scheduling states to avoid stale state from previous playback\n this.audioSession?.resetPlaybackStates();\n // Reset window to start position\n this.initWindow(0);\n } else {\n this.pause();\n // Set to 0 instead of duration to prevent audio operations in final frame\n // from polluting cache with wrong position data\n this.currentTimeUs = 0;\n this.state = 'ended';\n this.eventBus.emit(MeframeEvent.PlaybackEnded, { timeUs: this.duration });\n }\n }\n\n // Emit time update\n this.eventBus.emit(MeframeEvent.PlaybackTimeUpdate, { timeUs: this.currentTimeUs });\n\n // Check if approaching window edge - trigger async preheat\n this.checkAndPreheatWindow();\n // Note: setWindow is now called in Orchestrator.renderFrame()\n // this.orchestrator.cacheManager.setWindow(this.currentTimeUs);\n }\n\n /**\n * Initialize window at given time (called on play/seek)\n * Sets unified window for both video and audio\n */\n private initWindow(timeUs: TimeUs): void {\n this.windowEnd = timeUs + this.WINDOW_DURATION;\n this.preheatInProgress = false; // Reset preheat state\n\n // Set unified window center for both video and audio\n this.orchestrator.cacheManager.setWindow(timeUs);\n }\n\n /**\n * Check if approaching window end and trigger preheat for next window\n *\n * Strategy: Unified sliding window for both video and audio\n * - Current window: [windowStart, windowEnd] (3s duration)\n * - When playback reaches windowEnd - 1s, preheat next window\n * - Next window: [windowEnd, windowEnd + 3s]\n */\n private checkAndPreheatWindow(): void {\n // Skip if already preheating or not playing\n if (this.preheatInProgress || this.state !== 'playing') {\n return;\n }\n\n // Check if approaching window end\n const distanceToWindowEnd = this.windowEnd - this.currentTimeUs;\n if (distanceToWindowEnd < 0) {\n this.initWindow(this.currentTimeUs);\n return;\n }\n\n // Trigger preheat when 1s from window end\n if (distanceToWindowEnd > 0 && distanceToWindowEnd <= this.PREHEAT_DISTANCE) {\n this.preheatInProgress = true;\n\n void this.preheatNextWindow().finally(() => {\n this.preheatInProgress = false;\n });\n }\n }\n\n /**\n * Preheat next window by decoding from current playback time\n * Updates windowStart and windowEnd after preheat completes\n * Preheats both video and audio in parallel\n */\n private async preheatNextWindow(): Promise<void> {\n try {\n // Slide window to current time (keep current data + load future)\n const newWindowStart = this.currentTimeUs;\n const newWindowEnd = newWindowStart + this.WINDOW_DURATION;\n\n // Preheat both video and audio in parallel\n await Promise.all([\n // Preheat video (without updating window center to avoid shifting away from current playback)\n this.orchestrator.getFrame(newWindowStart, { immediate: false, preheat: true }),\n // Preheat audio (non-blocking mode for background decoding)\n this.audioSession?.ensureAudioForTime(newWindowStart, { immediate: false }),\n ]);\n\n // Update window bounds after successful preheat\n this.windowEnd = newWindowEnd;\n } catch (error) {\n // Preheat failures are not critical\n console.warn('[PlaybackController] Preheat failed:', error);\n }\n }\n\n async renderCurrentFrame(timeUs: TimeUs): Promise<void> {\n if (!this.videoComposer) {\n console.error('[PlaybackController] VideoComposer not initialized');\n return;\n }\n\n try {\n // Get render state (layers) from orchestrator\n // Use immediate mode when playing to detect buffering\n const renderState = await this.orchestrator.getRenderState(timeUs, {\n immediate: this.state === 'playing',\n });\n\n if (!renderState) {\n // If renderState is null during playback, we hit a cache miss/buffer underrun\n if (this.state === 'playing' && !this.isBuffering) {\n await this.handlePlaybackBuffering(timeUs);\n }\n return;\n }\n\n // Compose directly to canvas\n await this.videoComposer.composeFrame({\n timeUs,\n layers: renderState.layers,\n transition: renderState.transition,\n });\n } catch (error) {\n console.error('Render error:', error);\n this.eventBus.emit(MeframeEvent.PlaybackError, error as Error);\n }\n }\n\n private async handlePlaybackBuffering(timeUs: TimeUs): Promise<void> {\n if (this.isBuffering || this.state !== 'playing') {\n return;\n }\n\n const seekId = this.currentSeekId;\n this.isBuffering = true;\n this.state = 'buffering';\n this.eventBus.emit(MeframeEvent.PlaybackBuffering);\n\n // Pause audio immediately to prevent desync\n this.audioSession?.stopPlayback();\n\n try {\n // Update window center for buffering position\n this.orchestrator.cacheManager.setWindow(timeUs);\n\n // Force load frame (blocking)\n // This ensures the resource is downloaded and decoded\n await this.orchestrator.getFrame(timeUs, { immediate: false });\n\n // Also ensure audio is ready (blocking mode for buffering)\n await this.orchestrator.audioSession.ensureAudioForTime(timeUs, { immediate: false });\n\n // Check if seek happened during buffering\n if (seekId !== this.currentSeekId) {\n return;\n }\n\n this.state = 'playing';\n this.startTimeUs = this.audioContext!.currentTime * 1_000_000 - timeUs / this.playbackRate;\n\n // Resume audio synced with timeline\n if (this.audioContext) {\n await this.audioSession?.startPlayback(timeUs, this.audioContext);\n }\n\n this.eventBus.emit(MeframeEvent.PlaybackPlay);\n\n if (!this.rafId) {\n this.playbackLoop();\n }\n } catch (error) {\n // Ignore WaiterReplacedError (happens during fast seeks)\n if (error instanceof WaiterReplacedError) {\n return;\n }\n // Check if seek happened during error handling\n if (seekId !== this.currentSeekId) {\n return;\n }\n console.error('[PlaybackController] Buffering error:', error);\n this.state = 'paused';\n this.eventBus.emit(MeframeEvent.PlaybackError, error as Error);\n } finally {\n this.isBuffering = false;\n }\n }\n\n private clampTime(timeUs: TimeUs): TimeUs {\n return Math.max(0, Math.min(timeUs, this.duration));\n }\n\n // Cleanup\n dispose(): void {\n this.stop();\n this.eventBus.off(MeframeEvent.CacheCover, this.onCacheCover);\n this.eventBus.off(MeframeEvent.ModelSet, this.onModelSet);\n if (this.videoComposer) {\n this.videoComposer.dispose();\n this.videoComposer = null;\n }\n }\n\n private onCacheCover = (): void => {\n // Optimization for Quick Start / Fast First Frame:\n // When the first frame of a resource is decoded (e.g. via side-channel parsing),\n // we immediately render it if we are at the start of the timeline.\n // This significantly improves perceived loading speed for compatible formats (e.g. fragmented MP4 with moov at start).\n // For standard formats or when not at time 0, this might be redundant as normal playback loop handles it.\n if (this.state === 'idle' && this.currentTimeUs === 0) {\n this.renderCurrentFrame(0);\n }\n };\n\n private onModelSet = (): void => {\n if (!this.videoComposer || !this.orchestrator.compositionModel) return;\n\n const model = this.orchestrator.compositionModel;\n // Update VideoComposer configuration with new model dimensions and fps\n this.videoComposer.updateConfig({\n width: model.renderConfig?.width || 720,\n height: model.renderConfig?.height || 1280,\n fps: model.fps || 30,\n backgroundColor: model.renderConfig?.backgroundColor || '#000',\n });\n\n // Preheat audio for first frame (non-blocking)\n if (this.audioSession) {\n void this.audioSession.ensureAudioForTime(0, { immediate: false });\n }\n\n // Re-render current frame to reflect dimension changes immediately\n void this.renderCurrentFrame(this.currentTimeUs);\n };\n\n private setupEventListeners(): void {\n this.eventBus.on(MeframeEvent.CacheCover, this.onCacheCover);\n this.eventBus.on(MeframeEvent.ModelSet, this.onModelSet);\n }\n\n private async ensureAudioContext(): Promise<void> {\n if (this.audioContext) {\n return;\n }\n\n this.audioContext = new AudioContext();\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"PlaybackController.js","sources":["../../src/controllers/PlaybackController.ts"],"sourcesContent":["import type {\n IPlaybackController,\n PlaybackState,\n PlaybackOptions,\n IEventBus,\n PreviewHandle,\n TimeUs,\n} from './types';\nimport { MeframeEvent } from '../event/events';\nimport type { GlobalAudioSession } from '../orchestrator/GlobalAudioSession';\nimport type { Orchestrator } from '../orchestrator';\nimport { WaiterReplacedError } from '../utils/errors';\nimport { VideoComposer } from '../stages/compose/VideoComposer';\nimport { isVideoClip } from '../model/types';\n\n/**\n * Playback controller for preview\n * Internal implementation - not exposed directly to external consumers\n */\nexport class PlaybackController implements IPlaybackController, PreviewHandle {\n private orchestrator: Orchestrator;\n private eventBus: IEventBus;\n private canvas: HTMLCanvasElement | OffscreenCanvas;\n private videoComposer: VideoComposer | null = null;\n\n // Playback state\n currentTimeUs: TimeUs = 0;\n private state: PlaybackState = 'idle';\n private playbackRate = 1.0;\n private volume = 1.0;\n private loop = false;\n\n // Animation loop\n private rafId: number | null = null;\n private startTimeUs: TimeUs = 0; // Playback start position in AudioContext timeline (microseconds)\n\n // Frame tracking\n private frameCount = 0;\n private lastFrameTime = 0;\n private fps = 0;\n private audioContext: AudioContext | null = null;\n private audioSession: GlobalAudioSession | null = null;\n\n // Buffering state\n private isBuffering = false;\n private currentSeekId = 0;\n private wasPlayingBeforeSeek = false;\n\n // Unified window management for both video and audio\n private windowEnd: TimeUs = 0;\n private readonly WINDOW_DURATION = 3_000_000; // 3s decode window\n private readonly PREHEAT_DISTANCE = 1_000_000; // 1s preheat trigger distance\n private preheatInProgress = false;\n\n constructor(orchestrator: Orchestrator, eventBus: IEventBus, options: PlaybackOptions) {\n this.orchestrator = orchestrator;\n this.eventBus = eventBus;\n this.canvas = options.canvas;\n\n // Initialize VideoComposer for real-time composition\n // Pass canvas as externalCanvas for direct rendering\n const model = orchestrator.compositionModel;\n\n // FIX: Prioritize model renderConfig over canvas current dimensions\n // The canvas should act as a viewport into the renderConfig resolution\n const width = model?.renderConfig?.width || this.canvas.width || 720;\n const height = model?.renderConfig?.height || this.canvas.height || 1280;\n\n this.videoComposer = new VideoComposer({\n width,\n height,\n fps: model?.fps || 30,\n backgroundColor: model?.renderConfig?.backgroundColor || '#000',\n externalCanvas: this.canvas,\n });\n\n // Set initial time if provided\n if (options.startUs !== undefined) {\n this.currentTimeUs = options.startUs;\n }\n\n if (options.rate !== undefined) {\n this.playbackRate = options.rate;\n }\n\n if (options.loop !== undefined) {\n this.loop = options.loop;\n }\n\n if (options.autoStart) {\n this.play();\n }\n\n this.setupEventListeners();\n }\n\n async renderCover(): Promise<void> {\n await this.renderCurrentFrame(0);\n }\n\n // Playback control\n play(): void {\n if (this.state === 'playing') return;\n\n // If playback has ended, reset audio scheduling states for clean replay\n if (this.state === 'ended') {\n this.audioSession?.resetPlaybackStates();\n }\n\n this.wasPlayingBeforeSeek = true; // User wants to play\n void this.startPlayback();\n }\n\n private async startPlayback(): Promise<void> {\n const wasIdle = this.state === 'idle';\n const seekId = this.currentSeekId;\n\n try {\n // Render first frame (may trigger buffering if cache miss)\n await this.renderCurrentFrame(this.currentTimeUs);\n\n // Check if seek happened during render\n if (seekId !== this.currentSeekId) {\n return;\n }\n\n this.state = 'playing';\n await this.ensureAudioContext();\n\n // Initialize windows BEFORE starting audio playback\n this.initWindow(this.currentTimeUs);\n\n if (this.audioSession && this.audioContext) {\n await this.audioSession.startPlayback(this.currentTimeUs, this.audioContext);\n }\n\n this.startTimeUs =\n this.audioContext!.currentTime * 1_000_000 - this.currentTimeUs / this.playbackRate;\n\n this.playbackLoop();\n\n this.eventBus.emit(MeframeEvent.PlaybackPlay);\n } catch (error) {\n console.error('[PlaybackController] Failed to start playback:', error);\n this.state = wasIdle ? 'idle' : 'paused';\n this.eventBus.emit(MeframeEvent.PlaybackError, error as Error);\n }\n }\n\n pause(): void {\n if (this.state !== 'playing') return;\n\n this.state = 'paused';\n this.wasPlayingBeforeSeek = false; // User explicitly paused\n\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n\n this.audioSession?.stopPlayback();\n\n this.eventBus.emit(MeframeEvent.PlaybackPause);\n }\n\n stop(): void {\n this.pause();\n this.currentTimeUs = 0;\n this.state = 'idle';\n this.wasPlayingBeforeSeek = false; // Reset seek state\n this.frameCount = 0; // Reset frame counter\n this.lastFrameTime = 0; // Reset frame timing\n\n // Clear canvas\n const ctx = this.canvas.getContext('2d') as\n | CanvasRenderingContext2D\n | OffscreenCanvasRenderingContext2D\n | null;\n if (ctx && 'clearRect' in ctx) {\n ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);\n }\n\n this.audioSession?.reset();\n this.audioSession?.resetPlaybackStates();\n\n this.eventBus.emit(MeframeEvent.PlaybackStop);\n }\n\n async seek(timeUs: TimeUs): Promise<void> {\n const previousState = this.state;\n\n // Stop playback without changing wasPlayingBeforeSeek\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n this.audioSession?.stopPlayback();\n\n // Reset audio playback states for all clips\n this.audioSession?.resetPlaybackStates();\n\n const clamped = this.clampTime(timeUs);\n this.currentTimeUs = clamped;\n this.currentSeekId++; // Invalidate previous seek operations\n this.isBuffering = false; // Reset buffering flag\n\n // Initialize window at seek position\n this.initWindow(clamped);\n\n this.state = 'seeking';\n\n const seekId = this.currentSeekId;\n\n try {\n // Ensure audio windows ready for seek position (blocking mode)\n if (this.audioSession) {\n await this.audioSession.ensureAudioForTime(clamped, { immediate: false });\n }\n\n await this.renderCurrentFrame(clamped);\n\n // Check if another seek happened during render\n if (seekId !== this.currentSeekId) {\n return;\n }\n\n this.eventBus.emit(MeframeEvent.PlaybackSeek, { timeUs: this.currentTimeUs });\n\n if (this.wasPlayingBeforeSeek) {\n await this.startPlayback();\n } else {\n this.state = previousState === 'idle' ? 'idle' : 'paused';\n }\n } catch (error) {\n // Check if this seek is still current\n if (seekId !== this.currentSeekId) {\n return;\n }\n console.error('[PlaybackController] Seek error:', error);\n this.eventBus.emit(MeframeEvent.PlaybackError, error as Error);\n this.state = previousState === 'idle' ? 'idle' : 'paused';\n }\n }\n\n // Playback properties\n setRate(rate: number): void {\n // Adjust audio start time to maintain current position\n const currentTimeUs = this.currentTimeUs;\n this.playbackRate = rate;\n this.startTimeUs = this.audioContext!.currentTime * 1_000_000 - currentTimeUs / rate;\n\n this.eventBus.emit(MeframeEvent.PlaybackRateChange, { rate });\n\n this.audioSession?.setPlaybackRate(this.playbackRate);\n }\n\n setVolume(volume: number): void {\n this.volume = Math.max(0, Math.min(1, volume));\n this.eventBus.emit(MeframeEvent.PlaybackVolumeChange, { volume: this.volume });\n\n this.audioSession?.setVolume(this.volume);\n }\n\n setMute(muted: boolean): void {\n if (muted) {\n this.audioSession?.stopPlayback();\n } else if (this.state === 'playing' && this.audioContext) {\n this.audioSession?.startPlayback(this.currentTimeUs, this.audioContext);\n }\n }\n\n setLoop(loop: boolean): void {\n this.loop = loop;\n }\n\n get duration(): TimeUs {\n const modelDuration = this.orchestrator.compositionModel?.durationUs;\n if (modelDuration !== undefined) {\n return modelDuration;\n }\n\n return 0;\n }\n\n get isPlaying(): boolean {\n return this.state === 'playing';\n }\n\n setAudioSession(session: GlobalAudioSession): void {\n this.audioSession = session;\n }\n\n // Resume is just an alias for play\n resume(): void {\n this.play();\n }\n\n on(event: string, handler: (payload: any) => void): void {\n this.eventBus.on(event as MeframeEvent, handler);\n }\n\n off(event: string, handler: (payload: any) => void): void {\n this.eventBus.off(event as MeframeEvent, handler);\n }\n\n // Private methods\n private playbackLoop(): void {\n // State Check #1: Loop entry (from recursive call)\n // Prevents next frame from starting if state changed during previous frame\n // Captures: pause(), stop(), seek() called during frame processing\n if (this.state !== 'playing') {\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n return;\n }\n\n this.rafId = requestAnimationFrame(async () => {\n // State Check #2: RAF callback start (async boundary)\n // Captures state changes during RAF delay (~16ms)\n // Scenario: User pauses/seeks between requestAnimationFrame call and callback execution\n if (this.state !== 'playing') {\n return;\n }\n\n this.updateTime();\n\n // State Check #3: After updateTime (playback end detection)\n // CRITICAL: Prevents ensureAudioForTime/scheduleAudio from polluting cache\n // When playback ends, currentTimeUs is reset to 0 for clean replay\n // Without this check, audio operations would execute with wrong position\n if (this.state !== 'playing') {\n return;\n }\n\n // Ensure audio windows ready (aligned with video architecture)\n // Use immediate mode during playback (non-blocking)\n if (this.audioSession) {\n await this.audioSession.ensureAudioForTime(this.currentTimeUs, { immediate: true });\n }\n\n // Lookahead audio scheduling (OfflineAudioMixer approach)\n if (this.audioContext && this.audioSession) {\n await this.audioSession.scheduleAudio(this.currentTimeUs, this.audioContext);\n }\n\n await this.renderCurrentFrame(this.currentTimeUs);\n\n // State Check #4: After render (buffering detection)\n // Captures: renderCurrentFrame() triggered buffering (cache miss)\n // Optimization: Early exit to avoid unnecessary FPS calculation and setWindow\n // Not strictly required (next loop's Check #1 would catch it), but improves responsiveness\n if (this.state !== 'playing') {\n return;\n }\n\n // Calculate FPS based on actual frame timing\n const now = performance.now();\n if (this.lastFrameTime > 0) {\n const deltaTime = now - this.lastFrameTime;\n const instantFps = 1000 / deltaTime;\n this.fps = this.fps > 0 ? this.fps * 0.9 + instantFps * 0.1 : instantFps;\n }\n this.lastFrameTime = now;\n\n this.frameCount++;\n\n // Update unified window for video and audio\n this.orchestrator.cacheManager.setWindow(this.currentTimeUs);\n\n this.playbackLoop();\n });\n }\n\n private updateTime(): void {\n const elapsedUs =\n (this.audioContext!.currentTime * 1_000_000 - this.startTimeUs) * this.playbackRate;\n this.currentTimeUs = elapsedUs;\n\n // Check if reached end\n if (this.currentTimeUs >= this.duration) {\n if (this.loop) {\n this.currentTimeUs = 0;\n this.startTimeUs = this.audioContext!.currentTime * 1_000_000;\n // Reset audio scheduling states to avoid stale state from previous playback\n this.audioSession?.resetPlaybackStates();\n // Reset window to start position\n this.initWindow(0);\n } else {\n this.pause();\n // Set to 0 instead of duration to prevent audio operations in final frame\n // from polluting cache with wrong position data\n this.currentTimeUs = 0;\n this.state = 'ended';\n this.eventBus.emit(MeframeEvent.PlaybackEnded, { timeUs: this.duration });\n }\n }\n\n // Emit time update\n this.eventBus.emit(MeframeEvent.PlaybackTimeUpdate, { timeUs: this.currentTimeUs });\n\n // Check if approaching window edge - trigger async preheat\n this.checkAndPreheatWindow();\n // Note: setWindow is now called in Orchestrator.renderFrame()\n // this.orchestrator.cacheManager.setWindow(this.currentTimeUs);\n }\n\n /**\n * Initialize window at given time (called on play/seek)\n * Sets unified window for both video and audio\n */\n private initWindow(timeUs: TimeUs): void {\n this.windowEnd = timeUs + this.WINDOW_DURATION;\n this.preheatInProgress = false; // Reset preheat state\n\n // Set unified window center for both video and audio\n this.orchestrator.cacheManager.setWindow(timeUs);\n }\n\n /**\n * Check if approaching window end and trigger preheat for next window\n *\n * Strategy: Unified sliding window for both video and audio\n * - Current window: [windowStart, windowEnd] (3s duration)\n * - When playback reaches windowEnd - 1s, preheat next window\n * - Next window: [windowEnd, windowEnd + 3s]\n */\n private checkAndPreheatWindow(): void {\n // Skip if already preheating or not playing\n if (this.preheatInProgress || this.state !== 'playing') {\n return;\n }\n\n // Check if approaching window end\n const distanceToWindowEnd = this.windowEnd - this.currentTimeUs;\n if (distanceToWindowEnd < 0) {\n this.initWindow(this.currentTimeUs);\n return;\n }\n\n // Trigger preheat when 1s from window end\n if (distanceToWindowEnd > 0 && distanceToWindowEnd <= this.PREHEAT_DISTANCE) {\n this.preheatInProgress = true;\n\n void this.preheatNextWindow().finally(() => {\n this.preheatInProgress = false;\n });\n }\n }\n\n /**\n * Preheat next window by decoding from current playback time\n * Supports cross-clip window preheating for seamless playback\n * Preheats both video and audio in parallel\n */\n private async preheatNextWindow(): Promise<void> {\n try {\n const windowStart = this.currentTimeUs;\n const windowEnd = windowStart + this.WINDOW_DURATION;\n\n // Get all clips in window range (may span multiple clips)\n const clipsInWindow =\n this.orchestrator.compositionModel?.getClipsInRange(windowStart, windowEnd) ?? [];\n\n const preheatPromises: Promise<any>[] = [];\n\n // Preheat video for each clip in window\n for (const clip of clipsInWindow) {\n if (!isVideoClip(clip)) continue;\n\n // Calculate clip-relative window boundaries\n const clipWindowStart = Math.max(0, windowStart - clip.startUs);\n const clipWindowEnd = Math.min(clip.durationUs, windowEnd - clip.startUs);\n\n // Skip if window doesn't overlap with this clip\n if (clipWindowStart >= clipWindowEnd) continue;\n\n preheatPromises.push(\n this.orchestrator.preheatClipWindow(clip.id, clipWindowStart, clipWindowEnd, windowStart)\n );\n }\n\n // Preheat audio (non-blocking mode for background decoding)\n if (this.audioSession) {\n preheatPromises.push(\n this.audioSession.ensureAudioForTime(windowStart, { immediate: false })\n );\n }\n\n await Promise.all(preheatPromises);\n\n // Update window bounds after successful preheat\n this.windowEnd = windowEnd;\n } catch (error) {\n // Preheat failures are not critical\n console.warn('[PlaybackController] Preheat failed:', error);\n }\n }\n\n async renderCurrentFrame(timeUs: TimeUs): Promise<void> {\n if (!this.videoComposer) {\n console.error('[PlaybackController] VideoComposer not initialized');\n return;\n }\n\n try {\n // Get render state (layers) from orchestrator\n // Use immediate mode when playing to detect buffering\n const renderState = await this.orchestrator.getRenderState(timeUs, {\n immediate: this.state === 'playing',\n });\n\n if (!renderState) {\n // If renderState is null during playback, we hit a cache miss/buffer underrun\n if (this.state === 'playing' && !this.isBuffering) {\n await this.handlePlaybackBuffering(timeUs);\n }\n return;\n }\n\n // Compose directly to canvas\n await this.videoComposer.composeFrame({\n timeUs,\n layers: renderState.layers,\n transition: renderState.transition,\n });\n } catch (error) {\n console.error('Render error:', error);\n this.eventBus.emit(MeframeEvent.PlaybackError, error as Error);\n }\n }\n\n private async handlePlaybackBuffering(timeUs: TimeUs): Promise<void> {\n if (this.isBuffering || this.state !== 'playing') {\n return;\n }\n\n const seekId = this.currentSeekId;\n this.isBuffering = true;\n this.state = 'buffering';\n this.eventBus.emit(MeframeEvent.PlaybackBuffering);\n\n // Pause audio immediately to prevent desync\n this.audioSession?.stopPlayback();\n\n try {\n // Update window center for buffering position\n this.orchestrator.cacheManager.setWindow(timeUs);\n\n // Force load frame (blocking)\n // This ensures the resource is downloaded and decoded\n await this.orchestrator.getFrame(timeUs, { immediate: false });\n\n // Also ensure audio is ready (blocking mode for buffering)\n await this.orchestrator.audioSession.ensureAudioForTime(timeUs, { immediate: false });\n\n // Check if seek happened during buffering\n if (seekId !== this.currentSeekId) {\n return;\n }\n\n this.state = 'playing';\n this.startTimeUs = this.audioContext!.currentTime * 1_000_000 - timeUs / this.playbackRate;\n\n // Resume audio synced with timeline\n if (this.audioContext) {\n await this.audioSession?.startPlayback(timeUs, this.audioContext);\n }\n\n this.eventBus.emit(MeframeEvent.PlaybackPlay);\n\n if (!this.rafId) {\n this.playbackLoop();\n }\n } catch (error) {\n // Ignore WaiterReplacedError (happens during fast seeks)\n if (error instanceof WaiterReplacedError) {\n return;\n }\n // Check if seek happened during error handling\n if (seekId !== this.currentSeekId) {\n return;\n }\n console.error('[PlaybackController] Buffering error:', error);\n this.state = 'paused';\n this.eventBus.emit(MeframeEvent.PlaybackError, error as Error);\n } finally {\n this.isBuffering = false;\n }\n }\n\n private clampTime(timeUs: TimeUs): TimeUs {\n return Math.max(0, Math.min(timeUs, this.duration));\n }\n\n // Cleanup\n dispose(): void {\n this.stop();\n this.eventBus.off(MeframeEvent.CacheCover, this.onCacheCover);\n this.eventBus.off(MeframeEvent.ModelSet, this.onModelSet);\n if (this.videoComposer) {\n this.videoComposer.dispose();\n this.videoComposer = null;\n }\n }\n\n private onCacheCover = (): void => {\n // Optimization for Quick Start / Fast First Frame:\n // When the first frame of a resource is decoded (e.g. via side-channel parsing),\n // we immediately render it if we are at the start of the timeline.\n // This significantly improves perceived loading speed for compatible formats (e.g. fragmented MP4 with moov at start).\n // For standard formats or when not at time 0, this might be redundant as normal playback loop handles it.\n if (this.state === 'idle' && this.currentTimeUs === 0) {\n this.renderCurrentFrame(0);\n }\n };\n\n private onModelSet = (): void => {\n if (!this.videoComposer || !this.orchestrator.compositionModel) return;\n\n const model = this.orchestrator.compositionModel;\n // Update VideoComposer configuration with new model dimensions and fps\n this.videoComposer.updateConfig({\n width: model.renderConfig?.width || 720,\n height: model.renderConfig?.height || 1280,\n fps: model.fps || 30,\n backgroundColor: model.renderConfig?.backgroundColor || '#000',\n });\n\n // Preheat audio for first frame (non-blocking)\n if (this.audioSession) {\n void this.audioSession.ensureAudioForTime(0, { immediate: false });\n }\n\n // Re-render current frame to reflect dimension changes immediately\n void this.renderCurrentFrame(this.currentTimeUs);\n };\n\n private setupEventListeners(): void {\n this.eventBus.on(MeframeEvent.CacheCover, this.onCacheCover);\n this.eventBus.on(MeframeEvent.ModelSet, this.onModelSet);\n }\n\n private async ensureAudioContext(): Promise<void> {\n if (this.audioContext) {\n return;\n }\n\n this.audioContext = new AudioContext();\n }\n}\n"],"names":[],"mappings":"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"}
|
package/dist/event/events.d.ts
CHANGED
|
@@ -227,7 +227,7 @@ export interface EventPayloadMap {
|
|
|
227
227
|
};
|
|
228
228
|
[MeframeEvent.ExportProgress]: {
|
|
229
229
|
progress: number;
|
|
230
|
-
stage?: 'preparing' | 'muxing';
|
|
230
|
+
stage?: 'preparing' | 'encoding' | 'muxing';
|
|
231
231
|
message?: string;
|
|
232
232
|
currentFrame?: number;
|
|
233
233
|
totalFrames?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/event/events.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/event/events.ts"],"names":[],"mappings":"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"}
|
package/dist/event/events.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.js","sources":["../../src/event/events.ts"],"sourcesContent":["/**\n * Core event definitions for the Meframe engine\n * These are public events exposed to plugins and external components\n */\n\nimport { CompositionModel, Resource, type TimeUs } from '../model';\nimport type { MP4Index } from '../stages/demux/types';\n\nexport interface ResourceEvent {\n type: MeframeEvent;\n resourceId: string;\n resource?: Resource;\n oldState?: Resource['state'];\n newState?: Resource['state'];\n workerType?: string;\n}\n\n/**\n * Core event types\n */\nexport enum MeframeEvent {\n // Composition model events\n ModelSet = 'model:set',\n\n // Resource events\n ResourceAdd = 'resource:add',\n ResourceUpdate = 'resource:update',\n ResourceRemove = 'resource:remove',\n ResourceStageChange = 'resource:state',\n ResourceFirstFrameReady = 'resource:firstFrameReady',\n\n // Load stage events\n LoadStart = 'load:start',\n LoadProgress = 'load:progress',\n LoadComplete = 'load:complete',\n LoadError = 'load:error',\n\n // Demux stage events\n DemuxStart = 'demux:start',\n DemuxProgress = 'demux:progress',\n DemuxComplete = 'demux:complete',\n DemuxError = 'demux:error',\n\n // Decode stage events\n DecodeStart = 'decode:start',\n DecodeProgress = 'decode:progress',\n DecodeComplete = 'decode:complete',\n DecodeError = 'decode:error',\n\n // Compose stage events\n ComposeStart = 'compose:start',\n ComposeProgress = 'compose:progress',\n ComposeComplete = 'compose:complete',\n\n // Composition frame events (L1 cache)\n ComposeFrameReady = 'compose:frameReady',\n ComposeFrameDropped = 'compose:frameDropped',\n\n // Encode events (L2 cache)\n EncodeChunkReady = 'encode:chunkReady',\n EncodeChunkError = 'encode:chunkError',\n\n // Cache events\n CacheHit = 'cache:hit',\n CacheMiss = 'cache:miss',\n CacheEvict = 'cache:evict',\n CacheWrite = 'cache:write',\n CacheCover = 'cache:cover',\n\n // Export events\n ExportPreparing = 'export:preparing',\n ExportStart = 'export:start',\n ExportProgress = 'export:progress',\n ExportComplete = 'export:complete',\n ExportError = 'export:error',\n\n // Composition model events\n CompositionUpdated = 'composition:updated',\n PatchApplied = 'patch:applied',\n Ready = 'ready',\n\n // Worker events\n WorkerStarted = 'worker:started',\n WorkerReady = 'worker:ready',\n WorkerError = 'worker:error',\n WorkerRestarted = 'worker:restarted',\n\n // Playback events\n PlaybackBuffering = 'playback:buffering',\n PlaybackPlay = 'playback:play',\n PlaybackPause = 'playback:pause',\n PlaybackStop = 'playback:stop',\n PlaybackSeek = 'playback:seek',\n PlaybackEnded = 'playback:ended',\n PlaybackTimeUpdate = 'playback:timeupdate',\n PlaybackRateChange = 'playback:ratechange',\n PlaybackVolumeChange = 'playback:volumechange',\n PlaybackError = 'playback:error',\n PlaybackStarted = 'playback:started',\n PlaybackPaused = 'playback:paused',\n PlaybackSeeked = 'playback:seeked',\n\n // General error event\n Error = 'error',\n\n // Plugin events\n PluginLoaded = 'plugin:loaded',\n PluginError = 'plugin:error',\n PluginUnloaded = 'plugin:unloaded',\n\n // Clip lifecycle events\n ClipActivated = 'clip:activated',\n ClipDeactivated = 'clip:deactivated',\n}\n\n/**\n * Event payload definitions\n */\nexport interface EventPayloadMap {\n // Composition model events\n [MeframeEvent.ModelSet]: CompositionModel;\n\n // Resource events\n [MeframeEvent.ResourceAdd]: ResourceEvent;\n [MeframeEvent.ResourceUpdate]: ResourceEvent;\n [MeframeEvent.ResourceRemove]: ResourceEvent;\n [MeframeEvent.ResourceStageChange]: ResourceEvent;\n [MeframeEvent.ResourceFirstFrameReady]: {\n resourceId: string;\n clipId: string;\n index: MP4Index;\n chunks: EncodedVideoChunk[];\n };\n\n // Load events\n [MeframeEvent.LoadStart]: {\n resourceId: string;\n url: string;\n size?: number;\n };\n\n [MeframeEvent.LoadProgress]: {\n resourceId: string;\n loaded: number;\n total: number;\n progress: number;\n };\n\n [MeframeEvent.LoadComplete]: {\n resourceId: string;\n bytes: number;\n durationMs: number;\n };\n\n [MeframeEvent.LoadError]: {\n resourceId: string;\n error: Error;\n retry?: boolean;\n };\n\n // Demux events\n [MeframeEvent.DemuxStart]: {\n clipId: string;\n trackId?: string;\n format?: string;\n };\n\n [MeframeEvent.DemuxProgress]: {\n clipId: string;\n progress: number;\n };\n\n [MeframeEvent.DemuxComplete]: {\n clipId: string;\n trackCount: number;\n durationUs: TimeUs;\n };\n\n [MeframeEvent.DemuxError]: {\n clipId: string;\n error: Error;\n };\n\n // Decode events\n [MeframeEvent.DecodeStart]: {\n clipId: string;\n frameCount?: number;\n trackType: 'video' | 'audio';\n };\n\n [MeframeEvent.DecodeProgress]: {\n clipId: string;\n decodedFrames: number;\n totalFrames: number;\n progress: number;\n };\n\n [MeframeEvent.DecodeComplete]: {\n clipId: string;\n frameCount: number;\n durationUs: TimeUs;\n };\n\n [MeframeEvent.DecodeError]: {\n clipId: string;\n error: Error;\n frame?: number;\n };\n\n // Compose events\n [MeframeEvent.ComposeStart]: {\n timeUs: TimeUs;\n clipIds: string[];\n };\n\n [MeframeEvent.ComposeProgress]: {\n timeUs: TimeUs;\n progress: number;\n };\n\n [MeframeEvent.ComposeComplete]: {\n timeUs: TimeUs;\n frameNumber: number;\n };\n\n // Composition frame events\n [MeframeEvent.ComposeFrameReady]: {\n timeUs: TimeUs;\n frameNumber: number;\n renderTimeMs: number;\n trackId: string;\n clipId: string;\n };\n\n [MeframeEvent.ComposeFrameDropped]: {\n timeUs: TimeUs;\n reason: 'decode_slow' | 'compose_slow' | 'backpressure';\n };\n\n // Encode events\n [MeframeEvent.EncodeChunkReady]: {\n timeUs: TimeUs;\n durationUs: TimeUs;\n track: 'video' | 'audio';\n size: number;\n };\n\n [MeframeEvent.EncodeChunkError]: {\n timeUs: TimeUs;\n track: 'video' | 'audio';\n error: Error;\n };\n\n // Cache events\n [MeframeEvent.CacheHit]: {\n timeUs: TimeUs;\n level: 'L1' | 'L2';\n key?: string;\n };\n\n [MeframeEvent.CacheMiss]: {\n timeUs: TimeUs;\n level: 'L1' | 'L2';\n key?: string;\n };\n\n [MeframeEvent.CacheEvict]: {\n clipId: string;\n count: number;\n level: 'L1' | 'L2';\n reason: 'size' | 'ttl' | 'manual';\n };\n\n [MeframeEvent.CacheWrite]: {\n clipId: string;\n timeUs: TimeUs;\n level: 'L1' | 'L2';\n size: number;\n };\n [MeframeEvent.CacheCover]: {\n clipId: string;\n timeUs: TimeUs;\n level: 'L1' | 'L2';\n size: number;\n };\n\n // Export events\n [MeframeEvent.ExportPreparing]: {\n totalClips: number;\n cachedClips: number;\n missingClips: string[];\n estimatedTimeMs?: number;\n };\n\n [MeframeEvent.ExportStart]: {\n format: string;\n width: number;\n height: number;\n fps: number;\n durationUs: TimeUs;\n };\n\n [MeframeEvent.ExportProgress]: {\n progress: number;\n stage?: 'preparing' | 'muxing';\n message?: string;\n currentFrame?: number;\n totalFrames?: number;\n timeUs?: TimeUs;\n };\n\n [MeframeEvent.ExportComplete]: {\n size: number;\n durationMs: number;\n format: string;\n };\n\n [MeframeEvent.ExportError]: {\n error: Error;\n stage?: string;\n };\n\n // Composition events\n [MeframeEvent.CompositionUpdated]: {\n trackCount: number;\n clipCount: number;\n durationUs: TimeUs;\n };\n\n [MeframeEvent.PatchApplied]: {\n operations: number;\n affectedClips: string[];\n };\n\n [MeframeEvent.Ready]: {\n trackCount: number;\n clipCount: number;\n durationUs: TimeUs;\n };\n\n // Worker events\n [MeframeEvent.WorkerStarted]: {\n type: string;\n workerId: string;\n };\n\n [MeframeEvent.WorkerReady]: {\n type: string;\n workerId: string;\n };\n\n [MeframeEvent.WorkerError]: {\n type: string;\n workerId: string;\n error: Error;\n };\n\n [MeframeEvent.WorkerRestarted]: {\n type: string;\n workerId: string;\n reason: string;\n };\n\n // Playback events\n [MeframeEvent.PlaybackBuffering]: undefined;\n\n [MeframeEvent.PlaybackPlay]: undefined;\n\n [MeframeEvent.PlaybackPause]: undefined;\n\n [MeframeEvent.PlaybackStop]: undefined;\n\n [MeframeEvent.PlaybackSeek]: {\n timeUs: TimeUs;\n };\n\n [MeframeEvent.PlaybackStarted]: {\n timeUs: TimeUs;\n };\n\n [MeframeEvent.PlaybackPaused]: {\n timeUs: TimeUs;\n };\n\n [MeframeEvent.PlaybackSeeked]: {\n fromUs: TimeUs;\n toUs: TimeUs;\n };\n\n [MeframeEvent.PlaybackEnded]: {\n timeUs: TimeUs;\n };\n\n [MeframeEvent.PlaybackTimeUpdate]: {\n timeUs: TimeUs;\n };\n\n [MeframeEvent.PlaybackRateChange]: {\n rate: number;\n };\n\n [MeframeEvent.PlaybackVolumeChange]: {\n volume: number;\n };\n\n [MeframeEvent.PlaybackError]: Error;\n\n // Error event\n [MeframeEvent.Error]: {\n source: string;\n error: Error;\n context?: any;\n recoverable?: boolean;\n };\n\n // Plugin events\n [MeframeEvent.PluginLoaded]: {\n name: string;\n version?: string;\n };\n\n [MeframeEvent.PluginError]: {\n plugin: string;\n error: Error;\n };\n\n [MeframeEvent.PluginUnloaded]: {\n name: string;\n };\n\n // Clip events\n [MeframeEvent.ClipActivated]: {\n clipId: string;\n };\n\n [MeframeEvent.ClipDeactivated]: {\n clipId: string;\n };\n}\n"],"names":["MeframeEvent"],"mappings":"AAoBO,IAAK,iCAAAA,kBAAL;AAELA,gBAAA,UAAA,IAAW;AAGXA,gBAAA,aAAA,IAAc;AACdA,gBAAA,gBAAA,IAAiB;AACjBA,gBAAA,gBAAA,IAAiB;AACjBA,gBAAA,qBAAA,IAAsB;AACtBA,gBAAA,yBAAA,IAA0B;AAG1BA,gBAAA,WAAA,IAAY;AACZA,gBAAA,cAAA,IAAe;AACfA,gBAAA,cAAA,IAAe;AACfA,gBAAA,WAAA,IAAY;AAGZA,gBAAA,YAAA,IAAa;AACbA,gBAAA,eAAA,IAAgB;AAChBA,gBAAA,eAAA,IAAgB;AAChBA,gBAAA,YAAA,IAAa;AAGbA,gBAAA,aAAA,IAAc;AACdA,gBAAA,gBAAA,IAAiB;AACjBA,gBAAA,gBAAA,IAAiB;AACjBA,gBAAA,aAAA,IAAc;AAGdA,gBAAA,cAAA,IAAe;AACfA,gBAAA,iBAAA,IAAkB;AAClBA,gBAAA,iBAAA,IAAkB;AAGlBA,gBAAA,mBAAA,IAAoB;AACpBA,gBAAA,qBAAA,IAAsB;AAGtBA,gBAAA,kBAAA,IAAmB;AACnBA,gBAAA,kBAAA,IAAmB;AAGnBA,gBAAA,UAAA,IAAW;AACXA,gBAAA,WAAA,IAAY;AACZA,gBAAA,YAAA,IAAa;AACbA,gBAAA,YAAA,IAAa;AACbA,gBAAA,YAAA,IAAa;AAGbA,gBAAA,iBAAA,IAAkB;AAClBA,gBAAA,aAAA,IAAc;AACdA,gBAAA,gBAAA,IAAiB;AACjBA,gBAAA,gBAAA,IAAiB;AACjBA,gBAAA,aAAA,IAAc;AAGdA,gBAAA,oBAAA,IAAqB;AACrBA,gBAAA,cAAA,IAAe;AACfA,gBAAA,OAAA,IAAQ;AAGRA,gBAAA,eAAA,IAAgB;AAChBA,gBAAA,aAAA,IAAc;AACdA,gBAAA,aAAA,IAAc;AACdA,gBAAA,iBAAA,IAAkB;AAGlBA,gBAAA,mBAAA,IAAoB;AACpBA,gBAAA,cAAA,IAAe;AACfA,gBAAA,eAAA,IAAgB;AAChBA,gBAAA,cAAA,IAAe;AACfA,gBAAA,cAAA,IAAe;AACfA,gBAAA,eAAA,IAAgB;AAChBA,gBAAA,oBAAA,IAAqB;AACrBA,gBAAA,oBAAA,IAAqB;AACrBA,gBAAA,sBAAA,IAAuB;AACvBA,gBAAA,eAAA,IAAgB;AAChBA,gBAAA,iBAAA,IAAkB;AAClBA,gBAAA,gBAAA,IAAiB;AACjBA,gBAAA,gBAAA,IAAiB;AAGjBA,gBAAA,OAAA,IAAQ;AAGRA,gBAAA,cAAA,IAAe;AACfA,gBAAA,aAAA,IAAc;AACdA,gBAAA,gBAAA,IAAiB;AAGjBA,gBAAA,eAAA,IAAgB;AAChBA,gBAAA,iBAAA,IAAkB;AA5FR,SAAAA;AAAA,GAAA,gBAAA,CAAA,CAAA;"}
|
|
1
|
+
{"version":3,"file":"events.js","sources":["../../src/event/events.ts"],"sourcesContent":["/**\n * Core event definitions for the Meframe engine\n * These are public events exposed to plugins and external components\n */\n\nimport { CompositionModel, Resource, type TimeUs } from '../model';\nimport type { MP4Index } from '../stages/demux/types';\n\nexport interface ResourceEvent {\n type: MeframeEvent;\n resourceId: string;\n resource?: Resource;\n oldState?: Resource['state'];\n newState?: Resource['state'];\n workerType?: string;\n}\n\n/**\n * Core event types\n */\nexport enum MeframeEvent {\n // Composition model events\n ModelSet = 'model:set',\n\n // Resource events\n ResourceAdd = 'resource:add',\n ResourceUpdate = 'resource:update',\n ResourceRemove = 'resource:remove',\n ResourceStageChange = 'resource:state',\n ResourceFirstFrameReady = 'resource:firstFrameReady',\n\n // Load stage events\n LoadStart = 'load:start',\n LoadProgress = 'load:progress',\n LoadComplete = 'load:complete',\n LoadError = 'load:error',\n\n // Demux stage events\n DemuxStart = 'demux:start',\n DemuxProgress = 'demux:progress',\n DemuxComplete = 'demux:complete',\n DemuxError = 'demux:error',\n\n // Decode stage events\n DecodeStart = 'decode:start',\n DecodeProgress = 'decode:progress',\n DecodeComplete = 'decode:complete',\n DecodeError = 'decode:error',\n\n // Compose stage events\n ComposeStart = 'compose:start',\n ComposeProgress = 'compose:progress',\n ComposeComplete = 'compose:complete',\n\n // Composition frame events (L1 cache)\n ComposeFrameReady = 'compose:frameReady',\n ComposeFrameDropped = 'compose:frameDropped',\n\n // Encode events (L2 cache)\n EncodeChunkReady = 'encode:chunkReady',\n EncodeChunkError = 'encode:chunkError',\n\n // Cache events\n CacheHit = 'cache:hit',\n CacheMiss = 'cache:miss',\n CacheEvict = 'cache:evict',\n CacheWrite = 'cache:write',\n CacheCover = 'cache:cover',\n\n // Export events\n ExportPreparing = 'export:preparing',\n ExportStart = 'export:start',\n ExportProgress = 'export:progress',\n ExportComplete = 'export:complete',\n ExportError = 'export:error',\n\n // Composition model events\n CompositionUpdated = 'composition:updated',\n PatchApplied = 'patch:applied',\n Ready = 'ready',\n\n // Worker events\n WorkerStarted = 'worker:started',\n WorkerReady = 'worker:ready',\n WorkerError = 'worker:error',\n WorkerRestarted = 'worker:restarted',\n\n // Playback events\n PlaybackBuffering = 'playback:buffering',\n PlaybackPlay = 'playback:play',\n PlaybackPause = 'playback:pause',\n PlaybackStop = 'playback:stop',\n PlaybackSeek = 'playback:seek',\n PlaybackEnded = 'playback:ended',\n PlaybackTimeUpdate = 'playback:timeupdate',\n PlaybackRateChange = 'playback:ratechange',\n PlaybackVolumeChange = 'playback:volumechange',\n PlaybackError = 'playback:error',\n PlaybackStarted = 'playback:started',\n PlaybackPaused = 'playback:paused',\n PlaybackSeeked = 'playback:seeked',\n\n // General error event\n Error = 'error',\n\n // Plugin events\n PluginLoaded = 'plugin:loaded',\n PluginError = 'plugin:error',\n PluginUnloaded = 'plugin:unloaded',\n\n // Clip lifecycle events\n ClipActivated = 'clip:activated',\n ClipDeactivated = 'clip:deactivated',\n}\n\n/**\n * Event payload definitions\n */\nexport interface EventPayloadMap {\n // Composition model events\n [MeframeEvent.ModelSet]: CompositionModel;\n\n // Resource events\n [MeframeEvent.ResourceAdd]: ResourceEvent;\n [MeframeEvent.ResourceUpdate]: ResourceEvent;\n [MeframeEvent.ResourceRemove]: ResourceEvent;\n [MeframeEvent.ResourceStageChange]: ResourceEvent;\n [MeframeEvent.ResourceFirstFrameReady]: {\n resourceId: string;\n clipId: string;\n index: MP4Index;\n chunks: EncodedVideoChunk[];\n };\n\n // Load events\n [MeframeEvent.LoadStart]: {\n resourceId: string;\n url: string;\n size?: number;\n };\n\n [MeframeEvent.LoadProgress]: {\n resourceId: string;\n loaded: number;\n total: number;\n progress: number;\n };\n\n [MeframeEvent.LoadComplete]: {\n resourceId: string;\n bytes: number;\n durationMs: number;\n };\n\n [MeframeEvent.LoadError]: {\n resourceId: string;\n error: Error;\n retry?: boolean;\n };\n\n // Demux events\n [MeframeEvent.DemuxStart]: {\n clipId: string;\n trackId?: string;\n format?: string;\n };\n\n [MeframeEvent.DemuxProgress]: {\n clipId: string;\n progress: number;\n };\n\n [MeframeEvent.DemuxComplete]: {\n clipId: string;\n trackCount: number;\n durationUs: TimeUs;\n };\n\n [MeframeEvent.DemuxError]: {\n clipId: string;\n error: Error;\n };\n\n // Decode events\n [MeframeEvent.DecodeStart]: {\n clipId: string;\n frameCount?: number;\n trackType: 'video' | 'audio';\n };\n\n [MeframeEvent.DecodeProgress]: {\n clipId: string;\n decodedFrames: number;\n totalFrames: number;\n progress: number;\n };\n\n [MeframeEvent.DecodeComplete]: {\n clipId: string;\n frameCount: number;\n durationUs: TimeUs;\n };\n\n [MeframeEvent.DecodeError]: {\n clipId: string;\n error: Error;\n frame?: number;\n };\n\n // Compose events\n [MeframeEvent.ComposeStart]: {\n timeUs: TimeUs;\n clipIds: string[];\n };\n\n [MeframeEvent.ComposeProgress]: {\n timeUs: TimeUs;\n progress: number;\n };\n\n [MeframeEvent.ComposeComplete]: {\n timeUs: TimeUs;\n frameNumber: number;\n };\n\n // Composition frame events\n [MeframeEvent.ComposeFrameReady]: {\n timeUs: TimeUs;\n frameNumber: number;\n renderTimeMs: number;\n trackId: string;\n clipId: string;\n };\n\n [MeframeEvent.ComposeFrameDropped]: {\n timeUs: TimeUs;\n reason: 'decode_slow' | 'compose_slow' | 'backpressure';\n };\n\n // Encode events\n [MeframeEvent.EncodeChunkReady]: {\n timeUs: TimeUs;\n durationUs: TimeUs;\n track: 'video' | 'audio';\n size: number;\n };\n\n [MeframeEvent.EncodeChunkError]: {\n timeUs: TimeUs;\n track: 'video' | 'audio';\n error: Error;\n };\n\n // Cache events\n [MeframeEvent.CacheHit]: {\n timeUs: TimeUs;\n level: 'L1' | 'L2';\n key?: string;\n };\n\n [MeframeEvent.CacheMiss]: {\n timeUs: TimeUs;\n level: 'L1' | 'L2';\n key?: string;\n };\n\n [MeframeEvent.CacheEvict]: {\n clipId: string;\n count: number;\n level: 'L1' | 'L2';\n reason: 'size' | 'ttl' | 'manual';\n };\n\n [MeframeEvent.CacheWrite]: {\n clipId: string;\n timeUs: TimeUs;\n level: 'L1' | 'L2';\n size: number;\n };\n [MeframeEvent.CacheCover]: {\n clipId: string;\n timeUs: TimeUs;\n level: 'L1' | 'L2';\n size: number;\n };\n\n // Export events\n [MeframeEvent.ExportPreparing]: {\n totalClips: number;\n cachedClips: number;\n missingClips: string[];\n estimatedTimeMs?: number;\n };\n\n [MeframeEvent.ExportStart]: {\n format: string;\n width: number;\n height: number;\n fps: number;\n durationUs: TimeUs;\n };\n\n [MeframeEvent.ExportProgress]: {\n progress: number;\n stage?: 'preparing' | 'encoding' | 'muxing';\n message?: string;\n currentFrame?: number;\n totalFrames?: number;\n timeUs?: TimeUs;\n };\n\n [MeframeEvent.ExportComplete]: {\n size: number;\n durationMs: number;\n format: string;\n };\n\n [MeframeEvent.ExportError]: {\n error: Error;\n stage?: string;\n };\n\n // Composition events\n [MeframeEvent.CompositionUpdated]: {\n trackCount: number;\n clipCount: number;\n durationUs: TimeUs;\n };\n\n [MeframeEvent.PatchApplied]: {\n operations: number;\n affectedClips: string[];\n };\n\n [MeframeEvent.Ready]: {\n trackCount: number;\n clipCount: number;\n durationUs: TimeUs;\n };\n\n // Worker events\n [MeframeEvent.WorkerStarted]: {\n type: string;\n workerId: string;\n };\n\n [MeframeEvent.WorkerReady]: {\n type: string;\n workerId: string;\n };\n\n [MeframeEvent.WorkerError]: {\n type: string;\n workerId: string;\n error: Error;\n };\n\n [MeframeEvent.WorkerRestarted]: {\n type: string;\n workerId: string;\n reason: string;\n };\n\n // Playback events\n [MeframeEvent.PlaybackBuffering]: undefined;\n\n [MeframeEvent.PlaybackPlay]: undefined;\n\n [MeframeEvent.PlaybackPause]: undefined;\n\n [MeframeEvent.PlaybackStop]: undefined;\n\n [MeframeEvent.PlaybackSeek]: {\n timeUs: TimeUs;\n };\n\n [MeframeEvent.PlaybackStarted]: {\n timeUs: TimeUs;\n };\n\n [MeframeEvent.PlaybackPaused]: {\n timeUs: TimeUs;\n };\n\n [MeframeEvent.PlaybackSeeked]: {\n fromUs: TimeUs;\n toUs: TimeUs;\n };\n\n [MeframeEvent.PlaybackEnded]: {\n timeUs: TimeUs;\n };\n\n [MeframeEvent.PlaybackTimeUpdate]: {\n timeUs: TimeUs;\n };\n\n [MeframeEvent.PlaybackRateChange]: {\n rate: number;\n };\n\n [MeframeEvent.PlaybackVolumeChange]: {\n volume: number;\n };\n\n [MeframeEvent.PlaybackError]: Error;\n\n // Error event\n [MeframeEvent.Error]: {\n source: string;\n error: Error;\n context?: any;\n recoverable?: boolean;\n };\n\n // Plugin events\n [MeframeEvent.PluginLoaded]: {\n name: string;\n version?: string;\n };\n\n [MeframeEvent.PluginError]: {\n plugin: string;\n error: Error;\n };\n\n [MeframeEvent.PluginUnloaded]: {\n name: string;\n };\n\n // Clip events\n [MeframeEvent.ClipActivated]: {\n clipId: string;\n };\n\n [MeframeEvent.ClipDeactivated]: {\n clipId: string;\n };\n}\n"],"names":["MeframeEvent"],"mappings":"AAoBO,IAAK,iCAAAA,kBAAL;AAELA,gBAAA,UAAA,IAAW;AAGXA,gBAAA,aAAA,IAAc;AACdA,gBAAA,gBAAA,IAAiB;AACjBA,gBAAA,gBAAA,IAAiB;AACjBA,gBAAA,qBAAA,IAAsB;AACtBA,gBAAA,yBAAA,IAA0B;AAG1BA,gBAAA,WAAA,IAAY;AACZA,gBAAA,cAAA,IAAe;AACfA,gBAAA,cAAA,IAAe;AACfA,gBAAA,WAAA,IAAY;AAGZA,gBAAA,YAAA,IAAa;AACbA,gBAAA,eAAA,IAAgB;AAChBA,gBAAA,eAAA,IAAgB;AAChBA,gBAAA,YAAA,IAAa;AAGbA,gBAAA,aAAA,IAAc;AACdA,gBAAA,gBAAA,IAAiB;AACjBA,gBAAA,gBAAA,IAAiB;AACjBA,gBAAA,aAAA,IAAc;AAGdA,gBAAA,cAAA,IAAe;AACfA,gBAAA,iBAAA,IAAkB;AAClBA,gBAAA,iBAAA,IAAkB;AAGlBA,gBAAA,mBAAA,IAAoB;AACpBA,gBAAA,qBAAA,IAAsB;AAGtBA,gBAAA,kBAAA,IAAmB;AACnBA,gBAAA,kBAAA,IAAmB;AAGnBA,gBAAA,UAAA,IAAW;AACXA,gBAAA,WAAA,IAAY;AACZA,gBAAA,YAAA,IAAa;AACbA,gBAAA,YAAA,IAAa;AACbA,gBAAA,YAAA,IAAa;AAGbA,gBAAA,iBAAA,IAAkB;AAClBA,gBAAA,aAAA,IAAc;AACdA,gBAAA,gBAAA,IAAiB;AACjBA,gBAAA,gBAAA,IAAiB;AACjBA,gBAAA,aAAA,IAAc;AAGdA,gBAAA,oBAAA,IAAqB;AACrBA,gBAAA,cAAA,IAAe;AACfA,gBAAA,OAAA,IAAQ;AAGRA,gBAAA,eAAA,IAAgB;AAChBA,gBAAA,aAAA,IAAc;AACdA,gBAAA,aAAA,IAAc;AACdA,gBAAA,iBAAA,IAAkB;AAGlBA,gBAAA,mBAAA,IAAoB;AACpBA,gBAAA,cAAA,IAAe;AACfA,gBAAA,eAAA,IAAgB;AAChBA,gBAAA,cAAA,IAAe;AACfA,gBAAA,cAAA,IAAe;AACfA,gBAAA,eAAA,IAAgB;AAChBA,gBAAA,oBAAA,IAAqB;AACrBA,gBAAA,oBAAA,IAAqB;AACrBA,gBAAA,sBAAA,IAAuB;AACvBA,gBAAA,eAAA,IAAgB;AAChBA,gBAAA,iBAAA,IAAkB;AAClBA,gBAAA,gBAAA,IAAiB;AACjBA,gBAAA,gBAAA,IAAiB;AAGjBA,gBAAA,OAAA,IAAQ;AAGRA,gBAAA,cAAA,IAAe;AACfA,gBAAA,aAAA,IAAc;AACdA,gBAAA,gBAAA,IAAiB;AAGjBA,gBAAA,eAAA,IAAgB;AAChBA,gBAAA,iBAAA,IAAkB;AA5FR,SAAAA;AAAA,GAAA,gBAAA,CAAA,CAAA;"}
|
|
@@ -22,6 +22,14 @@ export declare class CompositionModel {
|
|
|
22
22
|
findClip(id: string): Clip | null;
|
|
23
23
|
getClipsAtTime(timeUs: TimeUs, trackId?: string): Clip[];
|
|
24
24
|
getActiveClips(startUs: TimeUs, endUs: TimeUs): Clip[];
|
|
25
|
+
/**
|
|
26
|
+
* Get all clips in a specific track that overlap with the given time range
|
|
27
|
+
* Uses binary search for O(log n + k) performance
|
|
28
|
+
* @param startUs - Range start time (inclusive)
|
|
29
|
+
* @param endUs - Range end time (exclusive)
|
|
30
|
+
* @param trackId - Optional track ID to filter (defaults to main track)
|
|
31
|
+
*/
|
|
32
|
+
getClipsInRange(startUs: TimeUs, endUs: TimeUs, trackId?: string): Clip[];
|
|
25
33
|
getClipIdsByResourceId(resourceId: string): string[];
|
|
26
34
|
getClipIdAtTime(trackId: string, timeUs: TimeUs): string | undefined;
|
|
27
35
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CompositionModel.d.ts","sourceRoot":"","sources":["../../src/model/CompositionModel.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CompositionModel.d.ts","sourceRoot":"","sources":["../../src/model/CompositionModel.ts"],"names":[],"mappings":"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"}
|
|
@@ -79,6 +79,24 @@ ${errors.map((e) => `${e.path}: ${e.message}`).join("\n")}`
|
|
|
79
79
|
}
|
|
80
80
|
return clips;
|
|
81
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* Get all clips in a specific track that overlap with the given time range
|
|
84
|
+
* Uses binary search for O(log n + k) performance
|
|
85
|
+
* @param startUs - Range start time (inclusive)
|
|
86
|
+
* @param endUs - Range end time (exclusive)
|
|
87
|
+
* @param trackId - Optional track ID to filter (defaults to main track)
|
|
88
|
+
*/
|
|
89
|
+
getClipsInRange(startUs, endUs, trackId) {
|
|
90
|
+
const targetTrackId = trackId ?? this.mainTrackId;
|
|
91
|
+
const track = this.findTrack(targetTrackId);
|
|
92
|
+
if (!track) {
|
|
93
|
+
return [];
|
|
94
|
+
}
|
|
95
|
+
return binarySearchOverlapping(track.clips, startUs, endUs, (clip) => ({
|
|
96
|
+
start: clip.startUs,
|
|
97
|
+
end: clip.startUs + clip.durationUs
|
|
98
|
+
}));
|
|
99
|
+
}
|
|
82
100
|
getClipIdsByResourceId(resourceId) {
|
|
83
101
|
const resource = this.resources.get(resourceId);
|
|
84
102
|
return resource?.clipIds || [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CompositionModel.js","sources":["../../src/model/CompositionModel.ts"],"sourcesContent":["import {\n CompositionModelData,\n Track,\n Clip,\n Resource,\n TimeUs,\n AnimationEffect,\n hasResourceId,\n} from './types';\nimport { binarySearchRange, binarySearchOverlapping } from '../utils/binary-search';\nimport { validateCompositionStructure } from './validation';\n\nexport class CompositionModel {\n public readonly version = '1.0' as const;\n public readonly fps: 24 | 25 | 30 | 60;\n public durationUs!: TimeUs; // Assigned in buildIndexes()\n public readonly mainTrackId: string;\n public tracks: Track[];\n public readonly resources: Map<string, Resource>;\n\n private readonly trackMap: Map<string, Track>;\n private readonly clipMap: Map<string, Clip>;\n private readonly resourceRefCount: Map<string, number>;\n\n public readonly renderConfig?: {\n width: number;\n height: number;\n backgroundColor?: string;\n };\n\n public readonly ext?: Record<string, unknown>;\n\n constructor(data: CompositionModelData) {\n const errors = validateCompositionStructure(data);\n if (errors.length > 0) {\n throw new Error(\n `Validation failed:\\n${errors.map((e) => `${e.path}: ${e.message}`).join('\\n')}`\n );\n }\n\n this.fps = data.fps;\n this.mainTrackId = data.mainTrackId ?? 'main';\n this.tracks = data.tracks;\n this.resources = new Map(Object.entries(data.resources));\n this.renderConfig = data.renderConfig;\n this.ext = data.ext;\n\n // Build indexes\n this.trackMap = new Map();\n this.clipMap = new Map();\n this.resourceRefCount = new Map();\n\n this.buildIndexes();\n\n console.log(\n 'CompositionModel constructed',\n this.tracks.find((t) => t.id === this.mainTrackId)?.clips[0]\n );\n }\n\n // Track operations\n findTrack(id: string): Track | null {\n return this.trackMap.get(id) || null;\n }\n\n getTracksByKind(kind: 'video' | 'audio' | 'caption' | 'overlay' | 'fx'): Track[] {\n return this.tracks.filter((track) => track.kind === kind);\n }\n\n // Clip operations with binary search optimization\n findClip(id: string): Clip | null {\n return this.clipMap.get(id) || null;\n }\n\n getClipsAtTime(timeUs: TimeUs, trackId?: string): Clip[] {\n const tracks = trackId ? [this.findTrack(trackId)] : this.tracks;\n const clips: Clip[] = [];\n\n for (const track of tracks) {\n if (!track) continue;\n // Use binary search for single point lookup\n const clip = binarySearchRange(track.clips, timeUs, (entry, _index) => ({\n start: entry.startUs,\n end: entry.startUs + entry.durationUs,\n }));\n\n if (clip) {\n clips.push(clip);\n }\n }\n\n return clips;\n }\n\n getActiveClips(startUs: TimeUs, endUs: TimeUs): Clip[] {\n const clips: Clip[] = [];\n\n for (const track of this.tracks) {\n // Use binary search for range overlap\n const overlappingClips = binarySearchOverlapping(\n track.clips,\n startUs,\n endUs,\n (clip, _index) => ({\n start: clip.startUs,\n end: clip.startUs + clip.durationUs,\n })\n );\n\n clips.push(...overlappingClips);\n }\n\n return clips;\n }\n\n getClipIdsByResourceId(resourceId: string): string[] {\n const resource = this.resources.get(resourceId);\n return resource?.clipIds || [];\n }\n\n getClipIdAtTime(trackId: string, timeUs: TimeUs): string | undefined {\n const track = this.findTrack(trackId);\n if (!track) {\n return undefined;\n }\n\n const clip = binarySearchRange(track.clips, timeUs, (entry, _index) => ({\n start: entry.startUs,\n end: entry.startUs + entry.durationUs,\n }));\n\n return clip?.id;\n }\n\n /**\n * Get neighboring clips (Prev/Current/Next) at a specific time for video tracks\n * Returns prev, current, and next clip IDs\n */\n getNeighboringClips(timeUs: TimeUs): { prev?: string; current?: string; next?: string } {\n const videoTracks = this.getTracksByKind('video');\n const result: { prev?: string; current?: string; next?: string } = {};\n\n for (const track of videoTracks) {\n const clips = track.clips;\n\n for (let i = 0; i < clips.length; i++) {\n const clip = clips[i];\n if (!clip) continue;\n\n const clipEndUs = clip.startUs + clip.durationUs;\n\n if (clip.startUs <= timeUs && timeUs < clipEndUs) {\n if (!result.current) {\n result.current = clip.id;\n }\n\n if (i > 0 && !result.prev) {\n const prevClip = clips[i - 1];\n if (prevClip) {\n result.prev = prevClip.id;\n }\n }\n\n if (i < clips.length - 1 && !result.next) {\n const nextClip = clips[i + 1];\n if (nextClip) {\n result.next = nextClip.id;\n }\n }\n }\n }\n }\n\n return result;\n }\n\n /**\n * Get all clip IDs that should be cached using adaptive strategy\n * - Short clips (≤ maxDuration): cache Current + Next (smooth transitions)\n * - Long clips (> maxDuration): cache Current only (memory control)\n * @param timeUs - Current playback time\n * @param maxDuration - Max duration for 2-clip strategy (default 5s)\n */\n getClipsToCacheAtTime(timeUs: TimeUs, maxDuration = 5_000_000): Set<string> {\n const { current, next } = this.getNeighboringClips(timeUs);\n const clipIds = new Set<string>();\n\n if (!current) return clipIds;\n clipIds.add(current);\n\n // Only cache next clip if current clip is short enough\n const currentClip = this.findClip(current);\n if (currentClip && currentClip.durationUs <= maxDuration && next) {\n clipIds.add(next);\n }\n\n return clipIds;\n }\n\n // Resource operations\n getResource(id: string): Resource | null {\n return this.resources.get(id) || null;\n }\n\n updateResourceState(id: string, state: 'pending' | 'loading' | 'ready' | 'error'): void {\n const resource = this.resources.get(id);\n if (resource) {\n resource.state = state;\n }\n }\n\n getUnusedResources(): Resource[] {\n const unused: Resource[] = [];\n\n for (const [id, resource] of this.resources) {\n if (!this.resourceRefCount.has(id) || this.resourceRefCount.get(id) === 0) {\n unused.push(resource);\n }\n }\n\n return unused;\n }\n\n // Time operations\n getDuration(): TimeUs {\n return this.durationUs;\n }\n\n getTrackDuration(trackId: string): TimeUs {\n const track = this.findTrack(trackId);\n if (!track || track.clips.length === 0) return 0;\n\n // Since clips are sorted, last clip determines duration\n const lastClip = track.clips[track.clips.length - 1];\n return (lastClip?.startUs ?? 0) + (lastClip?.durationUs ?? 0);\n }\n\n buildIndexes(options?: {\n incremental?: boolean;\n trackId?: string;\n clipId?: string;\n clip?: Clip;\n operation?: 'add' | 'update' | 'remove';\n }): void {\n const track = options?.trackId ? this.findTrack(options.trackId) : undefined;\n const isAttachmentTrack = track && track.kind !== 'video' && track.kind !== 'audio';\n // Incremental update for video/audio track clip operations\n if (options?.incremental && !isAttachmentTrack && options.clipId && options.operation) {\n const clip = options.clip ?? this.clipMap.get(options.clipId);\n\n if (options.operation === 'add' && clip) {\n this.addClipToIndexes(clip);\n } else if (options.operation === 'remove' && clip) {\n this.removeClipFromIndexes(clip);\n } else if (options.operation === 'update' && clip) {\n // Handle resource change during update\n if (clip.oldResourceId) {\n this.updateClipResourceIndex(\n options.clipId,\n clip.oldResourceId,\n hasResourceId(clip) ? clip.resourceId : undefined\n );\n }\n }\n\n // Recalculate duration only if affected main track\n if (track?.id === this.mainTrackId) {\n this.recalculateDuration();\n }\n return;\n }\n\n // Full rebuild: needed for attachment tracks or initial load\n this.fullRebuildIndexes();\n }\n\n private fullRebuildIndexes(): void {\n // Clear existing indexes\n this.trackMap.clear();\n this.clipMap.clear();\n this.resourceRefCount.clear();\n\n // Step 1: Sink attachment tracks to main track (preserves original tracks)\n this.sinkAttachmentTracks();\n\n let maxEndUs = 0;\n\n // Step 2: Build all indexes in one pass (track, clip, resource)\n for (const track of this.tracks) {\n this.trackMap.set(track.id, track);\n\n for (const clip of track.clips) {\n (clip as Clip).trackId = track.id;\n (clip as Clip).trackKind = track.kind;\n this.clipMap.set(clip.id, clip);\n\n // Main track resource index (only for clips with resourceId)\n if (hasResourceId(clip)) {\n const resource = this.resources.get(clip.resourceId);\n if (resource) {\n resource.clipIds = [...(resource.clipIds || []), clip.id];\n }\n const count = this.resourceRefCount.get(clip.resourceId) || 0;\n this.resourceRefCount.set(clip.resourceId, count + 1);\n }\n\n // Attachment resource indexes (attachments are already sunk)\n const attachments = clip.attachments ?? [];\n for (const attachment of attachments) {\n const attachmentResourceId = attachment.data?.resourceId;\n if (attachmentResourceId && typeof attachmentResourceId === 'string') {\n const attachmentResource = this.resources.get(attachmentResourceId);\n if (attachmentResource) {\n const clipIds = attachmentResource.clipIds || [];\n if (!clipIds.includes(clip.id)) {\n attachmentResource.clipIds = [...clipIds, clip.id];\n }\n }\n const attachmentCount = this.resourceRefCount.get(attachmentResourceId) || 0;\n this.resourceRefCount.set(attachmentResourceId, attachmentCount + 1);\n }\n }\n\n // Calculate max end time\n const clipEndUs = clip.startUs + clip.durationUs;\n if (clipEndUs > maxEndUs) {\n maxEndUs = clipEndUs;\n }\n }\n }\n\n this.durationUs = maxEndUs;\n }\n\n private addClipToIndexes(clip: Clip): void {\n this.clipMap.set(clip.id, clip);\n\n if (hasResourceId(clip)) {\n const resource = this.resources.get(clip.resourceId);\n if (resource) {\n if (!resource.clipIds) {\n resource.clipIds = [];\n }\n if (!resource.clipIds.includes(clip.id)) {\n resource.clipIds.push(clip.id);\n }\n }\n const count = this.resourceRefCount.get(clip.resourceId) || 0;\n this.resourceRefCount.set(clip.resourceId, count + 1);\n }\n }\n\n private removeClipFromIndexes(clip: Clip): void {\n this.clipMap.delete(clip.id);\n\n const resourceId = clip.oldResourceId || (hasResourceId(clip) ? clip.resourceId : undefined);\n if (resourceId) {\n const resource = this.resources.get(resourceId);\n if (resource?.clipIds) {\n resource.clipIds = resource.clipIds.filter((id) => id !== clip.id);\n }\n const count = this.resourceRefCount.get(resourceId) || 0;\n this.resourceRefCount.set(resourceId, Math.max(0, count - 1));\n }\n }\n\n /**\n * Incrementally update resource index when clip's resourceId changes\n */\n updateClipResourceIndex(\n clipId: string,\n oldResourceId: string | undefined,\n newResourceId: string | undefined\n ): void {\n // Remove from old resource\n if (oldResourceId) {\n const oldResource = this.resources.get(oldResourceId);\n if (oldResource?.clipIds) {\n oldResource.clipIds = oldResource.clipIds.filter((id) => id !== clipId);\n }\n const oldCount = this.resourceRefCount.get(oldResourceId) || 0;\n this.resourceRefCount.set(oldResourceId, Math.max(0, oldCount - 1));\n }\n\n // Add to new resource\n if (newResourceId) {\n const newResource = this.resources.get(newResourceId);\n if (newResource) {\n if (!newResource.clipIds) {\n newResource.clipIds = [];\n }\n if (!newResource.clipIds.includes(clipId)) {\n newResource.clipIds.push(clipId);\n }\n }\n const newCount = this.resourceRefCount.get(newResourceId) || 0;\n this.resourceRefCount.set(newResourceId, newCount + 1);\n }\n }\n\n /**\n * Recalculate total duration based on main track\n */\n recalculateDuration(): void {\n const mainTrack = this.findTrack(this.mainTrackId);\n if (!mainTrack || mainTrack.clips.length === 0) {\n this.durationUs = 0;\n return;\n }\n\n // Since clips are sorted, last clip determines duration\n const lastClip = mainTrack.clips[mainTrack.clips.length - 1];\n this.durationUs = (lastClip?.startUs ?? 0) + (lastClip?.durationUs ?? 0);\n }\n\n private sinkAttachmentTracks(): void {\n let mainTrack: Track | undefined;\n const attachmentTracks = [];\n\n // Sort all tracks\n for (const track of this.tracks) {\n track.clips.sort((a, b) => a.startUs - b.startUs);\n\n if (track.id === this.mainTrackId) {\n mainTrack = track;\n continue;\n }\n // Collect attachment tracks for sinking (caption, overlay, fx)\n // Video and audio tracks are not sunk\n if (track.kind === 'caption' || track.kind === 'overlay' || track.kind === 'fx') {\n attachmentTracks.push(track);\n }\n }\n\n if (!mainTrack) {\n throw new Error('Main track not found');\n }\n\n // Clear existing attachments before sinking (in case of rebuild)\n for (const clip of mainTrack.clips) {\n clip.attachments = [];\n }\n\n for (const attachmentTrack of attachmentTracks) {\n for (const attachmentClip of attachmentTrack.clips) {\n // Use track.kind directly as attachment kind\n const attachmentKind = attachmentTrack.kind;\n\n for (const mainClip of mainTrack.clips) {\n const overlap = this.getTimeOverlap(attachmentClip, mainClip);\n if (!overlap) continue;\n\n if (!mainClip.attachments) {\n mainClip.attachments = [];\n }\n\n // Extract animation effect\n const animationEffect = attachmentClip.effects?.find(\n (e) => e.effectType === 'animation'\n ) as AnimationEffect | undefined;\n\n // Extract target dimensions from metadata\n const targetWidth = attachmentClip.metadata?.targetWidth as number | undefined;\n const targetHeight = attachmentClip.metadata?.targetHeight as number | undefined;\n\n const attachmentData: Record<string, unknown> = {\n animation: animationEffect?.params,\n overlayClipStartUs: attachmentClip.startUs,\n mainClipStartUs: mainClip.startUs,\n ...(targetWidth !== undefined && { targetWidth }),\n ...(targetHeight !== undefined && { targetHeight }),\n };\n\n // Add resourceId if exists (trackKind not yet set, check field directly)\n if ('resourceId' in attachmentClip && attachmentClip.resourceId) {\n attachmentData.resourceId = attachmentClip.resourceId;\n }\n\n // Add text if exists (trackKind not yet set, check field directly)\n if ('text' in attachmentClip && attachmentClip.text) {\n attachmentData.text = attachmentClip.text;\n }\n\n mainClip.attachments.push({\n id: `${attachmentKind}-${attachmentClip.id}-${mainClip.id}`,\n kind: attachmentKind,\n startUs: overlap.clipRelativeStart,\n durationUs: overlap.duration,\n data: attachmentData,\n });\n }\n }\n }\n }\n\n private getTimeOverlap(\n attachmentClip: Clip,\n mainClip: Clip\n ): { clipRelativeStart: number; duration: number } | null {\n const attachmentStart = attachmentClip.startUs;\n const attachmentEnd = attachmentClip.startUs + attachmentClip.durationUs;\n const mainStart = mainClip.startUs;\n const mainEnd = mainClip.startUs + mainClip.durationUs;\n\n if (attachmentEnd <= mainStart || attachmentStart >= mainEnd) {\n return null;\n }\n\n const overlapStart = Math.max(attachmentStart, mainStart);\n const overlapEnd = Math.min(attachmentEnd, mainEnd);\n const duration = overlapEnd - overlapStart;\n const clipRelativeStart = overlapStart - mainStart;\n\n return { clipRelativeStart, duration };\n }\n}\n"],"names":[],"mappings":";;;AAYO,MAAM,iBAAiB;AAAA,EACZ,UAAU;AAAA,EACV;AAAA,EACT;AAAA;AAAA,EACS;AAAA,EACT;AAAA,EACS;AAAA,EAEC;AAAA,EACA;AAAA,EACA;AAAA,EAED;AAAA,EAMA;AAAA,EAEhB,YAAY,MAA4B;AACtC,UAAM,SAAS,6BAA6B,IAAI;AAChD,QAAI,OAAO,SAAS,GAAG;AACrB,YAAM,IAAI;AAAA,QACR;AAAA,EAAuB,OAAO,IAAI,CAAC,MAAM,GAAG,EAAE,IAAI,KAAK,EAAE,OAAO,EAAE,EAAE,KAAK,IAAI,CAAC;AAAA,MAAA;AAAA,IAElF;AAEA,SAAK,MAAM,KAAK;AAChB,SAAK,cAAc,KAAK,eAAe;AACvC,SAAK,SAAS,KAAK;AACnB,SAAK,YAAY,IAAI,IAAI,OAAO,QAAQ,KAAK,SAAS,CAAC;AACvD,SAAK,eAAe,KAAK;AACzB,SAAK,MAAM,KAAK;AAGhB,SAAK,+BAAe,IAAA;AACpB,SAAK,8BAAc,IAAA;AACnB,SAAK,uCAAuB,IAAA;AAE5B,SAAK,aAAA;AAEL,YAAQ;AAAA,MACN;AAAA,MACA,KAAK,OAAO,KAAK,CAAC,MAAM,EAAE,OAAO,KAAK,WAAW,GAAG,MAAM,CAAC;AAAA,IAAA;AAAA,EAE/D;AAAA;AAAA,EAGA,UAAU,IAA0B;AAClC,WAAO,KAAK,SAAS,IAAI,EAAE,KAAK;AAAA,EAClC;AAAA,EAEA,gBAAgB,MAAiE;AAC/E,WAAO,KAAK,OAAO,OAAO,CAAC,UAAU,MAAM,SAAS,IAAI;AAAA,EAC1D;AAAA;AAAA,EAGA,SAAS,IAAyB;AAChC,WAAO,KAAK,QAAQ,IAAI,EAAE,KAAK;AAAA,EACjC;AAAA,EAEA,eAAe,QAAgB,SAA0B;AACvD,UAAM,SAAS,UAAU,CAAC,KAAK,UAAU,OAAO,CAAC,IAAI,KAAK;AAC1D,UAAM,QAAgB,CAAA;AAEtB,eAAW,SAAS,QAAQ;AAC1B,UAAI,CAAC,MAAO;AAEZ,YAAM,OAAO,kBAAkB,MAAM,OAAO,QAAQ,CAAC,OAAO,YAAY;AAAA,QACtE,OAAO,MAAM;AAAA,QACb,KAAK,MAAM,UAAU,MAAM;AAAA,MAAA,EAC3B;AAEF,UAAI,MAAM;AACR,cAAM,KAAK,IAAI;AAAA,MACjB;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,eAAe,SAAiB,OAAuB;AACrD,UAAM,QAAgB,CAAA;AAEtB,eAAW,SAAS,KAAK,QAAQ;AAE/B,YAAM,mBAAmB;AAAA,QACvB,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA,CAAC,MAAM,YAAY;AAAA,UACjB,OAAO,KAAK;AAAA,UACZ,KAAK,KAAK,UAAU,KAAK;AAAA,QAAA;AAAA,MAC3B;AAGF,YAAM,KAAK,GAAG,gBAAgB;AAAA,IAChC;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,uBAAuB,YAA8B;AACnD,UAAM,WAAW,KAAK,UAAU,IAAI,UAAU;AAC9C,WAAO,UAAU,WAAW,CAAA;AAAA,EAC9B;AAAA,EAEA,gBAAgB,SAAiB,QAAoC;AACnE,UAAM,QAAQ,KAAK,UAAU,OAAO;AACpC,QAAI,CAAC,OAAO;AACV,aAAO;AAAA,IACT;AAEA,UAAM,OAAO,kBAAkB,MAAM,OAAO,QAAQ,CAAC,OAAO,YAAY;AAAA,MACtE,OAAO,MAAM;AAAA,MACb,KAAK,MAAM,UAAU,MAAM;AAAA,IAAA,EAC3B;AAEF,WAAO,MAAM;AAAA,EACf;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,oBAAoB,QAAoE;AACtF,UAAM,cAAc,KAAK,gBAAgB,OAAO;AAChD,UAAM,SAA6D,CAAA;AAEnE,eAAW,SAAS,aAAa;AAC/B,YAAM,QAAQ,MAAM;AAEpB,eAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,cAAM,OAAO,MAAM,CAAC;AACpB,YAAI,CAAC,KAAM;AAEX,cAAM,YAAY,KAAK,UAAU,KAAK;AAEtC,YAAI,KAAK,WAAW,UAAU,SAAS,WAAW;AAChD,cAAI,CAAC,OAAO,SAAS;AACnB,mBAAO,UAAU,KAAK;AAAA,UACxB;AAEA,cAAI,IAAI,KAAK,CAAC,OAAO,MAAM;AACzB,kBAAM,WAAW,MAAM,IAAI,CAAC;AAC5B,gBAAI,UAAU;AACZ,qBAAO,OAAO,SAAS;AAAA,YACzB;AAAA,UACF;AAEA,cAAI,IAAI,MAAM,SAAS,KAAK,CAAC,OAAO,MAAM;AACxC,kBAAM,WAAW,MAAM,IAAI,CAAC;AAC5B,gBAAI,UAAU;AACZ,qBAAO,OAAO,SAAS;AAAA,YACzB;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,sBAAsB,QAAgB,cAAc,KAAwB;AAC1E,UAAM,EAAE,SAAS,KAAA,IAAS,KAAK,oBAAoB,MAAM;AACzD,UAAM,8BAAc,IAAA;AAEpB,QAAI,CAAC,QAAS,QAAO;AACrB,YAAQ,IAAI,OAAO;AAGnB,UAAM,cAAc,KAAK,SAAS,OAAO;AACzC,QAAI,eAAe,YAAY,cAAc,eAAe,MAAM;AAChE,cAAQ,IAAI,IAAI;AAAA,IAClB;AAEA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,YAAY,IAA6B;AACvC,WAAO,KAAK,UAAU,IAAI,EAAE,KAAK;AAAA,EACnC;AAAA,EAEA,oBAAoB,IAAY,OAAwD;AACtF,UAAM,WAAW,KAAK,UAAU,IAAI,EAAE;AACtC,QAAI,UAAU;AACZ,eAAS,QAAQ;AAAA,IACnB;AAAA,EACF;AAAA,EAEA,qBAAiC;AAC/B,UAAM,SAAqB,CAAA;AAE3B,eAAW,CAAC,IAAI,QAAQ,KAAK,KAAK,WAAW;AAC3C,UAAI,CAAC,KAAK,iBAAiB,IAAI,EAAE,KAAK,KAAK,iBAAiB,IAAI,EAAE,MAAM,GAAG;AACzE,eAAO,KAAK,QAAQ;AAAA,MACtB;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,cAAsB;AACpB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,iBAAiB,SAAyB;AACxC,UAAM,QAAQ,KAAK,UAAU,OAAO;AACpC,QAAI,CAAC,SAAS,MAAM,MAAM,WAAW,EAAG,QAAO;AAG/C,UAAM,WAAW,MAAM,MAAM,MAAM,MAAM,SAAS,CAAC;AACnD,YAAQ,UAAU,WAAW,MAAM,UAAU,cAAc;AAAA,EAC7D;AAAA,EAEA,aAAa,SAMJ;AACP,UAAM,QAAQ,SAAS,UAAU,KAAK,UAAU,QAAQ,OAAO,IAAI;AACnE,UAAM,oBAAoB,SAAS,MAAM,SAAS,WAAW,MAAM,SAAS;AAE5E,QAAI,SAAS,eAAe,CAAC,qBAAqB,QAAQ,UAAU,QAAQ,WAAW;AACrF,YAAM,OAAO,QAAQ,QAAQ,KAAK,QAAQ,IAAI,QAAQ,MAAM;AAE5D,UAAI,QAAQ,cAAc,SAAS,MAAM;AACvC,aAAK,iBAAiB,IAAI;AAAA,MAC5B,WAAW,QAAQ,cAAc,YAAY,MAAM;AACjD,aAAK,sBAAsB,IAAI;AAAA,MACjC,WAAW,QAAQ,cAAc,YAAY,MAAM;AAEjD,YAAI,KAAK,eAAe;AACtB,eAAK;AAAA,YACH,QAAQ;AAAA,YACR,KAAK;AAAA,YACL,cAAc,IAAI,IAAI,KAAK,aAAa;AAAA,UAAA;AAAA,QAE5C;AAAA,MACF;AAGA,UAAI,OAAO,OAAO,KAAK,aAAa;AAClC,aAAK,oBAAA;AAAA,MACP;AACA;AAAA,IACF;AAGA,SAAK,mBAAA;AAAA,EACP;AAAA,EAEQ,qBAA2B;AAEjC,SAAK,SAAS,MAAA;AACd,SAAK,QAAQ,MAAA;AACb,SAAK,iBAAiB,MAAA;AAGtB,SAAK,qBAAA;AAEL,QAAI,WAAW;AAGf,eAAW,SAAS,KAAK,QAAQ;AAC/B,WAAK,SAAS,IAAI,MAAM,IAAI,KAAK;AAEjC,iBAAW,QAAQ,MAAM,OAAO;AAC7B,aAAc,UAAU,MAAM;AAC9B,aAAc,YAAY,MAAM;AACjC,aAAK,QAAQ,IAAI,KAAK,IAAI,IAAI;AAG9B,YAAI,cAAc,IAAI,GAAG;AACvB,gBAAM,WAAW,KAAK,UAAU,IAAI,KAAK,UAAU;AACnD,cAAI,UAAU;AACZ,qBAAS,UAAU,CAAC,GAAI,SAAS,WAAW,CAAA,GAAK,KAAK,EAAE;AAAA,UAC1D;AACA,gBAAM,QAAQ,KAAK,iBAAiB,IAAI,KAAK,UAAU,KAAK;AAC5D,eAAK,iBAAiB,IAAI,KAAK,YAAY,QAAQ,CAAC;AAAA,QACtD;AAGA,cAAM,cAAc,KAAK,eAAe,CAAA;AACxC,mBAAW,cAAc,aAAa;AACpC,gBAAM,uBAAuB,WAAW,MAAM;AAC9C,cAAI,wBAAwB,OAAO,yBAAyB,UAAU;AACpE,kBAAM,qBAAqB,KAAK,UAAU,IAAI,oBAAoB;AAClE,gBAAI,oBAAoB;AACtB,oBAAM,UAAU,mBAAmB,WAAW,CAAA;AAC9C,kBAAI,CAAC,QAAQ,SAAS,KAAK,EAAE,GAAG;AAC9B,mCAAmB,UAAU,CAAC,GAAG,SAAS,KAAK,EAAE;AAAA,cACnD;AAAA,YACF;AACA,kBAAM,kBAAkB,KAAK,iBAAiB,IAAI,oBAAoB,KAAK;AAC3E,iBAAK,iBAAiB,IAAI,sBAAsB,kBAAkB,CAAC;AAAA,UACrE;AAAA,QACF;AAGA,cAAM,YAAY,KAAK,UAAU,KAAK;AACtC,YAAI,YAAY,UAAU;AACxB,qBAAW;AAAA,QACb;AAAA,MACF;AAAA,IACF;AAEA,SAAK,aAAa;AAAA,EACpB;AAAA,EAEQ,iBAAiB,MAAkB;AACzC,SAAK,QAAQ,IAAI,KAAK,IAAI,IAAI;AAE9B,QAAI,cAAc,IAAI,GAAG;AACvB,YAAM,WAAW,KAAK,UAAU,IAAI,KAAK,UAAU;AACnD,UAAI,UAAU;AACZ,YAAI,CAAC,SAAS,SAAS;AACrB,mBAAS,UAAU,CAAA;AAAA,QACrB;AACA,YAAI,CAAC,SAAS,QAAQ,SAAS,KAAK,EAAE,GAAG;AACvC,mBAAS,QAAQ,KAAK,KAAK,EAAE;AAAA,QAC/B;AAAA,MACF;AACA,YAAM,QAAQ,KAAK,iBAAiB,IAAI,KAAK,UAAU,KAAK;AAC5D,WAAK,iBAAiB,IAAI,KAAK,YAAY,QAAQ,CAAC;AAAA,IACtD;AAAA,EACF;AAAA,EAEQ,sBAAsB,MAAkB;AAC9C,SAAK,QAAQ,OAAO,KAAK,EAAE;AAE3B,UAAM,aAAa,KAAK,kBAAkB,cAAc,IAAI,IAAI,KAAK,aAAa;AAClF,QAAI,YAAY;AACd,YAAM,WAAW,KAAK,UAAU,IAAI,UAAU;AAC9C,UAAI,UAAU,SAAS;AACrB,iBAAS,UAAU,SAAS,QAAQ,OAAO,CAAC,OAAO,OAAO,KAAK,EAAE;AAAA,MACnE;AACA,YAAM,QAAQ,KAAK,iBAAiB,IAAI,UAAU,KAAK;AACvD,WAAK,iBAAiB,IAAI,YAAY,KAAK,IAAI,GAAG,QAAQ,CAAC,CAAC;AAAA,IAC9D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,wBACE,QACA,eACA,eACM;AAEN,QAAI,eAAe;AACjB,YAAM,cAAc,KAAK,UAAU,IAAI,aAAa;AACpD,UAAI,aAAa,SAAS;AACxB,oBAAY,UAAU,YAAY,QAAQ,OAAO,CAAC,OAAO,OAAO,MAAM;AAAA,MACxE;AACA,YAAM,WAAW,KAAK,iBAAiB,IAAI,aAAa,KAAK;AAC7D,WAAK,iBAAiB,IAAI,eAAe,KAAK,IAAI,GAAG,WAAW,CAAC,CAAC;AAAA,IACpE;AAGA,QAAI,eAAe;AACjB,YAAM,cAAc,KAAK,UAAU,IAAI,aAAa;AACpD,UAAI,aAAa;AACf,YAAI,CAAC,YAAY,SAAS;AACxB,sBAAY,UAAU,CAAA;AAAA,QACxB;AACA,YAAI,CAAC,YAAY,QAAQ,SAAS,MAAM,GAAG;AACzC,sBAAY,QAAQ,KAAK,MAAM;AAAA,QACjC;AAAA,MACF;AACA,YAAM,WAAW,KAAK,iBAAiB,IAAI,aAAa,KAAK;AAC7D,WAAK,iBAAiB,IAAI,eAAe,WAAW,CAAC;AAAA,IACvD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,sBAA4B;AAC1B,UAAM,YAAY,KAAK,UAAU,KAAK,WAAW;AACjD,QAAI,CAAC,aAAa,UAAU,MAAM,WAAW,GAAG;AAC9C,WAAK,aAAa;AAClB;AAAA,IACF;AAGA,UAAM,WAAW,UAAU,MAAM,UAAU,MAAM,SAAS,CAAC;AAC3D,SAAK,cAAc,UAAU,WAAW,MAAM,UAAU,cAAc;AAAA,EACxE;AAAA,EAEQ,uBAA6B;AACnC,QAAI;AACJ,UAAM,mBAAmB,CAAA;AAGzB,eAAW,SAAS,KAAK,QAAQ;AAC/B,YAAM,MAAM,KAAK,CAAC,GAAG,MAAM,EAAE,UAAU,EAAE,OAAO;AAEhD,UAAI,MAAM,OAAO,KAAK,aAAa;AACjC,oBAAY;AACZ;AAAA,MACF;AAGA,UAAI,MAAM,SAAS,aAAa,MAAM,SAAS,aAAa,MAAM,SAAS,MAAM;AAC/E,yBAAiB,KAAK,KAAK;AAAA,MAC7B;AAAA,IACF;AAEA,QAAI,CAAC,WAAW;AACd,YAAM,IAAI,MAAM,sBAAsB;AAAA,IACxC;AAGA,eAAW,QAAQ,UAAU,OAAO;AAClC,WAAK,cAAc,CAAA;AAAA,IACrB;AAEA,eAAW,mBAAmB,kBAAkB;AAC9C,iBAAW,kBAAkB,gBAAgB,OAAO;AAElD,cAAM,iBAAiB,gBAAgB;AAEvC,mBAAW,YAAY,UAAU,OAAO;AACtC,gBAAM,UAAU,KAAK,eAAe,gBAAgB,QAAQ;AAC5D,cAAI,CAAC,QAAS;AAEd,cAAI,CAAC,SAAS,aAAa;AACzB,qBAAS,cAAc,CAAA;AAAA,UACzB;AAGA,gBAAM,kBAAkB,eAAe,SAAS;AAAA,YAC9C,CAAC,MAAM,EAAE,eAAe;AAAA,UAAA;AAI1B,gBAAM,cAAc,eAAe,UAAU;AAC7C,gBAAM,eAAe,eAAe,UAAU;AAE9C,gBAAM,iBAA0C;AAAA,YAC9C,WAAW,iBAAiB;AAAA,YAC5B,oBAAoB,eAAe;AAAA,YACnC,iBAAiB,SAAS;AAAA,YAC1B,GAAI,gBAAgB,UAAa,EAAE,YAAA;AAAA,YACnC,GAAI,iBAAiB,UAAa,EAAE,aAAA;AAAA,UAAa;AAInD,cAAI,gBAAgB,kBAAkB,eAAe,YAAY;AAC/D,2BAAe,aAAa,eAAe;AAAA,UAC7C;AAGA,cAAI,UAAU,kBAAkB,eAAe,MAAM;AACnD,2BAAe,OAAO,eAAe;AAAA,UACvC;AAEA,mBAAS,YAAY,KAAK;AAAA,YACxB,IAAI,GAAG,cAAc,IAAI,eAAe,EAAE,IAAI,SAAS,EAAE;AAAA,YACzD,MAAM;AAAA,YACN,SAAS,QAAQ;AAAA,YACjB,YAAY,QAAQ;AAAA,YACpB,MAAM;AAAA,UAAA,CACP;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,eACN,gBACA,UACwD;AACxD,UAAM,kBAAkB,eAAe;AACvC,UAAM,gBAAgB,eAAe,UAAU,eAAe;AAC9D,UAAM,YAAY,SAAS;AAC3B,UAAM,UAAU,SAAS,UAAU,SAAS;AAE5C,QAAI,iBAAiB,aAAa,mBAAmB,SAAS;AAC5D,aAAO;AAAA,IACT;AAEA,UAAM,eAAe,KAAK,IAAI,iBAAiB,SAAS;AACxD,UAAM,aAAa,KAAK,IAAI,eAAe,OAAO;AAClD,UAAM,WAAW,aAAa;AAC9B,UAAM,oBAAoB,eAAe;AAEzC,WAAO,EAAE,mBAAmB,SAAA;AAAA,EAC9B;AACF;"}
|
|
1
|
+
{"version":3,"file":"CompositionModel.js","sources":["../../src/model/CompositionModel.ts"],"sourcesContent":["import {\n CompositionModelData,\n Track,\n Clip,\n Resource,\n TimeUs,\n AnimationEffect,\n hasResourceId,\n} from './types';\nimport { binarySearchRange, binarySearchOverlapping } from '../utils/binary-search';\nimport { validateCompositionStructure } from './validation';\n\nexport class CompositionModel {\n public readonly version = '1.0' as const;\n public readonly fps: 24 | 25 | 30 | 60;\n public durationUs!: TimeUs; // Assigned in buildIndexes()\n public readonly mainTrackId: string;\n public tracks: Track[];\n public readonly resources: Map<string, Resource>;\n\n private readonly trackMap: Map<string, Track>;\n private readonly clipMap: Map<string, Clip>;\n private readonly resourceRefCount: Map<string, number>;\n\n public readonly renderConfig?: {\n width: number;\n height: number;\n backgroundColor?: string;\n };\n\n public readonly ext?: Record<string, unknown>;\n\n constructor(data: CompositionModelData) {\n const errors = validateCompositionStructure(data);\n if (errors.length > 0) {\n throw new Error(\n `Validation failed:\\n${errors.map((e) => `${e.path}: ${e.message}`).join('\\n')}`\n );\n }\n\n this.fps = data.fps;\n this.mainTrackId = data.mainTrackId ?? 'main';\n this.tracks = data.tracks;\n this.resources = new Map(Object.entries(data.resources));\n this.renderConfig = data.renderConfig;\n this.ext = data.ext;\n\n // Build indexes\n this.trackMap = new Map();\n this.clipMap = new Map();\n this.resourceRefCount = new Map();\n\n this.buildIndexes();\n\n console.log(\n 'CompositionModel constructed',\n this.tracks.find((t) => t.id === this.mainTrackId)?.clips[0]\n );\n }\n\n // Track operations\n findTrack(id: string): Track | null {\n return this.trackMap.get(id) || null;\n }\n\n getTracksByKind(kind: 'video' | 'audio' | 'caption' | 'overlay' | 'fx'): Track[] {\n return this.tracks.filter((track) => track.kind === kind);\n }\n\n // Clip operations with binary search optimization\n findClip(id: string): Clip | null {\n return this.clipMap.get(id) || null;\n }\n\n getClipsAtTime(timeUs: TimeUs, trackId?: string): Clip[] {\n const tracks = trackId ? [this.findTrack(trackId)] : this.tracks;\n const clips: Clip[] = [];\n\n for (const track of tracks) {\n if (!track) continue;\n // Use binary search for single point lookup\n const clip = binarySearchRange(track.clips, timeUs, (entry, _index) => ({\n start: entry.startUs,\n end: entry.startUs + entry.durationUs,\n }));\n\n if (clip) {\n clips.push(clip);\n }\n }\n\n return clips;\n }\n\n getActiveClips(startUs: TimeUs, endUs: TimeUs): Clip[] {\n const clips: Clip[] = [];\n\n for (const track of this.tracks) {\n // Use binary search for range overlap\n const overlappingClips = binarySearchOverlapping(\n track.clips,\n startUs,\n endUs,\n (clip, _index) => ({\n start: clip.startUs,\n end: clip.startUs + clip.durationUs,\n })\n );\n\n clips.push(...overlappingClips);\n }\n\n return clips;\n }\n\n /**\n * Get all clips in a specific track that overlap with the given time range\n * Uses binary search for O(log n + k) performance\n * @param startUs - Range start time (inclusive)\n * @param endUs - Range end time (exclusive)\n * @param trackId - Optional track ID to filter (defaults to main track)\n */\n getClipsInRange(startUs: TimeUs, endUs: TimeUs, trackId?: string): Clip[] {\n const targetTrackId = trackId ?? this.mainTrackId;\n const track = this.findTrack(targetTrackId);\n\n if (!track) {\n return [];\n }\n\n return binarySearchOverlapping(track.clips, startUs, endUs, (clip) => ({\n start: clip.startUs,\n end: clip.startUs + clip.durationUs,\n }));\n }\n\n getClipIdsByResourceId(resourceId: string): string[] {\n const resource = this.resources.get(resourceId);\n return resource?.clipIds || [];\n }\n\n getClipIdAtTime(trackId: string, timeUs: TimeUs): string | undefined {\n const track = this.findTrack(trackId);\n if (!track) {\n return undefined;\n }\n\n const clip = binarySearchRange(track.clips, timeUs, (entry, _index) => ({\n start: entry.startUs,\n end: entry.startUs + entry.durationUs,\n }));\n\n return clip?.id;\n }\n\n /**\n * Get neighboring clips (Prev/Current/Next) at a specific time for video tracks\n * Returns prev, current, and next clip IDs\n */\n getNeighboringClips(timeUs: TimeUs): { prev?: string; current?: string; next?: string } {\n const videoTracks = this.getTracksByKind('video');\n const result: { prev?: string; current?: string; next?: string } = {};\n\n for (const track of videoTracks) {\n const clips = track.clips;\n\n for (let i = 0; i < clips.length; i++) {\n const clip = clips[i];\n if (!clip) continue;\n\n const clipEndUs = clip.startUs + clip.durationUs;\n\n if (clip.startUs <= timeUs && timeUs < clipEndUs) {\n if (!result.current) {\n result.current = clip.id;\n }\n\n if (i > 0 && !result.prev) {\n const prevClip = clips[i - 1];\n if (prevClip) {\n result.prev = prevClip.id;\n }\n }\n\n if (i < clips.length - 1 && !result.next) {\n const nextClip = clips[i + 1];\n if (nextClip) {\n result.next = nextClip.id;\n }\n }\n }\n }\n }\n\n return result;\n }\n\n /**\n * Get all clip IDs that should be cached using adaptive strategy\n * - Short clips (≤ maxDuration): cache Current + Next (smooth transitions)\n * - Long clips (> maxDuration): cache Current only (memory control)\n * @param timeUs - Current playback time\n * @param maxDuration - Max duration for 2-clip strategy (default 5s)\n */\n getClipsToCacheAtTime(timeUs: TimeUs, maxDuration = 5_000_000): Set<string> {\n const { current, next } = this.getNeighboringClips(timeUs);\n const clipIds = new Set<string>();\n\n if (!current) return clipIds;\n clipIds.add(current);\n\n // Only cache next clip if current clip is short enough\n const currentClip = this.findClip(current);\n if (currentClip && currentClip.durationUs <= maxDuration && next) {\n clipIds.add(next);\n }\n\n return clipIds;\n }\n\n // Resource operations\n getResource(id: string): Resource | null {\n return this.resources.get(id) || null;\n }\n\n updateResourceState(id: string, state: 'pending' | 'loading' | 'ready' | 'error'): void {\n const resource = this.resources.get(id);\n if (resource) {\n resource.state = state;\n }\n }\n\n getUnusedResources(): Resource[] {\n const unused: Resource[] = [];\n\n for (const [id, resource] of this.resources) {\n if (!this.resourceRefCount.has(id) || this.resourceRefCount.get(id) === 0) {\n unused.push(resource);\n }\n }\n\n return unused;\n }\n\n // Time operations\n getDuration(): TimeUs {\n return this.durationUs;\n }\n\n getTrackDuration(trackId: string): TimeUs {\n const track = this.findTrack(trackId);\n if (!track || track.clips.length === 0) return 0;\n\n // Since clips are sorted, last clip determines duration\n const lastClip = track.clips[track.clips.length - 1];\n return (lastClip?.startUs ?? 0) + (lastClip?.durationUs ?? 0);\n }\n\n buildIndexes(options?: {\n incremental?: boolean;\n trackId?: string;\n clipId?: string;\n clip?: Clip;\n operation?: 'add' | 'update' | 'remove';\n }): void {\n const track = options?.trackId ? this.findTrack(options.trackId) : undefined;\n const isAttachmentTrack = track && track.kind !== 'video' && track.kind !== 'audio';\n // Incremental update for video/audio track clip operations\n if (options?.incremental && !isAttachmentTrack && options.clipId && options.operation) {\n const clip = options.clip ?? this.clipMap.get(options.clipId);\n\n if (options.operation === 'add' && clip) {\n this.addClipToIndexes(clip);\n } else if (options.operation === 'remove' && clip) {\n this.removeClipFromIndexes(clip);\n } else if (options.operation === 'update' && clip) {\n // Handle resource change during update\n if (clip.oldResourceId) {\n this.updateClipResourceIndex(\n options.clipId,\n clip.oldResourceId,\n hasResourceId(clip) ? clip.resourceId : undefined\n );\n }\n }\n\n // Recalculate duration only if affected main track\n if (track?.id === this.mainTrackId) {\n this.recalculateDuration();\n }\n return;\n }\n\n // Full rebuild: needed for attachment tracks or initial load\n this.fullRebuildIndexes();\n }\n\n private fullRebuildIndexes(): void {\n // Clear existing indexes\n this.trackMap.clear();\n this.clipMap.clear();\n this.resourceRefCount.clear();\n\n // Step 1: Sink attachment tracks to main track (preserves original tracks)\n this.sinkAttachmentTracks();\n\n let maxEndUs = 0;\n\n // Step 2: Build all indexes in one pass (track, clip, resource)\n for (const track of this.tracks) {\n this.trackMap.set(track.id, track);\n\n for (const clip of track.clips) {\n (clip as Clip).trackId = track.id;\n (clip as Clip).trackKind = track.kind;\n this.clipMap.set(clip.id, clip);\n\n // Main track resource index (only for clips with resourceId)\n if (hasResourceId(clip)) {\n const resource = this.resources.get(clip.resourceId);\n if (resource) {\n resource.clipIds = [...(resource.clipIds || []), clip.id];\n }\n const count = this.resourceRefCount.get(clip.resourceId) || 0;\n this.resourceRefCount.set(clip.resourceId, count + 1);\n }\n\n // Attachment resource indexes (attachments are already sunk)\n const attachments = clip.attachments ?? [];\n for (const attachment of attachments) {\n const attachmentResourceId = attachment.data?.resourceId;\n if (attachmentResourceId && typeof attachmentResourceId === 'string') {\n const attachmentResource = this.resources.get(attachmentResourceId);\n if (attachmentResource) {\n const clipIds = attachmentResource.clipIds || [];\n if (!clipIds.includes(clip.id)) {\n attachmentResource.clipIds = [...clipIds, clip.id];\n }\n }\n const attachmentCount = this.resourceRefCount.get(attachmentResourceId) || 0;\n this.resourceRefCount.set(attachmentResourceId, attachmentCount + 1);\n }\n }\n\n // Calculate max end time\n const clipEndUs = clip.startUs + clip.durationUs;\n if (clipEndUs > maxEndUs) {\n maxEndUs = clipEndUs;\n }\n }\n }\n\n this.durationUs = maxEndUs;\n }\n\n private addClipToIndexes(clip: Clip): void {\n this.clipMap.set(clip.id, clip);\n\n if (hasResourceId(clip)) {\n const resource = this.resources.get(clip.resourceId);\n if (resource) {\n if (!resource.clipIds) {\n resource.clipIds = [];\n }\n if (!resource.clipIds.includes(clip.id)) {\n resource.clipIds.push(clip.id);\n }\n }\n const count = this.resourceRefCount.get(clip.resourceId) || 0;\n this.resourceRefCount.set(clip.resourceId, count + 1);\n }\n }\n\n private removeClipFromIndexes(clip: Clip): void {\n this.clipMap.delete(clip.id);\n\n const resourceId = clip.oldResourceId || (hasResourceId(clip) ? clip.resourceId : undefined);\n if (resourceId) {\n const resource = this.resources.get(resourceId);\n if (resource?.clipIds) {\n resource.clipIds = resource.clipIds.filter((id) => id !== clip.id);\n }\n const count = this.resourceRefCount.get(resourceId) || 0;\n this.resourceRefCount.set(resourceId, Math.max(0, count - 1));\n }\n }\n\n /**\n * Incrementally update resource index when clip's resourceId changes\n */\n updateClipResourceIndex(\n clipId: string,\n oldResourceId: string | undefined,\n newResourceId: string | undefined\n ): void {\n // Remove from old resource\n if (oldResourceId) {\n const oldResource = this.resources.get(oldResourceId);\n if (oldResource?.clipIds) {\n oldResource.clipIds = oldResource.clipIds.filter((id) => id !== clipId);\n }\n const oldCount = this.resourceRefCount.get(oldResourceId) || 0;\n this.resourceRefCount.set(oldResourceId, Math.max(0, oldCount - 1));\n }\n\n // Add to new resource\n if (newResourceId) {\n const newResource = this.resources.get(newResourceId);\n if (newResource) {\n if (!newResource.clipIds) {\n newResource.clipIds = [];\n }\n if (!newResource.clipIds.includes(clipId)) {\n newResource.clipIds.push(clipId);\n }\n }\n const newCount = this.resourceRefCount.get(newResourceId) || 0;\n this.resourceRefCount.set(newResourceId, newCount + 1);\n }\n }\n\n /**\n * Recalculate total duration based on main track\n */\n recalculateDuration(): void {\n const mainTrack = this.findTrack(this.mainTrackId);\n if (!mainTrack || mainTrack.clips.length === 0) {\n this.durationUs = 0;\n return;\n }\n\n // Since clips are sorted, last clip determines duration\n const lastClip = mainTrack.clips[mainTrack.clips.length - 1];\n this.durationUs = (lastClip?.startUs ?? 0) + (lastClip?.durationUs ?? 0);\n }\n\n private sinkAttachmentTracks(): void {\n let mainTrack: Track | undefined;\n const attachmentTracks = [];\n\n // Sort all tracks\n for (const track of this.tracks) {\n track.clips.sort((a, b) => a.startUs - b.startUs);\n\n if (track.id === this.mainTrackId) {\n mainTrack = track;\n continue;\n }\n // Collect attachment tracks for sinking (caption, overlay, fx)\n // Video and audio tracks are not sunk\n if (track.kind === 'caption' || track.kind === 'overlay' || track.kind === 'fx') {\n attachmentTracks.push(track);\n }\n }\n\n if (!mainTrack) {\n throw new Error('Main track not found');\n }\n\n // Clear existing attachments before sinking (in case of rebuild)\n for (const clip of mainTrack.clips) {\n clip.attachments = [];\n }\n\n for (const attachmentTrack of attachmentTracks) {\n for (const attachmentClip of attachmentTrack.clips) {\n // Use track.kind directly as attachment kind\n const attachmentKind = attachmentTrack.kind;\n\n for (const mainClip of mainTrack.clips) {\n const overlap = this.getTimeOverlap(attachmentClip, mainClip);\n if (!overlap) continue;\n\n if (!mainClip.attachments) {\n mainClip.attachments = [];\n }\n\n // Extract animation effect\n const animationEffect = attachmentClip.effects?.find(\n (e) => e.effectType === 'animation'\n ) as AnimationEffect | undefined;\n\n // Extract target dimensions from metadata\n const targetWidth = attachmentClip.metadata?.targetWidth as number | undefined;\n const targetHeight = attachmentClip.metadata?.targetHeight as number | undefined;\n\n const attachmentData: Record<string, unknown> = {\n animation: animationEffect?.params,\n overlayClipStartUs: attachmentClip.startUs,\n mainClipStartUs: mainClip.startUs,\n ...(targetWidth !== undefined && { targetWidth }),\n ...(targetHeight !== undefined && { targetHeight }),\n };\n\n // Add resourceId if exists (trackKind not yet set, check field directly)\n if ('resourceId' in attachmentClip && attachmentClip.resourceId) {\n attachmentData.resourceId = attachmentClip.resourceId;\n }\n\n // Add text if exists (trackKind not yet set, check field directly)\n if ('text' in attachmentClip && attachmentClip.text) {\n attachmentData.text = attachmentClip.text;\n }\n\n mainClip.attachments.push({\n id: `${attachmentKind}-${attachmentClip.id}-${mainClip.id}`,\n kind: attachmentKind,\n startUs: overlap.clipRelativeStart,\n durationUs: overlap.duration,\n data: attachmentData,\n });\n }\n }\n }\n }\n\n private getTimeOverlap(\n attachmentClip: Clip,\n mainClip: Clip\n ): { clipRelativeStart: number; duration: number } | null {\n const attachmentStart = attachmentClip.startUs;\n const attachmentEnd = attachmentClip.startUs + attachmentClip.durationUs;\n const mainStart = mainClip.startUs;\n const mainEnd = mainClip.startUs + mainClip.durationUs;\n\n if (attachmentEnd <= mainStart || attachmentStart >= mainEnd) {\n return null;\n }\n\n const overlapStart = Math.max(attachmentStart, mainStart);\n const overlapEnd = Math.min(attachmentEnd, mainEnd);\n const duration = overlapEnd - overlapStart;\n const clipRelativeStart = overlapStart - mainStart;\n\n return { clipRelativeStart, duration };\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -29,6 +29,10 @@ export declare class ExportScheduler {
|
|
|
29
29
|
private deps;
|
|
30
30
|
constructor(deps: ExportSchedulerDeps);
|
|
31
31
|
execute(model: CompositionModel, options: ExtendedExportOptions): Promise<Blob>;
|
|
32
|
+
/**
|
|
33
|
+
* Preload all resources (0-40% progress)
|
|
34
|
+
*/
|
|
35
|
+
private preloadResources;
|
|
32
36
|
/**
|
|
33
37
|
* Process audio in 60-second windows
|
|
34
38
|
* - Videos ≤60s: Single pass (zero boundaries)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExportScheduler.d.ts","sourceRoot":"","sources":["../../src/orchestrator/ExportScheduler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE1D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAgB,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEhE,UAAU,mBAAmB;IAC3B,UAAU,EAAE,UAAU,CAAC;IACvB,OAAO,EAAE,kBAAkB,CAAC;IAC5B,YAAY,EAAE,YAAY,CAAC;IAC3B,cAAc,EAAE,cAAc,CAAC;IAC/B,UAAU,EAAE,UAAU,CAAC;IACvB,YAAY,EAAE,kBAAkB,CAAC;IACjC,qBAAqB,EAAE,MAAM,MAAM,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IACrD,QAAQ,EAAE,QAAQ,CAAC,eAAe,CAAC,CAAC;CACrC;AAED,UAAU,qBAAsB,SAAQ,aAAa;IACnD,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC/B;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,IAAI,CAAsB;gBAEtB,IAAI,EAAE,mBAAmB;IAI/B,OAAO,CAAC,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"ExportScheduler.d.ts","sourceRoot":"","sources":["../../src/orchestrator/ExportScheduler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE1D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAgB,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEhE,UAAU,mBAAmB;IAC3B,UAAU,EAAE,UAAU,CAAC;IACvB,OAAO,EAAE,kBAAkB,CAAC;IAC5B,YAAY,EAAE,YAAY,CAAC;IAC3B,cAAc,EAAE,cAAc,CAAC;IAC/B,UAAU,EAAE,UAAU,CAAC;IACvB,YAAY,EAAE,kBAAkB,CAAC;IACjC,qBAAqB,EAAE,MAAM,MAAM,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IACrD,QAAQ,EAAE,QAAQ,CAAC,eAAe,CAAC,CAAC;CACrC;AAED,UAAU,qBAAsB,SAAQ,aAAa;IACnD,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC/B;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,IAAI,CAAsB;gBAEtB,IAAI,EAAE,mBAAmB;IAI/B,OAAO,CAAC,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IAuFrF;;OAEG;YACW,gBAAgB;IAwC9B;;;;OAIG;YACW,qBAAqB;YAsBrB,6BAA6B;CAwH5C"}
|