@meframe/core 0.0.19 → 0.0.21
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/config/types.d.ts +4 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/model/CompositionModel.d.ts.map +1 -1
- package/dist/model/CompositionModel.js +21 -1
- package/dist/model/CompositionModel.js.map +1 -1
- package/dist/model/types.d.ts +31 -0
- package/dist/model/types.d.ts.map +1 -1
- package/dist/model/types.js.map +1 -1
- package/dist/orchestrator/CompositionPlanner.d.ts +1 -0
- package/dist/orchestrator/CompositionPlanner.d.ts.map +1 -1
- package/dist/orchestrator/CompositionPlanner.js +36 -10
- package/dist/orchestrator/CompositionPlanner.js.map +1 -1
- package/dist/orchestrator/Orchestrator.d.ts.map +1 -1
- package/dist/orchestrator/Orchestrator.js +2 -1
- package/dist/orchestrator/Orchestrator.js.map +1 -1
- package/dist/stages/compose/LayerRenderer.d.ts +4 -7
- package/dist/stages/compose/LayerRenderer.d.ts.map +1 -1
- package/dist/stages/compose/VideoComposer.d.ts +1 -0
- package/dist/stages/compose/VideoComposer.d.ts.map +1 -1
- package/dist/stages/compose/font-system/FontManager.d.ts +11 -0
- package/dist/stages/compose/font-system/FontManager.d.ts.map +1 -0
- package/dist/stages/compose/font-system/FontManager.js +69 -0
- package/dist/stages/compose/font-system/FontManager.js.map +1 -0
- package/dist/stages/compose/font-system/font-templates.d.ts +12 -0
- package/dist/stages/compose/font-system/font-templates.d.ts.map +1 -0
- package/dist/stages/compose/font-system/font-templates.js +384 -0
- package/dist/stages/compose/font-system/font-templates.js.map +1 -0
- package/dist/stages/compose/font-system/index.d.ts +5 -0
- package/dist/stages/compose/font-system/index.d.ts.map +1 -0
- package/dist/stages/compose/font-system/types.d.ts +60 -0
- package/dist/stages/compose/font-system/types.d.ts.map +1 -0
- package/dist/stages/compose/instructions.d.ts +50 -0
- package/dist/stages/compose/instructions.d.ts.map +1 -1
- package/dist/stages/compose/text-renderers/animation-utils.d.ts +16 -0
- package/dist/stages/compose/text-renderers/animation-utils.d.ts.map +1 -0
- package/dist/stages/compose/text-renderers/basic-text-renderer.d.ts +5 -0
- package/dist/stages/compose/text-renderers/basic-text-renderer.d.ts.map +1 -0
- package/dist/stages/compose/text-renderers/character-ktv-renderer.d.ts +4 -0
- package/dist/stages/compose/text-renderers/character-ktv-renderer.d.ts.map +1 -0
- package/dist/stages/compose/text-renderers/index.d.ts +6 -0
- package/dist/stages/compose/text-renderers/index.d.ts.map +1 -0
- package/dist/stages/compose/text-renderers/word-by-word-renderer.d.ts +4 -0
- package/dist/stages/compose/text-renderers/word-by-word-renderer.d.ts.map +1 -0
- package/dist/stages/compose/text-renderers/word-fancy-renderer.d.ts +4 -0
- package/dist/stages/compose/text-renderers/word-fancy-renderer.d.ts.map +1 -0
- package/dist/stages/compose/text-utils/index.d.ts +4 -0
- package/dist/stages/compose/text-utils/index.d.ts.map +1 -0
- package/dist/stages/compose/text-utils/locale-detector.d.ts +5 -0
- package/dist/stages/compose/text-utils/locale-detector.d.ts.map +1 -0
- package/dist/stages/compose/text-utils/text-metrics.d.ts +3 -0
- package/dist/stages/compose/text-utils/text-metrics.d.ts.map +1 -0
- package/dist/stages/compose/text-utils/text-wrapper.d.ts +4 -0
- package/dist/stages/compose/text-utils/text-wrapper.d.ts.map +1 -0
- package/dist/stages/compose/types.d.ts +51 -1
- package/dist/stages/compose/types.d.ts.map +1 -1
- package/dist/workers/stages/compose/video-compose.worker.js +845 -77
- package/dist/workers/stages/compose/video-compose.worker.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Orchestrator.js","sources":["../../src/orchestrator/Orchestrator.ts"],"sourcesContent":["import { EventBus } from '../event/EventBus';\nimport { WorkerPool } from '../worker/WorkerPool';\nimport { applyPatch as applyModelPatch } from '../model/patch';\nimport { ResourceConflictError, ResourceLoader } from '../stages/load/ResourceLoader';\nimport { CacheManager } from '../cache/CacheManager';\nimport { ConfigLoader } from '../config/ConfigLoader';\nimport type { IOrchestrator, OrchestratorConfig, RenderFrameOptions } from './types';\nimport { WorkerStatus, WorkerType } from '../worker/types';\nimport { CompositionModel, CompositionPatch, Resource, TimeUs, RcFrame, Clip } from '../model';\nimport { hasResourceId } from '../model/types';\nimport { MeframeEvent, type EventPayloadMap } from '../event/events';\nimport { CompositionPlanner } from './CompositionPlanner';\nimport { VideoClipSession } from './VideoClipSession';\nimport { ClipSessionManager } from './ClipSessionManager';\nimport { GlobalAudioSession } from './GlobalAudioSession';\nimport { MuxManager } from '../stages/mux/MuxManager';\nimport { ExportOptions } from '@/types';\nimport { VideoChunkDecoder } from '../stages/decode/VideoChunkDecoder';\nimport { quantizeTimestampToFrame } from '../utils/time-utils';\n\nexport class Orchestrator implements IOrchestrator {\n workers: WorkerPool;\n eventBus: EventBus<EventPayloadMap>;\n compositionModel: CompositionModel | null = null;\n resourceLoader: ResourceLoader;\n cacheManager: CacheManager;\n planner: CompositionPlanner;\n audioSession: GlobalAudioSession;\n muxManager: MuxManager;\n\n private activeClips = new Set<string>();\n private isInitialized = false;\n private config = ConfigLoader.getInstance().getConfig();\n private clipSessionManager: ClipSessionManager;\n private currentClipId: string | null = null;\n private ensureCacheDebounceTimer: number | null = null;\n private readonly ensureCacheDebounceDelay = 150;\n readonly events: Pick<EventBus<EventPayloadMap>, 'on' | 'off' | 'once'>;\n\n constructor(config: OrchestratorConfig) {\n // Use provided eventBus or create a new one\n this.eventBus = config.eventBus || new EventBus<EventPayloadMap>();\n this.events = this.eventBus.asReadonly();\n\n // Initialize config first\n this.config = ConfigLoader.getInstance().getConfig();\n\n const workerConfigs = this.buildWorkerConfigs();\n\n // Initialize WorkerPool with worker path from config\n this.workers = new WorkerPool({\n eventBus: this.eventBus,\n workerConfigs,\n workerPath: config.workerPath,\n workerExtension: config.workerExtension,\n });\n\n this.resourceLoader = new ResourceLoader({\n orchestrator: this as any,\n eventBus: this.eventBus,\n config: {\n maxConcurrent: config.maxWorkers || (this.config.load as any)?.retry?.maxAttempts || 4,\n },\n onStateChange: (resourceId, state) => this.handleResourceStateChange(resourceId, state),\n });\n\n this.planner = new CompositionPlanner();\n\n const cacheConfig = config.cacheConfig || this.config.cache;\n this.cacheManager = new CacheManager(\n {\n l1: {\n maxMemoryMB:\n (cacheConfig as any)?.l1Size || (cacheConfig as any)?.l1?.maxMemoryMB || 1024,\n maxGOPs: (this.config.decode as any)?.video?.maxGOPs || 4,\n },\n l2: {\n maxSizeMB: (cacheConfig as any)?.l2Size || (cacheConfig as any)?.l2?.maxSizeMB || 2048,\n projectId: 'default',\n },\n },\n this.eventBus\n );\n\n this.clipSessionManager = new ClipSessionManager({\n maxConcurrent: 2,\n factory: {\n createSession: (clipId) => this.createSession(clipId),\n },\n cacheManager: this.cacheManager,\n });\n\n this.audioSession = new GlobalAudioSession({\n cacheManager: this.cacheManager,\n workers: this.workers,\n resourceLoader: this.resourceLoader,\n eventBus: this.eventBus,\n getModel: () => this.compositionModel,\n buildWorkerConfigs: () => this.buildWorkerConfigs(),\n });\n\n this.muxManager = new MuxManager(\n this.cacheManager,\n this.audioSession,\n this.config.encode.audio as AudioEncoderConfig\n );\n }\n\n get workerStatus(): WorkerStatus {\n const status = this.workers.status;\n const result: WorkerStatus = {} as WorkerStatus;\n\n const workerTypes: WorkerType[] = [\n 'videoDemux',\n 'audioDemux',\n 'videoDecode',\n 'audioDecode',\n 'videoCompose',\n 'audioCompose',\n 'videoEncode',\n ];\n\n for (const type of workerTypes) {\n result[type] = status[type] || {\n state: 'idle',\n taskCount: 0,\n };\n }\n\n return result;\n }\n\n async initialize(): Promise<void> {\n if (this.isInitialized) return;\n\n await this.cacheManager.init();\n\n this.isInitialized = true;\n }\n\n // Event methods - forward to eventBus\n on<K extends keyof EventPayloadMap>(\n event: K,\n handler: (payload: EventPayloadMap[K]) => void\n ): void {\n this.eventBus.on(event, handler);\n }\n\n off<K extends keyof EventPayloadMap>(\n event: K,\n handler: (payload: EventPayloadMap[K]) => void\n ): void {\n this.eventBus.off(event, handler);\n }\n\n once<K extends keyof EventPayloadMap>(\n event: K,\n handler: (payload: EventPayloadMap[K]) => void\n ): void {\n this.eventBus.once(event, handler);\n }\n\n async setCompositionModel(model: CompositionModel): Promise<void> {\n this.compositionModel = model;\n this.planner.setModel(model);\n this.currentClipId = null;\n\n this.eventBus.emit(MeframeEvent.ModelSet, model);\n\n this.eventBus.emit(MeframeEvent.CompositionUpdated, {\n trackCount: model.tracks.length,\n clipCount: model.tracks.reduce((acc: number, track: any) => acc + track.clips.length, 0),\n durationUs: model.durationUs,\n });\n\n await this.audioSession.activateAllAudioClips();\n }\n\n async applyPatch(patch: CompositionPatch): Promise<void> {\n if (!this.compositionModel) {\n throw new Error('No composition model set');\n }\n\n // Apply patch and get affected clip IDs (simplified for 2-Clip strategy)\n const affectedClipIds = applyModelPatch(this.compositionModel, patch);\n const clipUpdates = this.planner.applyPatch(patch, affectedClipIds);\n\n this.eventBus.emit(MeframeEvent.PatchApplied, {\n operations: patch.operations.length,\n affectedClips: Array.from(affectedClipIds),\n });\n\n // Process clip updates\n for (const update of clipUpdates) {\n if (update.type === 'remove') {\n this.activeClips.delete(update.clipId);\n }\n\n this.cacheManager.invalidateClip(update.clipId);\n await this.clipSessionManager.handlePlannerUpdate(update.clipId, update);\n }\n\n // Reactivate updated audio clips\n const reactivatedAudioClips: string[] = [];\n const reactivatedVideoClips: string[] = [];\n for (const clipId of affectedClipIds) {\n const clip = this.compositionModel.findClip(clipId);\n if (clip?.trackKind === 'audio') {\n await this.audioSession.deactivateClip(clipId);\n reactivatedAudioClips.push(clipId);\n } else if (clip?.trackKind === 'video') {\n // Video clip audio will be restarted via VideoClipSession pipeline restart\n reactivatedVideoClips.push(clipId);\n }\n }\n\n // Activate all audio clips (including reactivated ones)\n await this.audioSession.activateAllAudioClips();\n\n // Restart playback for affected clips (give pipeline time to decode first frame)\n const allReactivatedClips = [...reactivatedAudioClips, ...reactivatedVideoClips];\n if (allReactivatedClips.length > 0) {\n setTimeout(() => {\n for (const clipId of allReactivatedClips) {\n this.audioSession.restartPlayingClip(clipId);\n }\n }, 150);\n }\n }\n\n private handleResourceStateChange(resourceId: string, state: Resource['state']): void {\n if (!this.compositionModel) {\n return;\n }\n\n this.compositionModel.updateResourceState(resourceId, state ?? 'pending');\n\n if (state !== 'ready') {\n return;\n }\n\n const resource = this.compositionModel.getResource(resourceId);\n if (!resource) {\n return;\n }\n\n // Main video/audio resources: data will flow naturally into pipeline\n if (resource.type === 'video' || resource.type === 'audio') {\n return;\n }\n\n // Attachment resources (fonts, images): update instructions for active clips\n const clipIds = this.compositionModel.getClipIdsByResourceId(resourceId);\n for (const clipId of clipIds) {\n // Only update active clips (in 2-Clip window)\n if (!this.clipSessionManager.isClipActive(clipId)) {\n continue;\n }\n\n const clip = this.compositionModel.findClip(clipId);\n if (!clip) {\n continue;\n }\n\n // Rebuild instructions with updated resource status\n const instructions = this.planner.getInstructions(clipId);\n if (!instructions) {\n continue;\n }\n\n // Send updated instructions to worker (no pipeline restart needed)\n const session = this.clipSessionManager.getSession(clipId);\n const visualWorker = session?.visualWorkerHandle;\n if (visualWorker) {\n visualWorker.send('install_instructions', instructions);\n }\n }\n }\n\n async restartWorker(type: WorkerType, clipId?: string): Promise<void> {\n const clipLocalTypes: WorkerType[] = [\n 'videoDemux',\n 'audioDemux',\n 'videoDecode',\n 'audioDecode',\n 'videoCompose',\n 'videoEncode',\n ];\n\n if (clipLocalTypes.includes(type) && !clipId) {\n throw new Error(`clipId required for restarting ${type} worker`);\n }\n\n this.workers.terminate(type, clipId);\n const worker = await this.workers.getOrCreate(type, clipId);\n\n this.eventBus.emit(MeframeEvent.WorkerRestarted, {\n type,\n workerId: worker.getWorkerId(),\n reason: 'Manual restart',\n });\n\n if (clipId) {\n const session = this.clipSessionManager.getSession(clipId);\n if (session) {\n await session.activate();\n }\n }\n }\n\n async renderFrame(timeUs: TimeUs, options?: RenderFrameOptions): Promise<RcFrame | null> {\n const signal = options?.signal;\n const immediate = options?.immediate ?? true;\n\n if (!this.compositionModel) {\n throw new Error('No composition model set');\n }\n\n const clip = this.compositionModel.getClipsAtTime(timeUs, this.compositionModel.mainTrackId)[0];\n if (!clip) {\n return null;\n }\n\n // Detect clip change and proactively ensure cache for current/next\n if (this.currentClipId !== clip.id) {\n this.currentClipId = clip.id;\n void this.ensureClipCache(timeUs, immediate);\n }\n\n // Calculate clip-relative time for cache lookup (global time - clip start time)\n let relativeTimeUs = options?.relativeTimeUs ?? timeUs - clip.startUs;\n\n // Quantize to frame boundary to handle timestamp precision issues\n relativeTimeUs = quantizeTimestampToFrame(relativeTimeUs, 0, this.compositionModel.fps);\n\n // Clamp to clip duration to handle edge cases where quantization pushes beyond clip end\n // This can happen when clip duration is not exactly aligned to frame boundaries\n relativeTimeUs = Math.min(relativeTimeUs, clip.durationUs - 1);\n\n const cachedFrame = this.cacheManager.getFrame(relativeTimeUs, clip.id);\n if (cachedFrame) {\n this.eventBus.emit(MeframeEvent.CacheHit, {\n timeUs,\n level: 'L1',\n key: `${clip.id}-${relativeTimeUs}`,\n });\n return cachedFrame;\n }\n\n this.eventBus.emit(MeframeEvent.CacheMiss, {\n timeUs,\n level: 'L1',\n key: `${clip.id}-${relativeTimeUs}`,\n });\n\n if (signal?.aborted) {\n throw new DOMException('Render aborted', 'AbortError');\n }\n\n // L1 miss - try decode from L2\n const l2Frame = await this.decodeFromL2(relativeTimeUs, clip);\n if (l2Frame) {\n // If we are serving video from L2, opportunistically ensure audio from L2 as well\n void this.ensureAudioFromL2(clip.id);\n return l2Frame;\n }\n\n return null;\n }\n\n private async ensureAudioFromL2(clipId: string): Promise<void> {\n try {\n // Skip if PCM already present\n if (this.cacheManager.hasClipPCM(clipId)) {\n return;\n }\n // Check if L2 has encoded audio for this clip\n const hasAudio = await this.cacheManager.hasClipInL2(clipId, 'audio');\n if (!hasAudio) return;\n // Decode from L2 into PCM cache (non-blocking for render)\n await this.audioSession.ensureClipAudioFromL2(clipId);\n } catch (error) {\n console.warn('[Orchestrator] ensureAudioFromL2IfNeeded error:', error);\n }\n }\n\n // TODO: move to @ClipSessionManager\n private async decodeFromL2(timeUs: TimeUs, clip: Clip): Promise<RcFrame | null> {\n const { id, trackId, startUs } = clip;\n const [chunkStream, metadata] = await Promise.all([\n this.cacheManager.l2Cache.createReadStream(id, 'video'),\n this.cacheManager.l2Cache.getClipMetadata(id, 'video'),\n ]);\n\n if (!chunkStream || !metadata?.codec) {\n return null;\n }\n\n const decoder = new VideoChunkDecoder(`l2-temp-${id}`, {\n codec: metadata.codec,\n width: metadata.codedWidth,\n height: metadata.codedHeight,\n description: metadata.description,\n hardwareAcceleration: metadata.hardwareAcceleration || 'no-preference',\n });\n\n try {\n const decodeStream = chunkStream.pipeThrough(decoder.createStream());\n\n let targetFrame: RcFrame | null = null;\n\n await this.cacheManager.receiveComposedFrames(decodeStream, {\n clipId: id,\n trackId: trackId || this.compositionModel?.mainTrackId || 'main',\n fps: this.compositionModel?.fps ?? 30,\n clipStartUs: startUs,\n onFrame: (info) => {\n if (info.timeUs === timeUs) {\n targetFrame = this.cacheManager.getFrame(timeUs, id);\n }\n },\n });\n\n return targetFrame;\n } finally {\n await decoder.close();\n }\n }\n\n /**\n * Ensure clips are cached using 2-Clip strategy\n * Debounced to avoid excessive session activation during fast seek\n * @param timeUs - Target time for cache window\n * @param immediate - Skip debounce if true (used for initial load)\n */\n async ensureClipCache(timeUs: TimeUs, immediate = false): Promise<void> {\n const executeCache = async (): Promise<void> => {\n if (!this.compositionModel) return;\n\n const clipIds = this.compositionModel.getClipsToCacheAtTime(timeUs);\n if (clipIds.size === 0) return;\n await this.clipSessionManager.ensureClips(clipIds);\n };\n\n if (this.ensureCacheDebounceTimer !== null) {\n clearTimeout(this.ensureCacheDebounceTimer);\n this.ensureCacheDebounceTimer = null;\n }\n\n if (immediate) {\n return executeCache();\n }\n\n return new Promise((resolve) => {\n this.ensureCacheDebounceTimer = setTimeout(async () => {\n this.ensureCacheDebounceTimer = null;\n await executeCache();\n resolve();\n }, this.ensureCacheDebounceDelay) as unknown as number;\n });\n }\n\n /**\n * Wait for clip cache to be ready for playback\n * Returns true if minimum cache is ready, false if timeout\n */\n async waitForClipReady(\n timeUs: TimeUs,\n options?: { minFrameCount?: number; timeoutMs?: number }\n ): Promise<boolean> {\n if (!this.compositionModel) {\n return false;\n }\n\n const clips = this.compositionModel.getClipsAtTime(timeUs, this.compositionModel.mainTrackId);\n if (clips.length === 0) {\n return true;\n }\n\n const currentClip = clips[0];\n if (!currentClip) {\n return true;\n }\n\n // For buffering scenario, we just need ANY frames in the clip\n // Don't restrict to frames after a specific startTimeUs, as the pipeline\n // might be rendering from the beginning while playback is in the middle\n return this.cacheManager.waitForClipReady(currentClip.id, {\n minFrameCount: options?.minFrameCount ?? 5,\n timeoutMs: options?.timeoutMs ?? 5_000,\n // Don't pass startTimeUs - count all frames in the clip\n });\n }\n\n // TODO: move to @ClipSessionManager\n async renderClipForL2(clipId: string): Promise<boolean> {\n const sessionId = `${clipId}#l2`;\n let session: VideoClipSession | null = null;\n\n return new Promise<boolean>((resolve, reject) => {\n this.createSession(sessionId, {\n forL2Only: true,\n clipId: clipId,\n onL2Complete: () => {\n resolve(true);\n },\n onL2Error: (error) => {\n console.error('[Orchestrator] L2 rendering failed for', clipId, error);\n reject(error);\n },\n })\n .then((s) => {\n session = s;\n return session.activate();\n })\n .catch(async (error) => {\n // Clean up partial session on any error to avoid worker state pollution\n if (session) {\n await session.dispose();\n }\n\n if (error instanceof ResourceConflictError) {\n resolve(false);\n } else {\n reject(error);\n }\n });\n });\n }\n\n // TODO: move to @ClipSessionManager\n private async createSession(\n sessionId: string,\n options?: {\n forL2Only?: boolean;\n clipId?: string;\n onL2Complete?: () => void;\n onL2Error?: (error: Error) => void;\n }\n ): Promise<VideoClipSession> {\n const clipId = options?.clipId ?? sessionId;\n const clip = this.compositionModel?.findClip(clipId);\n if (!clip) {\n throw new Error(`Clip ${clipId} not found`);\n }\n\n const session = await VideoClipSession.create({\n clipId,\n sessionId,\n forL2Only: options?.forL2Only ?? false,\n planner: this.planner,\n workerPool: this.workers,\n cacheManager: this.cacheManager,\n compositionModel: this.compositionModel!,\n workerConfigs: this.buildWorkerConfigs(),\n resourceLoader: this.resourceLoader,\n callbacks: {\n onComposedStreamReady: (stream, fps) => {\n if (options?.forL2Only) {\n // L2 channel: don't need L1, cancel stream\n stream.cancel();\n } else {\n // Preview channel: fill L1\n this.cacheManager.receiveComposedFrames(stream, {\n clipId: clipId,\n trackId: this.compositionModel!.mainTrackId,\n fps,\n clipStartUs: clip.startUs,\n onFrame: () => {},\n });\n }\n },\n onEncodedStreamReady: (stream, track) => {\n if (options?.forL2Only) {\n // L2 channel: write to L2 using clipId, notify on complete\n this.cacheManager.receiveEncodedChunks(stream, clipId, track, {\n onComplete: () => {\n session.dispose();\n // Only notify completion for video track (audio is optional)\n if (track === 'video' && options.onL2Complete) {\n options.onL2Complete();\n }\n },\n onError: (error) => {\n console.error(\n `[Orchestrator] L2 encode stream error for ${clipId} ${track}:`,\n error\n );\n session.dispose();\n if (options.onL2Error) {\n options.onL2Error(error);\n }\n },\n });\n } else {\n // Preview channel: don't write to L2, cancel stream\n stream.cancel();\n }\n },\n onAudioStreamReady: (stream, metadata) => {\n if (options?.forL2Only) {\n stream.cancel();\n } else {\n this.audioSession.handleAudioStream(stream, metadata);\n }\n },\n onPipelineReady: async (attachmentResourceIds?: string[]) => {\n // 1. Load main track resource\n const clip = this.compositionModel?.findClip(clipId);\n if (clip && hasResourceId(clip)) {\n await this.resourceLoader.fetch(clip.resourceId, {\n priority: options?.forL2Only ? 'low' : 'high',\n sessionId: sessionId,\n trackId: clip.trackId,\n isMainTrack: true,\n });\n }\n\n // 2. Load attachment resources (global shared Blob cache)\n if (attachmentResourceIds && attachmentResourceIds.length > 0) {\n for (const resourceId of attachmentResourceIds) {\n await this.resourceLoader.fetch(resourceId, {\n priority: 'normal',\n sessionId: sessionId,\n isMainTrack: false,\n });\n }\n }\n },\n },\n });\n\n this.activeClips.add(sessionId);\n return session;\n }\n\n async dispose(): Promise<void> {\n if (this.ensureCacheDebounceTimer !== null) {\n clearTimeout(this.ensureCacheDebounceTimer);\n this.ensureCacheDebounceTimer = null;\n }\n\n this.resourceLoader.dispose();\n await this.clipSessionManager.dispose();\n await this.cacheManager.clear();\n\n this.currentClipId = null;\n this.activeClips.clear();\n\n this.workers.terminateAll();\n this.compositionModel = null;\n this.eventBus.dispose();\n }\n\n private buildWorkerConfigs(): Record<WorkerType, any> {\n const config = this.config as any;\n const defaultCanvasWidth = config.global?.defaultCanvasWidth ?? 720;\n const defaultCanvasHeight = config.global?.defaultCanvasHeight ?? 1280;\n const defaultFps = config.global?.defaultFps ?? 30;\n return {\n videoDemux: {\n highWaterMark: config.demux?.backpressure?.highWaterMark ?? 10,\n },\n audioDemux: {\n highWaterMark: config.demux?.backpressure?.highWaterMark ?? 10,\n },\n videoDecode: config.decode?.video,\n audioDecode: config.decode?.audio,\n videoCompose: {\n width: config.compose?.canvas?.width ?? defaultCanvasWidth,\n height: config.compose?.canvas?.height ?? defaultCanvasHeight,\n fps: config.global?.defaultFps ?? defaultFps,\n backgroundColor: config.compose?.canvas?.backgroundColor ?? '#000000',\n enableSmoothing: config.compose?.visual?.enableSmoothing ?? true,\n enableHardwareAcceleration: config.compose?.visual?.enableHardwareAcceleration ?? true,\n },\n audioCompose: {\n ducking: config.compose?.audio?.ducking,\n mixing: config.compose?.audio?.mixing,\n },\n videoEncode: {\n codec: 'avc1.42002A',\n width: config.compose?.canvas?.width || defaultCanvasWidth,\n height: config.compose?.canvas?.height || defaultCanvasHeight,\n bitrate: config.encode?.video?.bitrateKbps\n ? config.encode.video.bitrateKbps * 1000\n : 12_000_000,\n framerate: config.encode?.video?.framerate || defaultFps,\n latencyMode: 'quality',\n bitrateMode: 'variable',\n hardwareAcceleration: 'no-preference',\n ...(config.encode?.video as any),\n },\n };\n }\n\n async export(model: CompositionModel, options: ExportOptions): Promise<Blob> {\n return this.muxManager.export(model, options);\n }\n}\n"],"names":["applyModelPatch","clip"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Orchestrator.js","sources":["../../src/orchestrator/Orchestrator.ts"],"sourcesContent":["import { EventBus } from '../event/EventBus';\nimport { WorkerPool } from '../worker/WorkerPool';\nimport { applyPatch as applyModelPatch } from '../model/patch';\nimport { ResourceConflictError, ResourceLoader } from '../stages/load/ResourceLoader';\nimport { CacheManager } from '../cache/CacheManager';\nimport { ConfigLoader } from '../config/ConfigLoader';\nimport type { IOrchestrator, OrchestratorConfig, RenderFrameOptions } from './types';\nimport { WorkerStatus, WorkerType } from '../worker/types';\nimport { CompositionModel, CompositionPatch, Resource, TimeUs, RcFrame, Clip } from '../model';\nimport { hasResourceId } from '../model/types';\nimport { MeframeEvent, type EventPayloadMap } from '../event/events';\nimport { CompositionPlanner } from './CompositionPlanner';\nimport { VideoClipSession } from './VideoClipSession';\nimport { ClipSessionManager } from './ClipSessionManager';\nimport { GlobalAudioSession } from './GlobalAudioSession';\nimport { MuxManager } from '../stages/mux/MuxManager';\nimport { ExportOptions } from '@/types';\nimport { VideoChunkDecoder } from '../stages/decode/VideoChunkDecoder';\nimport { quantizeTimestampToFrame } from '../utils/time-utils';\n\nexport class Orchestrator implements IOrchestrator {\n workers: WorkerPool;\n eventBus: EventBus<EventPayloadMap>;\n compositionModel: CompositionModel | null = null;\n resourceLoader: ResourceLoader;\n cacheManager: CacheManager;\n planner: CompositionPlanner;\n audioSession: GlobalAudioSession;\n muxManager: MuxManager;\n\n private activeClips = new Set<string>();\n private isInitialized = false;\n private config = ConfigLoader.getInstance().getConfig();\n private clipSessionManager: ClipSessionManager;\n private currentClipId: string | null = null;\n private ensureCacheDebounceTimer: number | null = null;\n private readonly ensureCacheDebounceDelay = 150;\n readonly events: Pick<EventBus<EventPayloadMap>, 'on' | 'off' | 'once'>;\n\n constructor(config: OrchestratorConfig) {\n // Use provided eventBus or create a new one\n this.eventBus = config.eventBus || new EventBus<EventPayloadMap>();\n this.events = this.eventBus.asReadonly();\n\n // Initialize config first\n this.config = ConfigLoader.getInstance().getConfig();\n\n const workerConfigs = this.buildWorkerConfigs();\n\n // Initialize WorkerPool with worker path from config\n this.workers = new WorkerPool({\n eventBus: this.eventBus,\n workerConfigs,\n workerPath: config.workerPath,\n workerExtension: config.workerExtension,\n });\n\n this.resourceLoader = new ResourceLoader({\n orchestrator: this as any,\n eventBus: this.eventBus,\n config: {\n maxConcurrent: config.maxWorkers || (this.config.load as any)?.retry?.maxAttempts || 4,\n },\n onStateChange: (resourceId, state) => this.handleResourceStateChange(resourceId, state),\n });\n\n this.planner = new CompositionPlanner();\n\n const cacheConfig = config.cacheConfig || this.config.cache;\n this.cacheManager = new CacheManager(\n {\n l1: {\n maxMemoryMB:\n (cacheConfig as any)?.l1Size || (cacheConfig as any)?.l1?.maxMemoryMB || 1024,\n maxGOPs: (this.config.decode as any)?.video?.maxGOPs || 4,\n },\n l2: {\n maxSizeMB: (cacheConfig as any)?.l2Size || (cacheConfig as any)?.l2?.maxSizeMB || 2048,\n projectId: 'default',\n },\n },\n this.eventBus\n );\n\n this.clipSessionManager = new ClipSessionManager({\n maxConcurrent: 2,\n factory: {\n createSession: (clipId) => this.createSession(clipId),\n },\n cacheManager: this.cacheManager,\n });\n\n this.audioSession = new GlobalAudioSession({\n cacheManager: this.cacheManager,\n workers: this.workers,\n resourceLoader: this.resourceLoader,\n eventBus: this.eventBus,\n getModel: () => this.compositionModel,\n buildWorkerConfigs: () => this.buildWorkerConfigs(),\n });\n\n this.muxManager = new MuxManager(\n this.cacheManager,\n this.audioSession,\n this.config.encode.audio as AudioEncoderConfig\n );\n }\n\n get workerStatus(): WorkerStatus {\n const status = this.workers.status;\n const result: WorkerStatus = {} as WorkerStatus;\n\n const workerTypes: WorkerType[] = [\n 'videoDemux',\n 'audioDemux',\n 'videoDecode',\n 'audioDecode',\n 'videoCompose',\n 'audioCompose',\n 'videoEncode',\n ];\n\n for (const type of workerTypes) {\n result[type] = status[type] || {\n state: 'idle',\n taskCount: 0,\n };\n }\n\n return result;\n }\n\n async initialize(): Promise<void> {\n if (this.isInitialized) return;\n\n await this.cacheManager.init();\n\n this.isInitialized = true;\n }\n\n // Event methods - forward to eventBus\n on<K extends keyof EventPayloadMap>(\n event: K,\n handler: (payload: EventPayloadMap[K]) => void\n ): void {\n this.eventBus.on(event, handler);\n }\n\n off<K extends keyof EventPayloadMap>(\n event: K,\n handler: (payload: EventPayloadMap[K]) => void\n ): void {\n this.eventBus.off(event, handler);\n }\n\n once<K extends keyof EventPayloadMap>(\n event: K,\n handler: (payload: EventPayloadMap[K]) => void\n ): void {\n this.eventBus.once(event, handler);\n }\n\n async setCompositionModel(model: CompositionModel): Promise<void> {\n this.compositionModel = model;\n this.planner.setModel(model);\n this.currentClipId = null;\n\n this.eventBus.emit(MeframeEvent.ModelSet, model);\n\n this.eventBus.emit(MeframeEvent.CompositionUpdated, {\n trackCount: model.tracks.length,\n clipCount: model.tracks.reduce((acc: number, track: any) => acc + track.clips.length, 0),\n durationUs: model.durationUs,\n });\n\n await this.audioSession.activateAllAudioClips();\n }\n\n async applyPatch(patch: CompositionPatch): Promise<void> {\n if (!this.compositionModel) {\n throw new Error('No composition model set');\n }\n\n // Apply patch and get affected clip IDs (simplified for 2-Clip strategy)\n const affectedClipIds = applyModelPatch(this.compositionModel, patch);\n const clipUpdates = this.planner.applyPatch(patch, affectedClipIds);\n\n this.eventBus.emit(MeframeEvent.PatchApplied, {\n operations: patch.operations.length,\n affectedClips: Array.from(affectedClipIds),\n });\n\n // Process clip updates\n for (const update of clipUpdates) {\n if (update.type === 'remove') {\n this.activeClips.delete(update.clipId);\n }\n\n this.cacheManager.invalidateClip(update.clipId);\n await this.clipSessionManager.handlePlannerUpdate(update.clipId, update);\n }\n\n // Reactivate updated audio clips\n const reactivatedAudioClips: string[] = [];\n const reactivatedVideoClips: string[] = [];\n for (const clipId of affectedClipIds) {\n const clip = this.compositionModel.findClip(clipId);\n if (clip?.trackKind === 'audio') {\n await this.audioSession.deactivateClip(clipId);\n reactivatedAudioClips.push(clipId);\n } else if (clip?.trackKind === 'video') {\n // Video clip audio will be restarted via VideoClipSession pipeline restart\n reactivatedVideoClips.push(clipId);\n }\n }\n\n // Activate all audio clips (including reactivated ones)\n await this.audioSession.activateAllAudioClips();\n\n // Restart playback for affected clips (give pipeline time to decode first frame)\n const allReactivatedClips = [...reactivatedAudioClips, ...reactivatedVideoClips];\n if (allReactivatedClips.length > 0) {\n setTimeout(() => {\n for (const clipId of allReactivatedClips) {\n this.audioSession.restartPlayingClip(clipId);\n }\n }, 150);\n }\n }\n\n private handleResourceStateChange(resourceId: string, state: Resource['state']): void {\n if (!this.compositionModel) {\n return;\n }\n\n this.compositionModel.updateResourceState(resourceId, state ?? 'pending');\n\n if (state !== 'ready') {\n return;\n }\n\n const resource = this.compositionModel.getResource(resourceId);\n if (!resource) {\n return;\n }\n\n // Main video/audio resources: data will flow naturally into pipeline\n if (resource.type === 'video' || resource.type === 'audio') {\n return;\n }\n\n // Attachment resources (fonts, images): update instructions for active clips\n const clipIds = this.compositionModel.getClipIdsByResourceId(resourceId);\n for (const clipId of clipIds) {\n // Only update active clips (in 2-Clip window)\n if (!this.clipSessionManager.isClipActive(clipId)) {\n continue;\n }\n\n const clip = this.compositionModel.findClip(clipId);\n if (!clip) {\n continue;\n }\n\n // Rebuild instructions with updated resource status\n const instructions = this.planner.getInstructions(clipId);\n if (!instructions) {\n continue;\n }\n\n // Send updated instructions to worker (no pipeline restart needed)\n const session = this.clipSessionManager.getSession(clipId);\n const visualWorker = session?.visualWorkerHandle;\n if (visualWorker) {\n visualWorker.send('install_instructions', instructions);\n }\n }\n }\n\n async restartWorker(type: WorkerType, clipId?: string): Promise<void> {\n const clipLocalTypes: WorkerType[] = [\n 'videoDemux',\n 'audioDemux',\n 'videoDecode',\n 'audioDecode',\n 'videoCompose',\n 'videoEncode',\n ];\n\n if (clipLocalTypes.includes(type) && !clipId) {\n throw new Error(`clipId required for restarting ${type} worker`);\n }\n\n this.workers.terminate(type, clipId);\n const worker = await this.workers.getOrCreate(type, clipId);\n\n this.eventBus.emit(MeframeEvent.WorkerRestarted, {\n type,\n workerId: worker.getWorkerId(),\n reason: 'Manual restart',\n });\n\n if (clipId) {\n const session = this.clipSessionManager.getSession(clipId);\n if (session) {\n await session.activate();\n }\n }\n }\n\n async renderFrame(timeUs: TimeUs, options?: RenderFrameOptions): Promise<RcFrame | null> {\n const signal = options?.signal;\n const immediate = options?.immediate ?? true;\n\n if (!this.compositionModel) {\n throw new Error('No composition model set');\n }\n\n const clip = this.compositionModel.getClipsAtTime(timeUs, this.compositionModel.mainTrackId)[0];\n if (!clip) {\n return null;\n }\n\n // Detect clip change and proactively ensure cache for current/next\n if (this.currentClipId !== clip.id) {\n this.currentClipId = clip.id;\n void this.ensureClipCache(timeUs, immediate);\n }\n\n // Calculate clip-relative time for cache lookup (global time - clip start time)\n let relativeTimeUs = options?.relativeTimeUs ?? timeUs - clip.startUs;\n\n // Quantize to frame boundary to handle timestamp precision issues\n relativeTimeUs = quantizeTimestampToFrame(relativeTimeUs, 0, this.compositionModel.fps);\n\n // Clamp to clip duration to handle edge cases where quantization pushes beyond clip end\n // This can happen when clip duration is not exactly aligned to frame boundaries\n relativeTimeUs = Math.min(relativeTimeUs, clip.durationUs - 1);\n\n const cachedFrame = this.cacheManager.getFrame(relativeTimeUs, clip.id);\n if (cachedFrame) {\n this.eventBus.emit(MeframeEvent.CacheHit, {\n timeUs,\n level: 'L1',\n key: `${clip.id}-${relativeTimeUs}`,\n });\n return cachedFrame;\n }\n\n this.eventBus.emit(MeframeEvent.CacheMiss, {\n timeUs,\n level: 'L1',\n key: `${clip.id}-${relativeTimeUs}`,\n });\n\n if (signal?.aborted) {\n throw new DOMException('Render aborted', 'AbortError');\n }\n\n // L1 miss - try decode from L2\n const l2Frame = await this.decodeFromL2(relativeTimeUs, clip);\n if (l2Frame) {\n // If we are serving video from L2, opportunistically ensure audio from L2 as well\n void this.ensureAudioFromL2(clip.id);\n return l2Frame;\n }\n\n return null;\n }\n\n private async ensureAudioFromL2(clipId: string): Promise<void> {\n try {\n // Skip if PCM already present\n if (this.cacheManager.hasClipPCM(clipId)) {\n return;\n }\n // Check if L2 has encoded audio for this clip\n const hasAudio = await this.cacheManager.hasClipInL2(clipId, 'audio');\n if (!hasAudio) return;\n // Decode from L2 into PCM cache (non-blocking for render)\n await this.audioSession.ensureClipAudioFromL2(clipId);\n } catch (error) {\n console.warn('[Orchestrator] ensureAudioFromL2IfNeeded error:', error);\n }\n }\n\n // TODO: move to @ClipSessionManager\n private async decodeFromL2(timeUs: TimeUs, clip: Clip): Promise<RcFrame | null> {\n const { id, trackId, startUs } = clip;\n const [chunkStream, metadata] = await Promise.all([\n this.cacheManager.l2Cache.createReadStream(id, 'video'),\n this.cacheManager.l2Cache.getClipMetadata(id, 'video'),\n ]);\n\n if (!chunkStream || !metadata?.codec) {\n return null;\n }\n\n const decoder = new VideoChunkDecoder(`l2-temp-${id}`, {\n codec: metadata.codec,\n width: metadata.codedWidth,\n height: metadata.codedHeight,\n description: metadata.description,\n hardwareAcceleration: metadata.hardwareAcceleration || 'no-preference',\n });\n\n try {\n const decodeStream = chunkStream.pipeThrough(decoder.createStream());\n\n let targetFrame: RcFrame | null = null;\n\n await this.cacheManager.receiveComposedFrames(decodeStream, {\n clipId: id,\n trackId: trackId || this.compositionModel?.mainTrackId || 'main',\n fps: this.compositionModel?.fps ?? 30,\n clipStartUs: startUs,\n onFrame: (info) => {\n if (info.timeUs === timeUs) {\n targetFrame = this.cacheManager.getFrame(timeUs, id);\n }\n },\n });\n\n return targetFrame;\n } finally {\n await decoder.close();\n }\n }\n\n /**\n * Ensure clips are cached using 2-Clip strategy\n * Debounced to avoid excessive session activation during fast seek\n * @param timeUs - Target time for cache window\n * @param immediate - Skip debounce if true (used for initial load)\n */\n async ensureClipCache(timeUs: TimeUs, immediate = false): Promise<void> {\n const executeCache = async (): Promise<void> => {\n if (!this.compositionModel) return;\n\n const clipIds = this.compositionModel.getClipsToCacheAtTime(timeUs);\n if (clipIds.size === 0) return;\n await this.clipSessionManager.ensureClips(clipIds);\n };\n\n if (this.ensureCacheDebounceTimer !== null) {\n clearTimeout(this.ensureCacheDebounceTimer);\n this.ensureCacheDebounceTimer = null;\n }\n\n if (immediate) {\n return executeCache();\n }\n\n return new Promise((resolve) => {\n this.ensureCacheDebounceTimer = setTimeout(async () => {\n this.ensureCacheDebounceTimer = null;\n await executeCache();\n resolve();\n }, this.ensureCacheDebounceDelay) as unknown as number;\n });\n }\n\n /**\n * Wait for clip cache to be ready for playback\n * Returns true if minimum cache is ready, false if timeout\n */\n async waitForClipReady(\n timeUs: TimeUs,\n options?: { minFrameCount?: number; timeoutMs?: number }\n ): Promise<boolean> {\n if (!this.compositionModel) {\n return false;\n }\n\n const clips = this.compositionModel.getClipsAtTime(timeUs, this.compositionModel.mainTrackId);\n if (clips.length === 0) {\n return true;\n }\n\n const currentClip = clips[0];\n if (!currentClip) {\n return true;\n }\n\n // For buffering scenario, we just need ANY frames in the clip\n // Don't restrict to frames after a specific startTimeUs, as the pipeline\n // might be rendering from the beginning while playback is in the middle\n return this.cacheManager.waitForClipReady(currentClip.id, {\n minFrameCount: options?.minFrameCount ?? 5,\n timeoutMs: options?.timeoutMs ?? 5_000,\n // Don't pass startTimeUs - count all frames in the clip\n });\n }\n\n // TODO: move to @ClipSessionManager\n async renderClipForL2(clipId: string): Promise<boolean> {\n const sessionId = `${clipId}#l2`;\n let session: VideoClipSession | null = null;\n\n return new Promise<boolean>((resolve, reject) => {\n this.createSession(sessionId, {\n forL2Only: true,\n clipId: clipId,\n onL2Complete: () => {\n resolve(true);\n },\n onL2Error: (error) => {\n console.error('[Orchestrator] L2 rendering failed for', clipId, error);\n reject(error);\n },\n })\n .then((s) => {\n session = s;\n return session.activate();\n })\n .catch(async (error) => {\n // Clean up partial session on any error to avoid worker state pollution\n if (session) {\n await session.dispose();\n }\n\n if (error instanceof ResourceConflictError) {\n resolve(false);\n } else {\n reject(error);\n }\n });\n });\n }\n\n // TODO: move to @ClipSessionManager\n private async createSession(\n sessionId: string,\n options?: {\n forL2Only?: boolean;\n clipId?: string;\n onL2Complete?: () => void;\n onL2Error?: (error: Error) => void;\n }\n ): Promise<VideoClipSession> {\n const clipId = options?.clipId ?? sessionId;\n const clip = this.compositionModel?.findClip(clipId);\n if (!clip) {\n throw new Error(`Clip ${clipId} not found`);\n }\n\n const session = await VideoClipSession.create({\n clipId,\n sessionId,\n forL2Only: options?.forL2Only ?? false,\n planner: this.planner,\n workerPool: this.workers,\n cacheManager: this.cacheManager,\n compositionModel: this.compositionModel!,\n workerConfigs: this.buildWorkerConfigs(),\n resourceLoader: this.resourceLoader,\n callbacks: {\n onComposedStreamReady: (stream, fps) => {\n if (options?.forL2Only) {\n // L2 channel: don't need L1, cancel stream\n stream.cancel();\n } else {\n // Preview channel: fill L1\n this.cacheManager.receiveComposedFrames(stream, {\n clipId: clipId,\n trackId: this.compositionModel!.mainTrackId,\n fps,\n clipStartUs: clip.startUs,\n onFrame: () => {},\n });\n }\n },\n onEncodedStreamReady: (stream, track) => {\n if (options?.forL2Only) {\n // L2 channel: write to L2 using clipId, notify on complete\n this.cacheManager.receiveEncodedChunks(stream, clipId, track, {\n onComplete: () => {\n session.dispose();\n // Only notify completion for video track (audio is optional)\n if (track === 'video' && options.onL2Complete) {\n options.onL2Complete();\n }\n },\n onError: (error) => {\n console.error(\n `[Orchestrator] L2 encode stream error for ${clipId} ${track}:`,\n error\n );\n session.dispose();\n if (options.onL2Error) {\n options.onL2Error(error);\n }\n },\n });\n } else {\n // Preview channel: don't write to L2, cancel stream\n stream.cancel();\n }\n },\n onAudioStreamReady: (stream, metadata) => {\n if (options?.forL2Only) {\n stream.cancel();\n } else {\n this.audioSession.handleAudioStream(stream, metadata);\n }\n },\n onPipelineReady: async (attachmentResourceIds?: string[]) => {\n // 1. Load main track resource\n const clip = this.compositionModel?.findClip(clipId);\n if (clip && hasResourceId(clip)) {\n await this.resourceLoader.fetch(clip.resourceId, {\n priority: options?.forL2Only ? 'low' : 'high',\n sessionId: sessionId,\n trackId: clip.trackId,\n isMainTrack: true,\n });\n }\n\n // 2. Load attachment resources (global shared Blob cache)\n if (attachmentResourceIds && attachmentResourceIds.length > 0) {\n for (const resourceId of attachmentResourceIds) {\n await this.resourceLoader.fetch(resourceId, {\n priority: 'normal',\n sessionId: sessionId,\n isMainTrack: false,\n });\n }\n }\n },\n },\n });\n\n this.activeClips.add(sessionId);\n return session;\n }\n\n async dispose(): Promise<void> {\n if (this.ensureCacheDebounceTimer !== null) {\n clearTimeout(this.ensureCacheDebounceTimer);\n this.ensureCacheDebounceTimer = null;\n }\n\n this.resourceLoader.dispose();\n await this.clipSessionManager.dispose();\n await this.cacheManager.clear();\n\n this.currentClipId = null;\n this.activeClips.clear();\n\n this.workers.terminateAll();\n this.compositionModel = null;\n this.eventBus.dispose();\n }\n\n private buildWorkerConfigs(): Record<WorkerType, any> {\n const config = this.config as any;\n const defaultCanvasWidth = config.global?.defaultCanvasWidth ?? 720;\n const defaultCanvasHeight = config.global?.defaultCanvasHeight ?? 1280;\n const defaultFps = config.global?.defaultFps ?? 30;\n return {\n videoDemux: {\n highWaterMark: config.demux?.backpressure?.highWaterMark ?? 10,\n },\n audioDemux: {\n highWaterMark: config.demux?.backpressure?.highWaterMark ?? 10,\n },\n videoDecode: config.decode?.video,\n audioDecode: config.decode?.audio,\n videoCompose: {\n width: config.compose?.canvas?.width ?? defaultCanvasWidth,\n height: config.compose?.canvas?.height ?? defaultCanvasHeight,\n fps: config.global?.defaultFps ?? defaultFps,\n backgroundColor: config.compose?.canvas?.backgroundColor ?? '#000000',\n enableSmoothing: config.compose?.visual?.enableSmoothing ?? true,\n enableHardwareAcceleration: config.compose?.visual?.enableHardwareAcceleration ?? true,\n fonts: config.global?.fonts,\n },\n audioCompose: {\n ducking: config.compose?.audio?.ducking,\n mixing: config.compose?.audio?.mixing,\n },\n videoEncode: {\n codec: 'avc1.42002A',\n width: config.compose?.canvas?.width || defaultCanvasWidth,\n height: config.compose?.canvas?.height || defaultCanvasHeight,\n bitrate: config.encode?.video?.bitrateKbps\n ? config.encode.video.bitrateKbps * 1000\n : 12_000_000,\n framerate: config.encode?.video?.framerate || defaultFps,\n latencyMode: 'quality',\n bitrateMode: 'variable',\n hardwareAcceleration: 'no-preference',\n ...(config.encode?.video as any),\n },\n };\n }\n\n async export(model: CompositionModel, options: ExportOptions): Promise<Blob> {\n return this.muxManager.export(model, options);\n }\n}\n"],"names":["applyModelPatch","clip"],"mappings":"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"}
|
|
@@ -8,7 +8,10 @@ export declare class LayerRenderer {
|
|
|
8
8
|
private ctx;
|
|
9
9
|
private width;
|
|
10
10
|
private height;
|
|
11
|
-
|
|
11
|
+
private currentFrame;
|
|
12
|
+
private fps;
|
|
13
|
+
constructor(ctx: OffscreenCanvasRenderingContext2D, width: number, height: number, fps?: number);
|
|
14
|
+
setCurrentFrame(frame: number): void;
|
|
12
15
|
private ensureHighQualityRendering;
|
|
13
16
|
/**
|
|
14
17
|
* Render a single layer with all its properties
|
|
@@ -20,12 +23,6 @@ export declare class LayerRenderer {
|
|
|
20
23
|
private renderVideoLayer;
|
|
21
24
|
private renderImageLayer;
|
|
22
25
|
private renderTextLayer;
|
|
23
|
-
/**
|
|
24
|
-
* Draw enhanced multi-layer stroke for better text visibility
|
|
25
|
-
*/
|
|
26
|
-
private drawEnhancedStroke;
|
|
27
|
-
private calculateTextX;
|
|
28
|
-
private calculateTextY;
|
|
29
26
|
private applyMask;
|
|
30
27
|
updateDimensions(width: number, height: number): void;
|
|
31
28
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LayerRenderer.d.ts","sourceRoot":"","sources":["../../../src/stages/compose/LayerRenderer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAA8D,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"LayerRenderer.d.ts","sourceRoot":"","sources":["../../../src/stages/compose/LayerRenderer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAA8D,MAAM,SAAS,CAAC;AAMjG;;;GAGG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,GAAG,CAAoC;IAC/C,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,YAAY,CAAa;IACjC,OAAO,CAAC,GAAG,CAAc;gBAGvB,GAAG,EAAE,iCAAiC,EACtC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,GAAG,GAAE,MAAW;IASlB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIpC,OAAO,CAAC,0BAA0B;IAKlC;;OAEG;IACG,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC;IA0C9C,OAAO,CAAC,cAAc;IAqBtB,OAAO,CAAC,kBAAkB;IA+C1B,OAAO,CAAC,cAAc;YA2BR,gBAAgB;YAuChB,gBAAgB;YAiFhB,eAAe;IAuC7B,OAAO,CAAC,SAAS;IAkBjB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;CAKtD"}
|
|
@@ -24,6 +24,7 @@ export declare class VideoComposer {
|
|
|
24
24
|
composeTransition(fromRequest: ComposeRequest, toRequest: ComposeRequest, transition: TransitionEffect): Promise<ComposeResult>;
|
|
25
25
|
private clearCanvas;
|
|
26
26
|
private createOutputFrame;
|
|
27
|
+
private loadFonts;
|
|
27
28
|
updateConfig(config: Partial<VideoComposeConfig>): void;
|
|
28
29
|
dispose(): void;
|
|
29
30
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VideoComposer.d.ts","sourceRoot":"","sources":["../../../src/stages/compose/VideoComposer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,cAAc,EACd,aAAa,EACb,gBAAgB,EAGjB,MAAM,SAAS,CAAC;AAKjB,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAEpD,UAAU,cAAc;IACtB,aAAa,EAAE,cAAc,CAAC,cAAc,CAAC,CAAC;IAC9C,WAAW,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IACxC,YAAY,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;CAC1C;AAED;;GAEG;AACH,qBAAa,aAAa;IACxB,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,kBAAkB,CAAC,CAAC;IAC9C,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;IAEjC,OAAO,CAAC,GAAG,CAAoC;IAC/C,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,mBAAmB,CAAsB;IACjD,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,eAAe,CAAyB;gBAEpC,MAAM,EAAE,kBAAkB;
|
|
1
|
+
{"version":3,"file":"VideoComposer.d.ts","sourceRoot":"","sources":["../../../src/stages/compose/VideoComposer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,cAAc,EACd,aAAa,EACb,gBAAgB,EAGjB,MAAM,SAAS,CAAC;AAKjB,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAEpD,UAAU,cAAc;IACtB,aAAa,EAAE,cAAc,CAAC,cAAc,CAAC,CAAC;IAC9C,WAAW,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IACxC,YAAY,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;CAC1C;AAED;;GAEG;AACH,qBAAa,aAAa;IACxB,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,kBAAkB,CAAC,CAAC;IAC9C,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;IAEjC,OAAO,CAAC,GAAG,CAAoC;IAC/C,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,mBAAmB,CAAsB;IACjD,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,eAAe,CAAyB;gBAEpC,MAAM,EAAE,kBAAkB;IAgCtC,OAAO,CAAC,aAAa;IAwBrB,aAAa,CAAC,YAAY,CAAC,EAAE,kBAAkB,GAAG,cAAc;IAqC1D,YAAY,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAqE7D,iBAAiB,CACrB,WAAW,EAAE,cAAc,EAC3B,SAAS,EAAE,cAAc,EACzB,UAAU,EAAE,gBAAgB,GAC3B,OAAO,CAAC,aAAa,CAAC;IAWzB,OAAO,CAAC,WAAW;YAaL,iBAAiB;YAWjB,SAAS;IAkBvB,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,kBAAkB,CAAC,GAAG,IAAI;IAuBvD,OAAO,IAAI,IAAI;CAGhB"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { LocaleCode, SerializedFontConfig } from './types';
|
|
2
|
+
|
|
3
|
+
export declare class FontManager {
|
|
4
|
+
private fontCache;
|
|
5
|
+
getFontConfig(locale: LocaleCode, templateName: string, fontFamilyName?: string): SerializedFontConfig;
|
|
6
|
+
private createFontConfig;
|
|
7
|
+
clearCache(): void;
|
|
8
|
+
}
|
|
9
|
+
export declare function getFontConfig(locale: LocaleCode, templateName: string, fontFamilyName?: string): SerializedFontConfig;
|
|
10
|
+
export declare function clearFontCache(): void;
|
|
11
|
+
//# sourceMappingURL=FontManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FontManager.d.ts","sourceRoot":"","sources":["../../../../src/stages/compose/font-system/FontManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAc,oBAAoB,EAAa,MAAM,SAAS,CAAC;AAqBvF,qBAAa,WAAW;IACtB,OAAO,CAAC,SAAS,CAAsC;IAEvD,aAAa,CACX,MAAM,EAAE,UAAU,EAClB,YAAY,EAAE,MAAM,EACpB,cAAc,CAAC,EAAE,MAAM,GACtB,oBAAoB;IAgBvB,OAAO,CAAC,gBAAgB;IAkCxB,UAAU,IAAI,IAAI;CAGnB;AAID,wBAAgB,aAAa,CAC3B,MAAM,EAAE,UAAU,EAClB,YAAY,EAAE,MAAM,EACpB,cAAc,CAAC,EAAE,MAAM,GACtB,oBAAoB,CAEtB;AAED,wBAAgB,cAAc,IAAI,IAAI,CAErC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { getTemplate } from "./font-templates.js";
|
|
2
|
+
const SYSTEM_FONT_FALLBACKS = {
|
|
3
|
+
"zh-CN": '-apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", sans-serif',
|
|
4
|
+
"en-US": '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif',
|
|
5
|
+
"ja-JP": '-apple-system, BlinkMacSystemFont, "Hiragino Sans", "Yu Gothic", sans-serif',
|
|
6
|
+
"ko-KR": '-apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif',
|
|
7
|
+
"ar-SA": '-apple-system, BlinkMacSystemFont, "Arabic UI Text", "Geeza Pro", sans-serif',
|
|
8
|
+
other: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif'
|
|
9
|
+
};
|
|
10
|
+
const PREFERRED_FONTS = {
|
|
11
|
+
"zh-CN": "dtjinbu",
|
|
12
|
+
"en-US": "dtjinbu",
|
|
13
|
+
"ja-JP": "dtjinbu",
|
|
14
|
+
"ko-KR": "dtjinbu",
|
|
15
|
+
"ar-SA": "dtjinbu",
|
|
16
|
+
other: "dtjinbu"
|
|
17
|
+
};
|
|
18
|
+
class FontManager {
|
|
19
|
+
fontCache = /* @__PURE__ */ new Map();
|
|
20
|
+
getFontConfig(locale, templateName, fontFamilyName) {
|
|
21
|
+
const cacheKey = `${locale}-${templateName}-${fontFamilyName || "default"}`;
|
|
22
|
+
let config = this.fontCache.get(cacheKey);
|
|
23
|
+
if (!config) {
|
|
24
|
+
config = this.createFontConfig(locale, templateName, fontFamilyName);
|
|
25
|
+
this.fontCache.set(cacheKey, config);
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
textStyle: { ...config.textStyle },
|
|
29
|
+
containerStyle: config.containerStyle ? { ...config.containerStyle } : void 0,
|
|
30
|
+
globalPosition: config.globalPosition ? { ...config.globalPosition } : void 0
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
createFontConfig(locale, templateName, fontFamilyName) {
|
|
34
|
+
const template = getTemplate(templateName);
|
|
35
|
+
const fontFamily = fontFamilyName ? `${fontFamilyName}, ${SYSTEM_FONT_FALLBACKS[locale]}` : `${PREFERRED_FONTS[locale]}, ${SYSTEM_FONT_FALLBACKS[locale]}`;
|
|
36
|
+
const textStyle = {
|
|
37
|
+
fontSize: template.textStyle?.fontSize || 40,
|
|
38
|
+
fontWeight: template.textStyle?.fontWeight || 400,
|
|
39
|
+
fontFamily: template.textStyle?.fontFamily || fontFamily,
|
|
40
|
+
fill: template.textStyle?.fill || "rgb(255, 255, 255)",
|
|
41
|
+
stroke: template.textStyle?.stroke,
|
|
42
|
+
strokeWidth: template.textStyle?.strokeWidth,
|
|
43
|
+
letterSpacing: template.textStyle?.letterSpacing || 0,
|
|
44
|
+
lineHeight: template.textStyle?.lineHeight || 1.2,
|
|
45
|
+
paintOrder: template.textStyle?.paintOrder,
|
|
46
|
+
strokeLinejoin: template.textStyle?.strokeLinejoin,
|
|
47
|
+
strokeLinecap: template.textStyle?.strokeLinecap
|
|
48
|
+
};
|
|
49
|
+
return {
|
|
50
|
+
familyName: fontFamily,
|
|
51
|
+
locales: [locale],
|
|
52
|
+
textStyle,
|
|
53
|
+
containerStyle: template.containerStyle,
|
|
54
|
+
globalPosition: template.globalPosition
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
clearCache() {
|
|
58
|
+
this.fontCache.clear();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const fontManagerInstance = new FontManager();
|
|
62
|
+
function getFontConfig(locale, templateName, fontFamilyName) {
|
|
63
|
+
return fontManagerInstance.getFontConfig(locale, templateName, fontFamilyName);
|
|
64
|
+
}
|
|
65
|
+
export {
|
|
66
|
+
FontManager,
|
|
67
|
+
getFontConfig
|
|
68
|
+
};
|
|
69
|
+
//# sourceMappingURL=FontManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FontManager.js","sources":["../../../../src/stages/compose/font-system/FontManager.ts"],"sourcesContent":["import type { LocaleCode, FontConfig, SerializedFontConfig, TextStyle } from './types';\nimport { getTemplate } from './font-templates';\n\nconst SYSTEM_FONT_FALLBACKS: Record<LocaleCode, string> = {\n 'zh-CN': '-apple-system, BlinkMacSystemFont, \"PingFang SC\", \"Microsoft YaHei\", sans-serif',\n 'en-US': '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Arial, sans-serif',\n 'ja-JP': '-apple-system, BlinkMacSystemFont, \"Hiragino Sans\", \"Yu Gothic\", sans-serif',\n 'ko-KR': '-apple-system, BlinkMacSystemFont, \"Apple SD Gothic Neo\", \"Malgun Gothic\", sans-serif',\n 'ar-SA': '-apple-system, BlinkMacSystemFont, \"Arabic UI Text\", \"Geeza Pro\", sans-serif',\n other: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Arial, sans-serif',\n};\n\nconst PREFERRED_FONTS: Record<LocaleCode, string> = {\n 'zh-CN': 'dtjinbu',\n 'en-US': 'dtjinbu',\n 'ja-JP': 'dtjinbu',\n 'ko-KR': 'dtjinbu',\n 'ar-SA': 'dtjinbu',\n other: 'dtjinbu',\n};\n\nexport class FontManager {\n private fontCache: Map<string, FontConfig> = new Map();\n\n getFontConfig(\n locale: LocaleCode,\n templateName: string,\n fontFamilyName?: string\n ): SerializedFontConfig {\n const cacheKey = `${locale}-${templateName}-${fontFamilyName || 'default'}`;\n\n let config = this.fontCache.get(cacheKey);\n if (!config) {\n config = this.createFontConfig(locale, templateName, fontFamilyName);\n this.fontCache.set(cacheKey, config);\n }\n\n return {\n textStyle: { ...config.textStyle },\n containerStyle: config.containerStyle ? { ...config.containerStyle } : undefined,\n globalPosition: config.globalPosition ? { ...config.globalPosition } : undefined,\n };\n }\n\n private createFontConfig(\n locale: LocaleCode,\n templateName: string,\n fontFamilyName?: string\n ): FontConfig {\n const template = getTemplate(templateName);\n\n const fontFamily = fontFamilyName\n ? `${fontFamilyName}, ${SYSTEM_FONT_FALLBACKS[locale]}`\n : `${PREFERRED_FONTS[locale]}, ${SYSTEM_FONT_FALLBACKS[locale]}`;\n\n const textStyle: TextStyle = {\n fontSize: template.textStyle?.fontSize || 40,\n fontWeight: template.textStyle?.fontWeight || 400,\n fontFamily: template.textStyle?.fontFamily || fontFamily,\n fill: template.textStyle?.fill || 'rgb(255, 255, 255)',\n stroke: template.textStyle?.stroke,\n strokeWidth: template.textStyle?.strokeWidth,\n letterSpacing: template.textStyle?.letterSpacing || 0,\n lineHeight: template.textStyle?.lineHeight || 1.2,\n paintOrder: template.textStyle?.paintOrder,\n strokeLinejoin: template.textStyle?.strokeLinejoin,\n strokeLinecap: template.textStyle?.strokeLinecap,\n };\n\n return {\n familyName: fontFamily,\n locales: [locale],\n textStyle,\n containerStyle: template.containerStyle,\n globalPosition: template.globalPosition,\n };\n }\n\n clearCache(): void {\n this.fontCache.clear();\n }\n}\n\nconst fontManagerInstance = new FontManager();\n\nexport function getFontConfig(\n locale: LocaleCode,\n templateName: string,\n fontFamilyName?: string\n): SerializedFontConfig {\n return fontManagerInstance.getFontConfig(locale, templateName, fontFamilyName);\n}\n\nexport function clearFontCache(): void {\n fontManagerInstance.clearCache();\n}\n"],"names":[],"mappings":";AAGA,MAAM,wBAAoD;AAAA,EACxD,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,OAAO;AACT;AAEA,MAAM,kBAA8C;AAAA,EAClD,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,OAAO;AACT;AAEO,MAAM,YAAY;AAAA,EACf,gCAAyC,IAAA;AAAA,EAEjD,cACE,QACA,cACA,gBACsB;AACtB,UAAM,WAAW,GAAG,MAAM,IAAI,YAAY,IAAI,kBAAkB,SAAS;AAEzE,QAAI,SAAS,KAAK,UAAU,IAAI,QAAQ;AACxC,QAAI,CAAC,QAAQ;AACX,eAAS,KAAK,iBAAiB,QAAQ,cAAc,cAAc;AACnE,WAAK,UAAU,IAAI,UAAU,MAAM;AAAA,IACrC;AAEA,WAAO;AAAA,MACL,WAAW,EAAE,GAAG,OAAO,UAAA;AAAA,MACvB,gBAAgB,OAAO,iBAAiB,EAAE,GAAG,OAAO,mBAAmB;AAAA,MACvE,gBAAgB,OAAO,iBAAiB,EAAE,GAAG,OAAO,mBAAmB;AAAA,IAAA;AAAA,EAE3E;AAAA,EAEQ,iBACN,QACA,cACA,gBACY;AACZ,UAAM,WAAW,YAAY,YAAY;AAEzC,UAAM,aAAa,iBACf,GAAG,cAAc,KAAK,sBAAsB,MAAM,CAAC,KACnD,GAAG,gBAAgB,MAAM,CAAC,KAAK,sBAAsB,MAAM,CAAC;AAEhE,UAAM,YAAuB;AAAA,MAC3B,UAAU,SAAS,WAAW,YAAY;AAAA,MAC1C,YAAY,SAAS,WAAW,cAAc;AAAA,MAC9C,YAAY,SAAS,WAAW,cAAc;AAAA,MAC9C,MAAM,SAAS,WAAW,QAAQ;AAAA,MAClC,QAAQ,SAAS,WAAW;AAAA,MAC5B,aAAa,SAAS,WAAW;AAAA,MACjC,eAAe,SAAS,WAAW,iBAAiB;AAAA,MACpD,YAAY,SAAS,WAAW,cAAc;AAAA,MAC9C,YAAY,SAAS,WAAW;AAAA,MAChC,gBAAgB,SAAS,WAAW;AAAA,MACpC,eAAe,SAAS,WAAW;AAAA,IAAA;AAGrC,WAAO;AAAA,MACL,YAAY;AAAA,MACZ,SAAS,CAAC,MAAM;AAAA,MAChB;AAAA,MACA,gBAAgB,SAAS;AAAA,MACzB,gBAAgB,SAAS;AAAA,IAAA;AAAA,EAE7B;AAAA,EAEA,aAAmB;AACjB,SAAK,UAAU,MAAA;AAAA,EACjB;AACF;AAEA,MAAM,sBAAsB,IAAI,YAAA;AAEzB,SAAS,cACd,QACA,cACA,gBACsB;AACtB,SAAO,oBAAoB,cAAc,QAAQ,cAAc,cAAc;AAC/E;"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { TextStyle, ContainerStyle, GlobalPositionStyle } from './types';
|
|
2
|
+
|
|
3
|
+
export interface FontTemplate {
|
|
4
|
+
name: string;
|
|
5
|
+
textStyle?: Partial<TextStyle>;
|
|
6
|
+
containerStyle?: Partial<ContainerStyle>;
|
|
7
|
+
globalPosition?: Partial<GlobalPositionStyle>;
|
|
8
|
+
}
|
|
9
|
+
export declare function mergeFontTemplates(...templates: FontTemplate[]): FontTemplate;
|
|
10
|
+
export declare const FONT_TEMPLATES: Record<string, FontTemplate>;
|
|
11
|
+
export declare function getTemplate(templateName: string): FontTemplate;
|
|
12
|
+
//# sourceMappingURL=font-templates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"font-templates.d.ts","sourceRoot":"","sources":["../../../../src/stages/compose/font-system/font-templates.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAE9E,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;IAC/B,cAAc,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;IACzC,cAAc,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,CAAC;CAC/C;AAED,wBAAgB,kBAAkB,CAAC,GAAG,SAAS,EAAE,YAAY,EAAE,GAAG,YAAY,CAgB7E;AAqVD,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CA6DvD,CAAC;AAEF,wBAAgB,WAAW,CAAC,YAAY,EAAE,MAAM,GAAG,YAAY,CA0B9D"}
|