@meframe/core 0.3.9 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Meframe.d.ts +2 -2
- package/dist/Meframe.d.ts.map +1 -1
- package/dist/Meframe.js +9 -6
- package/dist/Meframe.js.map +1 -1
- package/dist/controllers/ExportController.d.ts.map +1 -1
- package/dist/controllers/ExportController.js +2 -0
- package/dist/controllers/ExportController.js.map +1 -1
- package/dist/medeo-fe/node_modules/.pnpm/mp4-muxer@5.2.2/node_modules/mp4-muxer/build/mp4-muxer.js.map +1 -0
- package/dist/{node_modules → medeo-fe/node_modules}/.pnpm/mp4box@0.5.4/node_modules/mp4box/dist/mp4box.all.js +2 -2
- package/dist/medeo-fe/node_modules/.pnpm/mp4box@0.5.4/node_modules/mp4box/dist/mp4box.all.js.map +1 -0
- package/dist/orchestrator/ExportScheduler.d.ts.map +1 -1
- package/dist/orchestrator/ExportScheduler.js +9 -0
- package/dist/orchestrator/ExportScheduler.js.map +1 -1
- package/dist/stages/encode/BaseEncoder.d.ts.map +1 -1
- package/dist/stages/encode/BaseEncoder.js +4 -1
- package/dist/stages/encode/BaseEncoder.js.map +1 -1
- package/dist/stages/mux/MP4Muxer.js +1 -1
- package/dist/utils/mp4box.js +1 -1
- package/dist/workers/stages/export/{export.worker.DbrPlw6d.js → export.worker.DCStS1mL.js} +5 -2
- package/dist/workers/stages/export/export.worker.DCStS1mL.js.map +1 -0
- package/dist/workers/worker-manifest.json +1 -1
- package/package.json +1 -1
- package/dist/node_modules/.pnpm/mp4-muxer@5.2.2/node_modules/mp4-muxer/build/mp4-muxer.js.map +0 -1
- package/dist/node_modules/.pnpm/mp4box@0.5.4/node_modules/mp4box/dist/mp4box.all.js.map +0 -1
- package/dist/workers/stages/export/export.worker.DbrPlw6d.js.map +0 -1
- /package/dist/{node_modules → medeo-fe/node_modules}/.pnpm/mp4-muxer@5.2.2/node_modules/mp4-muxer/build/mp4-muxer.js +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExportScheduler.d.ts","sourceRoot":"","sources":["../../src/orchestrator/ExportScheduler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAQ,MAAM,UAAU,CAAC;AAClD,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;AAExE,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAgB,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAKhE,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;IAC9B,UAAU,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC/B,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACzD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAKD,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,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"ExportScheduler.d.ts","sourceRoot":"","sources":["../../src/orchestrator/ExportScheduler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAQ,MAAM,UAAU,CAAC;AAClD,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;AAExE,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAgB,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAKhE,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;IAC9B,UAAU,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC/B,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACzD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAKD,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,GAAG,IAAI,CAAC;YAe9E,eAAe;YA8If,gBAAgB;YAyDhB,qBAAqB;IAwBnC;;;OAGG;YACW,oBAAoB;YAyIpB,wBAAwB;YAuDxB,gBAAgB;IA8B9B,OAAO,CAAC,qBAAqB;YAKf,0BAA0B;IA2BxC,OAAO,CAAC,+BAA+B;YAazB,mBAAmB;CA0ClC"}
|
|
@@ -12,6 +12,7 @@ class ExportScheduler {
|
|
|
12
12
|
async execute(model, options) {
|
|
13
13
|
this.deps.cacheManager.clear();
|
|
14
14
|
const projectId = this.deps.cacheManager.resourceCache.projectId;
|
|
15
|
+
console.info("[ExportScheduler] Export is starting, projectId:", projectId);
|
|
15
16
|
if (!navigator.locks) {
|
|
16
17
|
return this.executeInternal(model, options);
|
|
17
18
|
}
|
|
@@ -23,6 +24,7 @@ class ExportScheduler {
|
|
|
23
24
|
const signal = options.signal;
|
|
24
25
|
const controller = options.controller;
|
|
25
26
|
const exportMode = options.exportMode ?? "blob";
|
|
27
|
+
console.info("[ExportScheduler] Export is starting, exportMode:", exportMode);
|
|
26
28
|
if (exportMode === "stream" && typeof options.onMuxData !== "function") {
|
|
27
29
|
throw new Error("onMuxData callback is required when exportMode is stream");
|
|
28
30
|
}
|
|
@@ -50,6 +52,7 @@ class ExportScheduler {
|
|
|
50
52
|
});
|
|
51
53
|
this.deps.cacheManager.beginExport();
|
|
52
54
|
try {
|
|
55
|
+
console.info("[ExportScheduler] Export is preloading resources");
|
|
53
56
|
await this.preloadResources(model, resourceLoader, eventBus, checkStatus);
|
|
54
57
|
const hasAudioSamples = this.deps.cacheManager.audioSampleCache.getTotalBytes() > 0;
|
|
55
58
|
const { enableAudio, disabledReason } = await this.decideAudioStrategy({
|
|
@@ -64,6 +67,7 @@ class ExportScheduler {
|
|
|
64
67
|
message: disabledReason
|
|
65
68
|
});
|
|
66
69
|
}
|
|
70
|
+
console.info("[ExportScheduler] Export is starting muxer");
|
|
67
71
|
muxManager.start({
|
|
68
72
|
width,
|
|
69
73
|
height,
|
|
@@ -79,6 +83,7 @@ class ExportScheduler {
|
|
|
79
83
|
chunked: options.muxChunked
|
|
80
84
|
} : { kind: "blob" }
|
|
81
85
|
});
|
|
86
|
+
console.info("[ExportScheduler] Export is processing video and audio");
|
|
82
87
|
const mainTrack = model.tracks.find((t) => t.id === model.mainTrackId);
|
|
83
88
|
if (mainTrack && mainTrack.clips.length > 0) {
|
|
84
89
|
const audioPromise = enableAudio ? this.processAudioInWindows(model.durationUs, audioSession, muxManager, checkStatus) : Promise.resolve();
|
|
@@ -99,6 +104,7 @@ class ExportScheduler {
|
|
|
99
104
|
if (signal?.aborted) {
|
|
100
105
|
throw new DOMException("Export aborted", "AbortError");
|
|
101
106
|
}
|
|
107
|
+
console.info("[ExportScheduler] Export is finalizing");
|
|
102
108
|
const blob = await muxManager.finalize();
|
|
103
109
|
eventBus.emit(MeframeEvent.ExportComplete, {
|
|
104
110
|
size: blob?.size ?? streamedBytes,
|
|
@@ -109,14 +115,17 @@ class ExportScheduler {
|
|
|
109
115
|
progress: 1,
|
|
110
116
|
stage: "muxing"
|
|
111
117
|
});
|
|
118
|
+
console.info("[ExportScheduler] Export is completed successfully");
|
|
112
119
|
return blob;
|
|
113
120
|
} catch (error) {
|
|
121
|
+
console.error("[ExportScheduler] Export error:", error);
|
|
114
122
|
eventBus.emit(MeframeEvent.ExportError, {
|
|
115
123
|
error: error instanceof Error ? error : new Error(String(error)),
|
|
116
124
|
stage: "export"
|
|
117
125
|
});
|
|
118
126
|
throw error;
|
|
119
127
|
} finally {
|
|
128
|
+
console.info("[ExportScheduler] Export is completed");
|
|
120
129
|
this.deps.cacheManager.endExport();
|
|
121
130
|
}
|
|
122
131
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExportScheduler.js","sources":["../../src/orchestrator/ExportScheduler.ts"],"sourcesContent":["import { CompositionModel, Clip } from '../model';\nimport { ExportOptions } from '../types';\nimport { WorkerPool } from '../worker/WorkerPool';\nimport { CompositionPlanner } from './CompositionPlanner';\nimport { CacheManager } from '../cache/CacheManager';\nimport { ResourceLoader } from '../stages/load/ResourceLoader';\nimport { MuxManager } from '../stages/mux/MuxManager';\nimport { AudioExportSession } from './AudioExportSession';\nimport { VideoWindowDecodeSession } from './VideoWindowDecodeSession';\nimport { WorkerType } from '../worker/types';\nimport { hasResourceId, type TimeUs, type Resource } from '../model/types';\nimport type { ExportController } from '../controllers/ExportController';\nimport type { BaseWorker } from '../worker/BaseWorker';\nimport { EventBus } from '../event/EventBus';\nimport { MeframeEvent, EventPayloadMap } from '../event/events';\nimport { AudioChunkEncoder } from '../stages/encode/AudioChunkEncoder';\nimport type { ClipInstructionSet } from '../stages/compose/instructions';\nimport { computeGOPAlignedWindows, computeFixedWindows } from '../utils/time-utils';\n\ninterface ExportSchedulerDeps {\n workerPool: WorkerPool;\n planner: CompositionPlanner;\n cacheManager: CacheManager;\n resourceLoader: ResourceLoader;\n muxManager: MuxManager;\n audioSession: AudioExportSession;\n workerConfigsProvider: () => Record<WorkerType, any>;\n eventBus: EventBus<EventPayloadMap>;\n}\n\ninterface ExtendedExportOptions extends ExportOptions {\n signal?: AbortSignal;\n controller?: ExportController;\n exportMode?: 'blob' | 'stream';\n onMuxData?: (data: Uint8Array, position: number) => void;\n muxChunkSizeBytes?: number;\n muxChunked?: boolean;\n}\n\n// 5 seconds per window, ~150 frames at 30fps\nconst VIDEO_WINDOW_DURATION_US: TimeUs = 5_000_000;\n\nexport class ExportScheduler {\n private deps: ExportSchedulerDeps;\n\n constructor(deps: ExportSchedulerDeps) {\n this.deps = deps;\n }\n\n async execute(model: CompositionModel, options: ExtendedExportOptions): Promise<Blob | null> {\n this.deps.cacheManager.clear();\n\n const projectId = this.deps.cacheManager.resourceCache.projectId;\n\n if (!navigator.locks) {\n return this.executeInternal(model, options);\n }\n\n const lockName = `meframe-resource-${projectId}`;\n return navigator.locks.request(lockName, () => this.executeInternal(model, options));\n }\n\n private async executeInternal(\n model: CompositionModel,\n options: ExtendedExportOptions\n ): Promise<Blob | null> {\n const { muxManager, audioSession, eventBus, resourceLoader } = this.deps;\n const signal = options.signal;\n const controller = options.controller;\n const exportMode = options.exportMode ?? 'blob';\n\n if (exportMode === 'stream' && typeof options.onMuxData !== 'function') {\n throw new Error('onMuxData callback is required when exportMode is stream');\n }\n\n let streamedBytes = 0;\n\n const checkStatus = async () => {\n if (signal?.aborted) {\n throw new DOMException('Export aborted', 'AbortError');\n }\n if (controller?.isPaused()) {\n while (controller.isPaused()) {\n if (signal?.aborted) throw new DOMException('Export aborted', 'AbortError');\n await new Promise((resolve) => setTimeout(resolve, 100));\n }\n }\n };\n\n const width = options.width || model.renderConfig?.width || 720;\n const height = options.height || model.renderConfig?.height || 1280;\n const fps = options.fps || model.fps || 30;\n\n eventBus.emit(MeframeEvent.ExportStart, {\n format: options.format || 'mp4',\n width,\n height,\n fps,\n durationUs: model.durationUs,\n });\n\n this.deps.cacheManager.beginExport();\n\n try {\n // 1. Preload and parse all resources (0-40%)\n await this.preloadResources(model, resourceLoader, eventBus, checkStatus);\n\n const hasAudioSamples = this.deps.cacheManager.audioSampleCache.getTotalBytes() > 0;\n const { enableAudio, disabledReason } = await this.decideAudioStrategy({\n hasAudioSamples,\n requestedFormat: options.format ?? 'mp4',\n requestedAudioCodec: options.audioCodec ?? 'aac',\n });\n if (disabledReason) {\n eventBus.emit(MeframeEvent.ExportProgress, {\n progress: 0.4,\n stage: 'encoding',\n message: disabledReason,\n });\n }\n\n // 2. Start Muxer\n muxManager.start({\n width,\n height,\n fps,\n enableAudio,\n output:\n exportMode === 'stream'\n ? {\n kind: 'stream',\n onData: (data, position) => {\n streamedBytes = Math.max(streamedBytes, position + data.byteLength);\n options.onMuxData?.(data, position);\n },\n chunkSize: options.muxChunkSizeBytes,\n chunked: options.muxChunked,\n }\n : { kind: 'blob' },\n });\n\n // 3. Process Video and Audio\n const mainTrack = model.tracks.find((t) => t.id === model.mainTrackId);\n if (mainTrack && mainTrack.clips.length > 0) {\n const audioPromise = enableAudio\n ? this.processAudioInWindows(model.durationUs, audioSession, muxManager, checkStatus)\n : Promise.resolve();\n\n await this.processVideoWindowed(mainTrack.clips, muxManager, model, checkStatus);\n\n try {\n await audioPromise;\n } catch (error) {\n eventBus.emit(MeframeEvent.ExportProgress, {\n progress: 0.95,\n stage: 'encoding',\n message: `Audio skipped (runtime failure): ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n } else {\n console.warn('[ExportScheduler] No video clips found');\n }\n\n await audioSession.finalizeExportAudio();\n\n if (signal?.aborted) {\n throw new DOMException('Export aborted', 'AbortError');\n }\n\n // 4. Finalize\n const blob = await muxManager.finalize();\n\n eventBus.emit(MeframeEvent.ExportComplete, {\n size: blob?.size ?? streamedBytes,\n durationMs: model.durationUs / 1000,\n format: options.format || 'mp4',\n });\n\n eventBus.emit(MeframeEvent.ExportProgress, {\n progress: 1,\n stage: 'muxing',\n });\n\n return blob;\n } catch (error) {\n eventBus.emit(MeframeEvent.ExportError, {\n error: error instanceof Error ? error : new Error(String(error)),\n stage: 'export',\n });\n throw error;\n } finally {\n this.deps.cacheManager.endExport();\n }\n }\n\n private async preloadResources(\n model: CompositionModel,\n resourceLoader: ResourceLoader,\n eventBus: EventBus<EventPayloadMap>,\n checkStatus: () => Promise<void>\n ): Promise<void> {\n eventBus.emit(MeframeEvent.ExportProgress, {\n progress: 0,\n stage: 'preparing',\n message: 'Loading and parsing resources...',\n });\n\n const tracks = model.tracks.filter((track) => ['video', 'audio'].includes(track.kind));\n if (tracks.length === 0) return;\n\n const maxClipCount = Math.max(...tracks.map((track) => track.clips.length));\n const resourcesToLoad: string[] = [];\n const seen = new Set<string>();\n\n for (let clipIndex = 0; clipIndex < maxClipCount; clipIndex++) {\n for (const track of tracks) {\n const clip = track.clips[clipIndex];\n if (clip && hasResourceId(clip)) {\n if (!seen.has(clip.resourceId)) {\n seen.add(clip.resourceId);\n resourcesToLoad.push(clip.resourceId);\n }\n }\n }\n }\n\n const total = resourcesToLoad.length;\n let completed = 0;\n\n await Promise.all(\n resourcesToLoad.map(async (resourceId) => {\n await checkStatus();\n await resourceLoader.load(resourceId, { isPreload: false });\n\n const resource = model.getResource(resourceId);\n if (resource?.state === 'error') {\n const details = resource.error?.message ?? 'Unknown resource error';\n throw new Error(`Export preload failed for ${resourceId}: ${details}`);\n }\n\n completed++;\n\n const progress = total > 0 ? (completed / total) * 0.4 : 0.4;\n eventBus.emit(MeframeEvent.ExportProgress, {\n progress,\n stage: 'preparing',\n message: `Loading resources... (${completed}/${total})`,\n });\n })\n );\n }\n\n private async processAudioInWindows(\n totalDurationUs: TimeUs,\n audioSession: AudioExportSession,\n muxManager: MuxManager,\n checkStatus: () => Promise<void>\n ): Promise<void> {\n const WINDOW_DURATION_US = 5 * 60 * 1_000_000;\n let currentUs = 0;\n\n while (currentUs < totalDurationUs) {\n await checkStatus();\n\n const endUs = Math.min(currentUs + WINDOW_DURATION_US, totalDurationUs);\n\n await audioSession.mixAndEncodeSegment(currentUs, endUs, (chunk, meta) =>\n muxManager.writeAudioChunk(chunk, meta)\n );\n\n this.deps.cacheManager.clearAudioCache();\n\n currentUs = endUs;\n }\n }\n\n /**\n * Windowed video processing: one ExportWorker for all clips and windows.\n * Memory bounded by window size (~150 frames).\n */\n private async processVideoWindowed(\n clips: Clip[],\n muxManager: MuxManager,\n model: CompositionModel,\n checkStatus: () => Promise<void>\n ) {\n const { workerPool, planner, cacheManager, resourceLoader } = this.deps;\n const workerConfigs = this.deps.workerConfigsProvider();\n\n // --- One-time setup: create and configure ExportWorker ---\n const exportWorker = await workerPool.getOrCreate('videoExport', 'export', { lazy: true });\n const exportConfig = workerConfigs.videoExport ?? {};\n\n // Apply render overrides from model\n const composeConfig = { ...(exportConfig.compose ?? {}) };\n const encodeConfig = { ...(exportConfig.encode ?? {}) };\n if (model.renderConfig?.width) {\n composeConfig.width = model.renderConfig.width;\n encodeConfig.width = model.renderConfig.width;\n }\n if (model.renderConfig?.height) {\n composeConfig.height = model.renderConfig.height;\n encodeConfig.height = model.renderConfig.height;\n }\n\n await exportWorker.send('configure', { compose: composeConfig, encode: encodeConfig });\n\n // --- Stream receiver: called once per window's encoded output ---\n let windowResolver!: () => void;\n let windowRejecter!: (err: any) => void;\n let nextClipStartUs = 0;\n let lastChunkEndUs = 0;\n\n exportWorker.receiveStream(async (stream, _metadata) => {\n const reader = stream.getReader();\n try {\n while (true) {\n await checkStatus();\n\n const { done, value } = await reader.read();\n if (done) break;\n if (!value) continue;\n\n const { chunk: originalChunk, metadata } = value as {\n chunk: EncodedVideoChunk;\n metadata: EncodedVideoChunkMetadata;\n };\n const chunkDuration = originalChunk.duration ?? 33333;\n\n // Chunks arrive with clip-relative timestamps; remap to global timeline\n const remappedTimestamp = originalChunk.timestamp + nextClipStartUs;\n\n const buffer = new ArrayBuffer(originalChunk.byteLength);\n originalChunk.copyTo(buffer);\n\n const remappedChunk = new EncodedVideoChunk({\n type: originalChunk.type,\n timestamp: remappedTimestamp,\n duration: chunkDuration,\n data: buffer,\n });\n\n muxManager.writeVideoChunk(remappedChunk, metadata);\n\n lastChunkEndUs = remappedTimestamp + chunkDuration;\n\n const encodingProgress = remappedTimestamp / model.durationUs;\n const totalProgress = 0.4 + encodingProgress * 0.6;\n\n this.deps.eventBus.emit(MeframeEvent.ExportProgress, {\n progress: Math.min(1.0, totalProgress),\n stage: 'encoding',\n timeUs: remappedTimestamp,\n });\n }\n windowResolver();\n } catch (error) {\n windowRejecter(error);\n } finally {\n reader.releaseLock();\n }\n });\n\n // --- Per-clip + per-window processing ---\n try {\n for (const clip of clips) {\n await checkStatus();\n\n const resource = hasResourceId(clip) ? model.getResource(clip.resourceId) : null;\n if (!resource) {\n console.warn('[ExportScheduler] Resource not found for clip:', clip.id);\n continue;\n }\n\n const instructions = this.buildClipInstructions(clip, planner);\n\n const createWindowPromise = () =>\n new Promise<void>((resolve, reject) => {\n windowResolver = resolve;\n windowRejecter = reject;\n });\n\n if (resource.type === 'image') {\n await this.processImageClip(\n exportWorker,\n clip,\n resource,\n instructions,\n model,\n resourceLoader,\n createWindowPromise\n );\n } else {\n await this.processVideoClipWindowed(\n exportWorker,\n clip,\n resource,\n instructions,\n model,\n cacheManager,\n resourceLoader,\n checkStatus,\n createWindowPromise\n );\n }\n\n await exportWorker.send('dispose_clip');\n nextClipStartUs = lastChunkEndUs;\n }\n\n // Flush encoder to drain remaining frames\n await exportWorker.send('flush');\n } finally {\n workerPool.terminate('videoExport', 'export');\n }\n }\n\n private async processVideoClipWindowed(\n exportWorker: BaseWorker,\n clip: Clip,\n resource: Resource,\n instructions: ClipInstructionSet,\n model: CompositionModel,\n cacheManager: CacheManager,\n resourceLoader: ResourceLoader,\n checkStatus: () => Promise<void>,\n createWindowPromise: () => Promise<void>\n ) {\n await exportWorker.send('install_instructions', instructions);\n await this.loadAndTransferAttachments(exportWorker, clip, instructions, model, resourceLoader);\n\n const trimStartUs = clip.trimStartUs ?? 0;\n const trimEndUs = trimStartUs + clip.durationUs;\n const fps = model.fps ?? 30;\n\n const index = cacheManager.mp4IndexCache.get(resource.id);\n const gopIndex = index?.tracks?.video?.gopIndex;\n const windows =\n gopIndex && gopIndex.length > 0\n ? computeGOPAlignedWindows(gopIndex, trimStartUs, trimEndUs, VIDEO_WINDOW_DURATION_US)\n : computeFixedWindows(trimStartUs, trimEndUs, VIDEO_WINDOW_DURATION_US);\n\n for (const { startUs, endUs } of windows) {\n await checkStatus();\n\n const windowDone = createWindowPromise();\n\n const decodeSession = await VideoWindowDecodeSession.create({\n clipId: clip.id,\n resourceId: resource.id,\n targetTimeUs: trimStartUs,\n globalTimeUs: clip.startUs,\n mp4IndexCache: cacheManager.mp4IndexCache,\n cacheManager,\n compositionModel: model,\n resourceLoader,\n fps,\n });\n\n const frameStream = await decodeSession.decodeRangeToStream(startUs, endUs);\n\n await exportWorker.sendStream(frameStream, {\n streamType: 'video',\n windowStartUs: startUs,\n windowEndUs: endUs,\n });\n\n await windowDone;\n await decodeSession.dispose();\n }\n }\n\n private async processImageClip(\n exportWorker: BaseWorker,\n clip: Clip,\n resource: Resource,\n instructions: ClipInstructionSet,\n model: CompositionModel,\n resourceLoader: ResourceLoader,\n createWindowPromise: () => Promise<void>\n ) {\n await this.loadAndTransferAttachments(exportWorker, clip, instructions, model, resourceLoader);\n\n const clipDone = createWindowPromise();\n\n const imageBitmap = await resourceLoader.loadImage(resource);\n await exportWorker.send(\n 'receive_image',\n {\n resourceId: resource.id,\n sessionId: clip.id,\n imageBitmap,\n instructions,\n },\n { transfer: [imageBitmap] }\n );\n\n // ExportWorker's startImageFrameStream sends encoded stream back;\n // the receiveStream handler resolves clipDone when stream ends\n await clipDone;\n }\n\n private buildClipInstructions(clip: Clip, planner: CompositionPlanner): ClipInstructionSet {\n const plan = planner.buildClipPlan(clip, { cache: false });\n return plan.instructions;\n }\n\n private async loadAndTransferAttachments(\n exportWorker: BaseWorker,\n clip: Clip,\n instructions: ClipInstructionSet,\n model: CompositionModel,\n resourceLoader: ResourceLoader\n ): Promise<void> {\n const attachmentResources = this.extractAttachmentImageResources(instructions);\n if (attachmentResources.length === 0) return;\n\n await Promise.all(\n attachmentResources.map(async (resourceId) => {\n const resource = model.getResource(resourceId);\n if (!resource) return;\n\n const imageBitmap = await resourceLoader.loadImage(resource);\n if (!imageBitmap) return;\n\n await exportWorker.send(\n 'receive_image',\n { clipId: clip.id, resourceId, sessionId: clip.id, imageBitmap },\n { transfer: [imageBitmap] }\n );\n })\n );\n }\n\n private extractAttachmentImageResources(instructions: ClipInstructionSet): string[] {\n const resourceIds = new Set<string>();\n for (const layer of instructions.layers) {\n if (!layer.payload.attachmentId) continue;\n if (layer.type === 'image') {\n const payload = layer.payload;\n if (payload.oldResourceId) resourceIds.add(payload.oldResourceId);\n if (payload.resourceId) resourceIds.add(payload.resourceId);\n }\n }\n return Array.from(resourceIds);\n }\n\n private async decideAudioStrategy(input: {\n hasAudioSamples: boolean;\n requestedFormat: NonNullable<ExportOptions['format']>;\n requestedAudioCodec: NonNullable<ExportOptions['audioCodec']>;\n }): Promise<{ enableAudio: boolean; disabledReason?: string }> {\n if (!input.hasAudioSamples) {\n return { enableAudio: false };\n }\n\n if (input.requestedFormat !== 'mp4') {\n return {\n enableAudio: false,\n disabledReason: `Audio skipped: format ${input.requestedFormat} is not supported.`,\n };\n }\n\n if (input.requestedAudioCodec !== 'aac') {\n return {\n enableAudio: false,\n disabledReason: `Audio skipped: mp4 output currently supports only AAC (requested ${input.requestedAudioCodec}).`,\n };\n }\n\n if (typeof AudioEncoder === 'undefined') {\n return {\n enableAudio: false,\n disabledReason:\n 'Audio skipped: WebCodecs AudioEncoder is not available in this browser/runtime (AAC required for mp4).',\n };\n }\n\n const support = await AudioEncoder.isConfigSupported(AudioChunkEncoder.DEFAULT_CONFIG);\n if (!support.supported) {\n return {\n enableAudio: false,\n disabledReason:\n 'Audio skipped: WebCodecs AAC (mp4a.40.2) AudioEncoder is not supported in this browser/runtime.',\n };\n }\n\n return { enableAudio: true };\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ExportScheduler.js","sources":["../../src/orchestrator/ExportScheduler.ts"],"sourcesContent":["import { CompositionModel, Clip } from '../model';\nimport { ExportOptions } from '../types';\nimport { WorkerPool } from '../worker/WorkerPool';\nimport { CompositionPlanner } from './CompositionPlanner';\nimport { CacheManager } from '../cache/CacheManager';\nimport { ResourceLoader } from '../stages/load/ResourceLoader';\nimport { MuxManager } from '../stages/mux/MuxManager';\nimport { AudioExportSession } from './AudioExportSession';\nimport { VideoWindowDecodeSession } from './VideoWindowDecodeSession';\nimport { WorkerType } from '../worker/types';\nimport { hasResourceId, type TimeUs, type Resource } from '../model/types';\nimport type { ExportController } from '../controllers/ExportController';\nimport type { BaseWorker } from '../worker/BaseWorker';\nimport { EventBus } from '../event/EventBus';\nimport { MeframeEvent, EventPayloadMap } from '../event/events';\nimport { AudioChunkEncoder } from '../stages/encode/AudioChunkEncoder';\nimport type { ClipInstructionSet } from '../stages/compose/instructions';\nimport { computeGOPAlignedWindows, computeFixedWindows } from '../utils/time-utils';\n\ninterface ExportSchedulerDeps {\n workerPool: WorkerPool;\n planner: CompositionPlanner;\n cacheManager: CacheManager;\n resourceLoader: ResourceLoader;\n muxManager: MuxManager;\n audioSession: AudioExportSession;\n workerConfigsProvider: () => Record<WorkerType, any>;\n eventBus: EventBus<EventPayloadMap>;\n}\n\ninterface ExtendedExportOptions extends ExportOptions {\n signal?: AbortSignal;\n controller?: ExportController;\n exportMode?: 'blob' | 'stream';\n onMuxData?: (data: Uint8Array, position: number) => void;\n muxChunkSizeBytes?: number;\n muxChunked?: boolean;\n}\n\n// 5 seconds per window, ~150 frames at 30fps\nconst VIDEO_WINDOW_DURATION_US: TimeUs = 5_000_000;\n\nexport class ExportScheduler {\n private deps: ExportSchedulerDeps;\n\n constructor(deps: ExportSchedulerDeps) {\n this.deps = deps;\n }\n\n async execute(model: CompositionModel, options: ExtendedExportOptions): Promise<Blob | null> {\n this.deps.cacheManager.clear();\n\n const projectId = this.deps.cacheManager.resourceCache.projectId;\n\n console.info('[ExportScheduler] Export is starting, projectId:', projectId);\n\n if (!navigator.locks) {\n return this.executeInternal(model, options);\n }\n\n const lockName = `meframe-resource-${projectId}`;\n return navigator.locks.request(lockName, () => this.executeInternal(model, options));\n }\n\n private async executeInternal(\n model: CompositionModel,\n options: ExtendedExportOptions\n ): Promise<Blob | null> {\n const { muxManager, audioSession, eventBus, resourceLoader } = this.deps;\n const signal = options.signal;\n const controller = options.controller;\n const exportMode = options.exportMode ?? 'blob';\n\n console.info('[ExportScheduler] Export is starting, exportMode:', exportMode);\n\n if (exportMode === 'stream' && typeof options.onMuxData !== 'function') {\n throw new Error('onMuxData callback is required when exportMode is stream');\n }\n\n let streamedBytes = 0;\n\n const checkStatus = async () => {\n if (signal?.aborted) {\n throw new DOMException('Export aborted', 'AbortError');\n }\n if (controller?.isPaused()) {\n while (controller.isPaused()) {\n if (signal?.aborted) throw new DOMException('Export aborted', 'AbortError');\n await new Promise((resolve) => setTimeout(resolve, 100));\n }\n }\n };\n\n const width = options.width || model.renderConfig?.width || 720;\n const height = options.height || model.renderConfig?.height || 1280;\n const fps = options.fps || model.fps || 30;\n\n eventBus.emit(MeframeEvent.ExportStart, {\n format: options.format || 'mp4',\n width,\n height,\n fps,\n durationUs: model.durationUs,\n });\n\n this.deps.cacheManager.beginExport();\n\n try {\n // 1. Preload and parse all resources (0-40%)\n console.info('[ExportScheduler] Export is preloading resources');\n await this.preloadResources(model, resourceLoader, eventBus, checkStatus);\n\n const hasAudioSamples = this.deps.cacheManager.audioSampleCache.getTotalBytes() > 0;\n const { enableAudio, disabledReason } = await this.decideAudioStrategy({\n hasAudioSamples,\n requestedFormat: options.format ?? 'mp4',\n requestedAudioCodec: options.audioCodec ?? 'aac',\n });\n if (disabledReason) {\n eventBus.emit(MeframeEvent.ExportProgress, {\n progress: 0.4,\n stage: 'encoding',\n message: disabledReason,\n });\n }\n\n // 2. Start Muxer\n console.info('[ExportScheduler] Export is starting muxer');\n muxManager.start({\n width,\n height,\n fps,\n enableAudio,\n output:\n exportMode === 'stream'\n ? {\n kind: 'stream',\n onData: (data, position) => {\n streamedBytes = Math.max(streamedBytes, position + data.byteLength);\n options.onMuxData?.(data, position);\n },\n chunkSize: options.muxChunkSizeBytes,\n chunked: options.muxChunked,\n }\n : { kind: 'blob' },\n });\n\n // 3. Process Video and Audio\n console.info('[ExportScheduler] Export is processing video and audio');\n const mainTrack = model.tracks.find((t) => t.id === model.mainTrackId);\n if (mainTrack && mainTrack.clips.length > 0) {\n const audioPromise = enableAudio\n ? this.processAudioInWindows(model.durationUs, audioSession, muxManager, checkStatus)\n : Promise.resolve();\n\n await this.processVideoWindowed(mainTrack.clips, muxManager, model, checkStatus);\n\n try {\n await audioPromise;\n } catch (error) {\n eventBus.emit(MeframeEvent.ExportProgress, {\n progress: 0.95,\n stage: 'encoding',\n message: `Audio skipped (runtime failure): ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n } else {\n console.warn('[ExportScheduler] No video clips found');\n }\n\n await audioSession.finalizeExportAudio();\n\n if (signal?.aborted) {\n throw new DOMException('Export aborted', 'AbortError');\n }\n\n // 4. Finalize\n console.info('[ExportScheduler] Export is finalizing');\n const blob = await muxManager.finalize();\n\n eventBus.emit(MeframeEvent.ExportComplete, {\n size: blob?.size ?? streamedBytes,\n durationMs: model.durationUs / 1000,\n format: options.format || 'mp4',\n });\n\n eventBus.emit(MeframeEvent.ExportProgress, {\n progress: 1,\n stage: 'muxing',\n });\n\n console.info('[ExportScheduler] Export is completed successfully');\n return blob;\n } catch (error) {\n console.error('[ExportScheduler] Export error:', error);\n eventBus.emit(MeframeEvent.ExportError, {\n error: error instanceof Error ? error : new Error(String(error)),\n stage: 'export',\n });\n throw error;\n } finally {\n console.info('[ExportScheduler] Export is completed');\n this.deps.cacheManager.endExport();\n }\n }\n\n private async preloadResources(\n model: CompositionModel,\n resourceLoader: ResourceLoader,\n eventBus: EventBus<EventPayloadMap>,\n checkStatus: () => Promise<void>\n ): Promise<void> {\n eventBus.emit(MeframeEvent.ExportProgress, {\n progress: 0,\n stage: 'preparing',\n message: 'Loading and parsing resources...',\n });\n\n const tracks = model.tracks.filter((track) => ['video', 'audio'].includes(track.kind));\n if (tracks.length === 0) return;\n\n const maxClipCount = Math.max(...tracks.map((track) => track.clips.length));\n const resourcesToLoad: string[] = [];\n const seen = new Set<string>();\n\n for (let clipIndex = 0; clipIndex < maxClipCount; clipIndex++) {\n for (const track of tracks) {\n const clip = track.clips[clipIndex];\n if (clip && hasResourceId(clip)) {\n if (!seen.has(clip.resourceId)) {\n seen.add(clip.resourceId);\n resourcesToLoad.push(clip.resourceId);\n }\n }\n }\n }\n\n const total = resourcesToLoad.length;\n let completed = 0;\n\n await Promise.all(\n resourcesToLoad.map(async (resourceId) => {\n await checkStatus();\n await resourceLoader.load(resourceId, { isPreload: false });\n\n const resource = model.getResource(resourceId);\n if (resource?.state === 'error') {\n const details = resource.error?.message ?? 'Unknown resource error';\n throw new Error(`Export preload failed for ${resourceId}: ${details}`);\n }\n\n completed++;\n\n const progress = total > 0 ? (completed / total) * 0.4 : 0.4;\n eventBus.emit(MeframeEvent.ExportProgress, {\n progress,\n stage: 'preparing',\n message: `Loading resources... (${completed}/${total})`,\n });\n })\n );\n }\n\n private async processAudioInWindows(\n totalDurationUs: TimeUs,\n audioSession: AudioExportSession,\n muxManager: MuxManager,\n checkStatus: () => Promise<void>\n ): Promise<void> {\n const WINDOW_DURATION_US = 5 * 60 * 1_000_000;\n let currentUs = 0;\n\n while (currentUs < totalDurationUs) {\n await checkStatus();\n\n const endUs = Math.min(currentUs + WINDOW_DURATION_US, totalDurationUs);\n\n await audioSession.mixAndEncodeSegment(currentUs, endUs, (chunk, meta) =>\n muxManager.writeAudioChunk(chunk, meta)\n );\n\n this.deps.cacheManager.clearAudioCache();\n\n currentUs = endUs;\n }\n }\n\n /**\n * Windowed video processing: one ExportWorker for all clips and windows.\n * Memory bounded by window size (~150 frames).\n */\n private async processVideoWindowed(\n clips: Clip[],\n muxManager: MuxManager,\n model: CompositionModel,\n checkStatus: () => Promise<void>\n ) {\n const { workerPool, planner, cacheManager, resourceLoader } = this.deps;\n const workerConfigs = this.deps.workerConfigsProvider();\n\n // --- One-time setup: create and configure ExportWorker ---\n const exportWorker = await workerPool.getOrCreate('videoExport', 'export', { lazy: true });\n const exportConfig = workerConfigs.videoExport ?? {};\n\n // Apply render overrides from model\n const composeConfig = { ...(exportConfig.compose ?? {}) };\n const encodeConfig = { ...(exportConfig.encode ?? {}) };\n if (model.renderConfig?.width) {\n composeConfig.width = model.renderConfig.width;\n encodeConfig.width = model.renderConfig.width;\n }\n if (model.renderConfig?.height) {\n composeConfig.height = model.renderConfig.height;\n encodeConfig.height = model.renderConfig.height;\n }\n\n await exportWorker.send('configure', { compose: composeConfig, encode: encodeConfig });\n\n // --- Stream receiver: called once per window's encoded output ---\n let windowResolver!: () => void;\n let windowRejecter!: (err: any) => void;\n let nextClipStartUs = 0;\n let lastChunkEndUs = 0;\n\n exportWorker.receiveStream(async (stream, _metadata) => {\n const reader = stream.getReader();\n try {\n while (true) {\n await checkStatus();\n\n const { done, value } = await reader.read();\n if (done) break;\n if (!value) continue;\n\n const { chunk: originalChunk, metadata } = value as {\n chunk: EncodedVideoChunk;\n metadata: EncodedVideoChunkMetadata;\n };\n const chunkDuration = originalChunk.duration ?? 33333;\n\n // Chunks arrive with clip-relative timestamps; remap to global timeline\n const remappedTimestamp = originalChunk.timestamp + nextClipStartUs;\n\n const buffer = new ArrayBuffer(originalChunk.byteLength);\n originalChunk.copyTo(buffer);\n\n const remappedChunk = new EncodedVideoChunk({\n type: originalChunk.type,\n timestamp: remappedTimestamp,\n duration: chunkDuration,\n data: buffer,\n });\n\n muxManager.writeVideoChunk(remappedChunk, metadata);\n\n lastChunkEndUs = remappedTimestamp + chunkDuration;\n\n const encodingProgress = remappedTimestamp / model.durationUs;\n const totalProgress = 0.4 + encodingProgress * 0.6;\n\n this.deps.eventBus.emit(MeframeEvent.ExportProgress, {\n progress: Math.min(1.0, totalProgress),\n stage: 'encoding',\n timeUs: remappedTimestamp,\n });\n }\n windowResolver();\n } catch (error) {\n windowRejecter(error);\n } finally {\n reader.releaseLock();\n }\n });\n\n // --- Per-clip + per-window processing ---\n try {\n for (const clip of clips) {\n await checkStatus();\n\n const resource = hasResourceId(clip) ? model.getResource(clip.resourceId) : null;\n if (!resource) {\n console.warn('[ExportScheduler] Resource not found for clip:', clip.id);\n continue;\n }\n\n const instructions = this.buildClipInstructions(clip, planner);\n\n const createWindowPromise = () =>\n new Promise<void>((resolve, reject) => {\n windowResolver = resolve;\n windowRejecter = reject;\n });\n\n if (resource.type === 'image') {\n await this.processImageClip(\n exportWorker,\n clip,\n resource,\n instructions,\n model,\n resourceLoader,\n createWindowPromise\n );\n } else {\n await this.processVideoClipWindowed(\n exportWorker,\n clip,\n resource,\n instructions,\n model,\n cacheManager,\n resourceLoader,\n checkStatus,\n createWindowPromise\n );\n }\n\n await exportWorker.send('dispose_clip');\n nextClipStartUs = lastChunkEndUs;\n }\n\n // Flush encoder to drain remaining frames\n await exportWorker.send('flush');\n } finally {\n workerPool.terminate('videoExport', 'export');\n }\n }\n\n private async processVideoClipWindowed(\n exportWorker: BaseWorker,\n clip: Clip,\n resource: Resource,\n instructions: ClipInstructionSet,\n model: CompositionModel,\n cacheManager: CacheManager,\n resourceLoader: ResourceLoader,\n checkStatus: () => Promise<void>,\n createWindowPromise: () => Promise<void>\n ) {\n await exportWorker.send('install_instructions', instructions);\n await this.loadAndTransferAttachments(exportWorker, clip, instructions, model, resourceLoader);\n\n const trimStartUs = clip.trimStartUs ?? 0;\n const trimEndUs = trimStartUs + clip.durationUs;\n const fps = model.fps ?? 30;\n\n const index = cacheManager.mp4IndexCache.get(resource.id);\n const gopIndex = index?.tracks?.video?.gopIndex;\n const windows =\n gopIndex && gopIndex.length > 0\n ? computeGOPAlignedWindows(gopIndex, trimStartUs, trimEndUs, VIDEO_WINDOW_DURATION_US)\n : computeFixedWindows(trimStartUs, trimEndUs, VIDEO_WINDOW_DURATION_US);\n\n for (const { startUs, endUs } of windows) {\n await checkStatus();\n\n const windowDone = createWindowPromise();\n\n const decodeSession = await VideoWindowDecodeSession.create({\n clipId: clip.id,\n resourceId: resource.id,\n targetTimeUs: trimStartUs,\n globalTimeUs: clip.startUs,\n mp4IndexCache: cacheManager.mp4IndexCache,\n cacheManager,\n compositionModel: model,\n resourceLoader,\n fps,\n });\n\n const frameStream = await decodeSession.decodeRangeToStream(startUs, endUs);\n\n await exportWorker.sendStream(frameStream, {\n streamType: 'video',\n windowStartUs: startUs,\n windowEndUs: endUs,\n });\n\n await windowDone;\n await decodeSession.dispose();\n }\n }\n\n private async processImageClip(\n exportWorker: BaseWorker,\n clip: Clip,\n resource: Resource,\n instructions: ClipInstructionSet,\n model: CompositionModel,\n resourceLoader: ResourceLoader,\n createWindowPromise: () => Promise<void>\n ) {\n await this.loadAndTransferAttachments(exportWorker, clip, instructions, model, resourceLoader);\n\n const clipDone = createWindowPromise();\n\n const imageBitmap = await resourceLoader.loadImage(resource);\n await exportWorker.send(\n 'receive_image',\n {\n resourceId: resource.id,\n sessionId: clip.id,\n imageBitmap,\n instructions,\n },\n { transfer: [imageBitmap] }\n );\n\n // ExportWorker's startImageFrameStream sends encoded stream back;\n // the receiveStream handler resolves clipDone when stream ends\n await clipDone;\n }\n\n private buildClipInstructions(clip: Clip, planner: CompositionPlanner): ClipInstructionSet {\n const plan = planner.buildClipPlan(clip, { cache: false });\n return plan.instructions;\n }\n\n private async loadAndTransferAttachments(\n exportWorker: BaseWorker,\n clip: Clip,\n instructions: ClipInstructionSet,\n model: CompositionModel,\n resourceLoader: ResourceLoader\n ): Promise<void> {\n const attachmentResources = this.extractAttachmentImageResources(instructions);\n if (attachmentResources.length === 0) return;\n\n await Promise.all(\n attachmentResources.map(async (resourceId) => {\n const resource = model.getResource(resourceId);\n if (!resource) return;\n\n const imageBitmap = await resourceLoader.loadImage(resource);\n if (!imageBitmap) return;\n\n await exportWorker.send(\n 'receive_image',\n { clipId: clip.id, resourceId, sessionId: clip.id, imageBitmap },\n { transfer: [imageBitmap] }\n );\n })\n );\n }\n\n private extractAttachmentImageResources(instructions: ClipInstructionSet): string[] {\n const resourceIds = new Set<string>();\n for (const layer of instructions.layers) {\n if (!layer.payload.attachmentId) continue;\n if (layer.type === 'image') {\n const payload = layer.payload;\n if (payload.oldResourceId) resourceIds.add(payload.oldResourceId);\n if (payload.resourceId) resourceIds.add(payload.resourceId);\n }\n }\n return Array.from(resourceIds);\n }\n\n private async decideAudioStrategy(input: {\n hasAudioSamples: boolean;\n requestedFormat: NonNullable<ExportOptions['format']>;\n requestedAudioCodec: NonNullable<ExportOptions['audioCodec']>;\n }): Promise<{ enableAudio: boolean; disabledReason?: string }> {\n if (!input.hasAudioSamples) {\n return { enableAudio: false };\n }\n\n if (input.requestedFormat !== 'mp4') {\n return {\n enableAudio: false,\n disabledReason: `Audio skipped: format ${input.requestedFormat} is not supported.`,\n };\n }\n\n if (input.requestedAudioCodec !== 'aac') {\n return {\n enableAudio: false,\n disabledReason: `Audio skipped: mp4 output currently supports only AAC (requested ${input.requestedAudioCodec}).`,\n };\n }\n\n if (typeof AudioEncoder === 'undefined') {\n return {\n enableAudio: false,\n disabledReason:\n 'Audio skipped: WebCodecs AudioEncoder is not available in this browser/runtime (AAC required for mp4).',\n };\n }\n\n const support = await AudioEncoder.isConfigSupported(AudioChunkEncoder.DEFAULT_CONFIG);\n if (!support.supported) {\n return {\n enableAudio: false,\n disabledReason:\n 'Audio skipped: WebCodecs AAC (mp4a.40.2) AudioEncoder is not supported in this browser/runtime.',\n };\n }\n\n return { enableAudio: true };\n }\n}\n"],"names":[],"mappings":";;;;;AAwCA,MAAM,2BAAmC;AAElC,MAAM,gBAAgB;AAAA,EACnB;AAAA,EAER,YAAY,MAA2B;AACrC,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,MAAM,QAAQ,OAAyB,SAAsD;AAC3F,SAAK,KAAK,aAAa,MAAA;AAEvB,UAAM,YAAY,KAAK,KAAK,aAAa,cAAc;AAEvD,YAAQ,KAAK,oDAAoD,SAAS;AAE1E,QAAI,CAAC,UAAU,OAAO;AACpB,aAAO,KAAK,gBAAgB,OAAO,OAAO;AAAA,IAC5C;AAEA,UAAM,WAAW,oBAAoB,SAAS;AAC9C,WAAO,UAAU,MAAM,QAAQ,UAAU,MAAM,KAAK,gBAAgB,OAAO,OAAO,CAAC;AAAA,EACrF;AAAA,EAEA,MAAc,gBACZ,OACA,SACsB;AACtB,UAAM,EAAE,YAAY,cAAc,UAAU,eAAA,IAAmB,KAAK;AACpE,UAAM,SAAS,QAAQ;AACvB,UAAM,aAAa,QAAQ;AAC3B,UAAM,aAAa,QAAQ,cAAc;AAEzC,YAAQ,KAAK,qDAAqD,UAAU;AAE5E,QAAI,eAAe,YAAY,OAAO,QAAQ,cAAc,YAAY;AACtE,YAAM,IAAI,MAAM,0DAA0D;AAAA,IAC5E;AAEA,QAAI,gBAAgB;AAEpB,UAAM,cAAc,YAAY;AAC9B,UAAI,QAAQ,SAAS;AACnB,cAAM,IAAI,aAAa,kBAAkB,YAAY;AAAA,MACvD;AACA,UAAI,YAAY,YAAY;AAC1B,eAAO,WAAW,YAAY;AAC5B,cAAI,QAAQ,QAAS,OAAM,IAAI,aAAa,kBAAkB,YAAY;AAC1E,gBAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,GAAG,CAAC;AAAA,QACzD;AAAA,MACF;AAAA,IACF;AAEA,UAAM,QAAQ,QAAQ,SAAS,MAAM,cAAc,SAAS;AAC5D,UAAM,SAAS,QAAQ,UAAU,MAAM,cAAc,UAAU;AAC/D,UAAM,MAAM,QAAQ,OAAO,MAAM,OAAO;AAExC,aAAS,KAAK,aAAa,aAAa;AAAA,MACtC,QAAQ,QAAQ,UAAU;AAAA,MAC1B;AAAA,MACA;AAAA,MACA;AAAA,MACA,YAAY,MAAM;AAAA,IAAA,CACnB;AAED,SAAK,KAAK,aAAa,YAAA;AAEvB,QAAI;AAEF,cAAQ,KAAK,kDAAkD;AAC/D,YAAM,KAAK,iBAAiB,OAAO,gBAAgB,UAAU,WAAW;AAExE,YAAM,kBAAkB,KAAK,KAAK,aAAa,iBAAiB,kBAAkB;AAClF,YAAM,EAAE,aAAa,eAAA,IAAmB,MAAM,KAAK,oBAAoB;AAAA,QACrE;AAAA,QACA,iBAAiB,QAAQ,UAAU;AAAA,QACnC,qBAAqB,QAAQ,cAAc;AAAA,MAAA,CAC5C;AACD,UAAI,gBAAgB;AAClB,iBAAS,KAAK,aAAa,gBAAgB;AAAA,UACzC,UAAU;AAAA,UACV,OAAO;AAAA,UACP,SAAS;AAAA,QAAA,CACV;AAAA,MACH;AAGA,cAAQ,KAAK,4CAA4C;AACzD,iBAAW,MAAM;AAAA,QACf;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,QACE,eAAe,WACX;AAAA,UACE,MAAM;AAAA,UACN,QAAQ,CAAC,MAAM,aAAa;AAC1B,4BAAgB,KAAK,IAAI,eAAe,WAAW,KAAK,UAAU;AAClE,oBAAQ,YAAY,MAAM,QAAQ;AAAA,UACpC;AAAA,UACA,WAAW,QAAQ;AAAA,UACnB,SAAS,QAAQ;AAAA,QAAA,IAEnB,EAAE,MAAM,OAAA;AAAA,MAAO,CACtB;AAGD,cAAQ,KAAK,wDAAwD;AACrE,YAAM,YAAY,MAAM,OAAO,KAAK,CAAC,MAAM,EAAE,OAAO,MAAM,WAAW;AACrE,UAAI,aAAa,UAAU,MAAM,SAAS,GAAG;AAC3C,cAAM,eAAe,cACjB,KAAK,sBAAsB,MAAM,YAAY,cAAc,YAAY,WAAW,IAClF,QAAQ,QAAA;AAEZ,cAAM,KAAK,qBAAqB,UAAU,OAAO,YAAY,OAAO,WAAW;AAE/E,YAAI;AACF,gBAAM;AAAA,QACR,SAAS,OAAO;AACd,mBAAS,KAAK,aAAa,gBAAgB;AAAA,YACzC,UAAU;AAAA,YACV,OAAO;AAAA,YACP,SAAS,oCAAoC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,UAAA,CACpG;AAAA,QACH;AAAA,MACF,OAAO;AACL,gBAAQ,KAAK,wCAAwC;AAAA,MACvD;AAEA,YAAM,aAAa,oBAAA;AAEnB,UAAI,QAAQ,SAAS;AACnB,cAAM,IAAI,aAAa,kBAAkB,YAAY;AAAA,MACvD;AAGA,cAAQ,KAAK,wCAAwC;AACrD,YAAM,OAAO,MAAM,WAAW,SAAA;AAE9B,eAAS,KAAK,aAAa,gBAAgB;AAAA,QACzC,MAAM,MAAM,QAAQ;AAAA,QACpB,YAAY,MAAM,aAAa;AAAA,QAC/B,QAAQ,QAAQ,UAAU;AAAA,MAAA,CAC3B;AAED,eAAS,KAAK,aAAa,gBAAgB;AAAA,QACzC,UAAU;AAAA,QACV,OAAO;AAAA,MAAA,CACR;AAED,cAAQ,KAAK,oDAAoD;AACjE,aAAO;AAAA,IACT,SAAS,OAAO;AACd,cAAQ,MAAM,mCAAmC,KAAK;AACtD,eAAS,KAAK,aAAa,aAAa;AAAA,QACtC,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AAAA,QAC/D,OAAO;AAAA,MAAA,CACR;AACD,YAAM;AAAA,IACR,UAAA;AACE,cAAQ,KAAK,uCAAuC;AACpD,WAAK,KAAK,aAAa,UAAA;AAAA,IACzB;AAAA,EACF;AAAA,EAEA,MAAc,iBACZ,OACA,gBACA,UACA,aACe;AACf,aAAS,KAAK,aAAa,gBAAgB;AAAA,MACzC,UAAU;AAAA,MACV,OAAO;AAAA,MACP,SAAS;AAAA,IAAA,CACV;AAED,UAAM,SAAS,MAAM,OAAO,OAAO,CAAC,UAAU,CAAC,SAAS,OAAO,EAAE,SAAS,MAAM,IAAI,CAAC;AACrF,QAAI,OAAO,WAAW,EAAG;AAEzB,UAAM,eAAe,KAAK,IAAI,GAAG,OAAO,IAAI,CAAC,UAAU,MAAM,MAAM,MAAM,CAAC;AAC1E,UAAM,kBAA4B,CAAA;AAClC,UAAM,2BAAW,IAAA;AAEjB,aAAS,YAAY,GAAG,YAAY,cAAc,aAAa;AAC7D,iBAAW,SAAS,QAAQ;AAC1B,cAAM,OAAO,MAAM,MAAM,SAAS;AAClC,YAAI,QAAQ,cAAc,IAAI,GAAG;AAC/B,cAAI,CAAC,KAAK,IAAI,KAAK,UAAU,GAAG;AAC9B,iBAAK,IAAI,KAAK,UAAU;AACxB,4BAAgB,KAAK,KAAK,UAAU;AAAA,UACtC;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,UAAM,QAAQ,gBAAgB;AAC9B,QAAI,YAAY;AAEhB,UAAM,QAAQ;AAAA,MACZ,gBAAgB,IAAI,OAAO,eAAe;AACxC,cAAM,YAAA;AACN,cAAM,eAAe,KAAK,YAAY,EAAE,WAAW,OAAO;AAE1D,cAAM,WAAW,MAAM,YAAY,UAAU;AAC7C,YAAI,UAAU,UAAU,SAAS;AAC/B,gBAAM,UAAU,SAAS,OAAO,WAAW;AAC3C,gBAAM,IAAI,MAAM,6BAA6B,UAAU,KAAK,OAAO,EAAE;AAAA,QACvE;AAEA;AAEA,cAAM,WAAW,QAAQ,IAAK,YAAY,QAAS,MAAM;AACzD,iBAAS,KAAK,aAAa,gBAAgB;AAAA,UACzC;AAAA,UACA,OAAO;AAAA,UACP,SAAS,yBAAyB,SAAS,IAAI,KAAK;AAAA,QAAA,CACrD;AAAA,MACH,CAAC;AAAA,IAAA;AAAA,EAEL;AAAA,EAEA,MAAc,sBACZ,iBACA,cACA,YACA,aACe;AACf,UAAM,qBAAqB,IAAI,KAAK;AACpC,QAAI,YAAY;AAEhB,WAAO,YAAY,iBAAiB;AAClC,YAAM,YAAA;AAEN,YAAM,QAAQ,KAAK,IAAI,YAAY,oBAAoB,eAAe;AAEtE,YAAM,aAAa;AAAA,QAAoB;AAAA,QAAW;AAAA,QAAO,CAAC,OAAO,SAC/D,WAAW,gBAAgB,OAAO,IAAI;AAAA,MAAA;AAGxC,WAAK,KAAK,aAAa,gBAAA;AAEvB,kBAAY;AAAA,IACd;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,qBACZ,OACA,YACA,OACA,aACA;AACA,UAAM,EAAE,YAAY,SAAS,cAAc,eAAA,IAAmB,KAAK;AACnE,UAAM,gBAAgB,KAAK,KAAK,sBAAA;AAGhC,UAAM,eAAe,MAAM,WAAW,YAAY,eAAe,UAAU,EAAE,MAAM,MAAM;AACzF,UAAM,eAAe,cAAc,eAAe,CAAA;AAGlD,UAAM,gBAAgB,EAAE,GAAI,aAAa,WAAW,CAAA,EAAC;AACrD,UAAM,eAAe,EAAE,GAAI,aAAa,UAAU,CAAA,EAAC;AACnD,QAAI,MAAM,cAAc,OAAO;AAC7B,oBAAc,QAAQ,MAAM,aAAa;AACzC,mBAAa,QAAQ,MAAM,aAAa;AAAA,IAC1C;AACA,QAAI,MAAM,cAAc,QAAQ;AAC9B,oBAAc,SAAS,MAAM,aAAa;AAC1C,mBAAa,SAAS,MAAM,aAAa;AAAA,IAC3C;AAEA,UAAM,aAAa,KAAK,aAAa,EAAE,SAAS,eAAe,QAAQ,cAAc;AAGrF,QAAI;AACJ,QAAI;AACJ,QAAI,kBAAkB;AACtB,QAAI,iBAAiB;AAErB,iBAAa,cAAc,OAAO,QAAQ,cAAc;AACtD,YAAM,SAAS,OAAO,UAAA;AACtB,UAAI;AACF,eAAO,MAAM;AACX,gBAAM,YAAA;AAEN,gBAAM,EAAE,MAAM,MAAA,IAAU,MAAM,OAAO,KAAA;AACrC,cAAI,KAAM;AACV,cAAI,CAAC,MAAO;AAEZ,gBAAM,EAAE,OAAO,eAAe,SAAA,IAAa;AAI3C,gBAAM,gBAAgB,cAAc,YAAY;AAGhD,gBAAM,oBAAoB,cAAc,YAAY;AAEpD,gBAAM,SAAS,IAAI,YAAY,cAAc,UAAU;AACvD,wBAAc,OAAO,MAAM;AAE3B,gBAAM,gBAAgB,IAAI,kBAAkB;AAAA,YAC1C,MAAM,cAAc;AAAA,YACpB,WAAW;AAAA,YACX,UAAU;AAAA,YACV,MAAM;AAAA,UAAA,CACP;AAED,qBAAW,gBAAgB,eAAe,QAAQ;AAElD,2BAAiB,oBAAoB;AAErC,gBAAM,mBAAmB,oBAAoB,MAAM;AACnD,gBAAM,gBAAgB,MAAM,mBAAmB;AAE/C,eAAK,KAAK,SAAS,KAAK,aAAa,gBAAgB;AAAA,YACnD,UAAU,KAAK,IAAI,GAAK,aAAa;AAAA,YACrC,OAAO;AAAA,YACP,QAAQ;AAAA,UAAA,CACT;AAAA,QACH;AACA,uBAAA;AAAA,MACF,SAAS,OAAO;AACd,uBAAe,KAAK;AAAA,MACtB,UAAA;AACE,eAAO,YAAA;AAAA,MACT;AAAA,IACF,CAAC;AAGD,QAAI;AACF,iBAAW,QAAQ,OAAO;AACxB,cAAM,YAAA;AAEN,cAAM,WAAW,cAAc,IAAI,IAAI,MAAM,YAAY,KAAK,UAAU,IAAI;AAC5E,YAAI,CAAC,UAAU;AACb,kBAAQ,KAAK,kDAAkD,KAAK,EAAE;AACtE;AAAA,QACF;AAEA,cAAM,eAAe,KAAK,sBAAsB,MAAM,OAAO;AAE7D,cAAM,sBAAsB,MAC1B,IAAI,QAAc,CAAC,SAAS,WAAW;AACrC,2BAAiB;AACjB,2BAAiB;AAAA,QACnB,CAAC;AAEH,YAAI,SAAS,SAAS,SAAS;AAC7B,gBAAM,KAAK;AAAA,YACT;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UAAA;AAAA,QAEJ,OAAO;AACL,gBAAM,KAAK;AAAA,YACT;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UAAA;AAAA,QAEJ;AAEA,cAAM,aAAa,KAAK,cAAc;AACtC,0BAAkB;AAAA,MACpB;AAGA,YAAM,aAAa,KAAK,OAAO;AAAA,IACjC,UAAA;AACE,iBAAW,UAAU,eAAe,QAAQ;AAAA,IAC9C;AAAA,EACF;AAAA,EAEA,MAAc,yBACZ,cACA,MACA,UACA,cACA,OACA,cACA,gBACA,aACA,qBACA;AACA,UAAM,aAAa,KAAK,wBAAwB,YAAY;AAC5D,UAAM,KAAK,2BAA2B,cAAc,MAAM,cAAc,OAAO,cAAc;AAE7F,UAAM,cAAc,KAAK,eAAe;AACxC,UAAM,YAAY,cAAc,KAAK;AACrC,UAAM,MAAM,MAAM,OAAO;AAEzB,UAAM,QAAQ,aAAa,cAAc,IAAI,SAAS,EAAE;AACxD,UAAM,WAAW,OAAO,QAAQ,OAAO;AACvC,UAAM,UACJ,YAAY,SAAS,SAAS,IAC1B,yBAAyB,UAAU,aAAa,WAAW,wBAAwB,IACnF,oBAAoB,aAAa,WAAW,wBAAwB;AAE1E,eAAW,EAAE,SAAS,MAAA,KAAW,SAAS;AACxC,YAAM,YAAA;AAEN,YAAM,aAAa,oBAAA;AAEnB,YAAM,gBAAgB,MAAM,yBAAyB,OAAO;AAAA,QAC1D,QAAQ,KAAK;AAAA,QACb,YAAY,SAAS;AAAA,QACrB,cAAc;AAAA,QACd,cAAc,KAAK;AAAA,QACnB,eAAe,aAAa;AAAA,QAC5B;AAAA,QACA,kBAAkB;AAAA,QAClB;AAAA,QACA;AAAA,MAAA,CACD;AAED,YAAM,cAAc,MAAM,cAAc,oBAAoB,SAAS,KAAK;AAE1E,YAAM,aAAa,WAAW,aAAa;AAAA,QACzC,YAAY;AAAA,QACZ,eAAe;AAAA,QACf,aAAa;AAAA,MAAA,CACd;AAED,YAAM;AACN,YAAM,cAAc,QAAA;AAAA,IACtB;AAAA,EACF;AAAA,EAEA,MAAc,iBACZ,cACA,MACA,UACA,cACA,OACA,gBACA,qBACA;AACA,UAAM,KAAK,2BAA2B,cAAc,MAAM,cAAc,OAAO,cAAc;AAE7F,UAAM,WAAW,oBAAA;AAEjB,UAAM,cAAc,MAAM,eAAe,UAAU,QAAQ;AAC3D,UAAM,aAAa;AAAA,MACjB;AAAA,MACA;AAAA,QACE,YAAY,SAAS;AAAA,QACrB,WAAW,KAAK;AAAA,QAChB;AAAA,QACA;AAAA,MAAA;AAAA,MAEF,EAAE,UAAU,CAAC,WAAW,EAAA;AAAA,IAAE;AAK5B,UAAM;AAAA,EACR;AAAA,EAEQ,sBAAsB,MAAY,SAAiD;AACzF,UAAM,OAAO,QAAQ,cAAc,MAAM,EAAE,OAAO,OAAO;AACzD,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAc,2BACZ,cACA,MACA,cACA,OACA,gBACe;AACf,UAAM,sBAAsB,KAAK,gCAAgC,YAAY;AAC7E,QAAI,oBAAoB,WAAW,EAAG;AAEtC,UAAM,QAAQ;AAAA,MACZ,oBAAoB,IAAI,OAAO,eAAe;AAC5C,cAAM,WAAW,MAAM,YAAY,UAAU;AAC7C,YAAI,CAAC,SAAU;AAEf,cAAM,cAAc,MAAM,eAAe,UAAU,QAAQ;AAC3D,YAAI,CAAC,YAAa;AAElB,cAAM,aAAa;AAAA,UACjB;AAAA,UACA,EAAE,QAAQ,KAAK,IAAI,YAAY,WAAW,KAAK,IAAI,YAAA;AAAA,UACnD,EAAE,UAAU,CAAC,WAAW,EAAA;AAAA,QAAE;AAAA,MAE9B,CAAC;AAAA,IAAA;AAAA,EAEL;AAAA,EAEQ,gCAAgC,cAA4C;AAClF,UAAM,kCAAkB,IAAA;AACxB,eAAW,SAAS,aAAa,QAAQ;AACvC,UAAI,CAAC,MAAM,QAAQ,aAAc;AACjC,UAAI,MAAM,SAAS,SAAS;AAC1B,cAAM,UAAU,MAAM;AACtB,YAAI,QAAQ,cAAe,aAAY,IAAI,QAAQ,aAAa;AAChE,YAAI,QAAQ,WAAY,aAAY,IAAI,QAAQ,UAAU;AAAA,MAC5D;AAAA,IACF;AACA,WAAO,MAAM,KAAK,WAAW;AAAA,EAC/B;AAAA,EAEA,MAAc,oBAAoB,OAI6B;AAC7D,QAAI,CAAC,MAAM,iBAAiB;AAC1B,aAAO,EAAE,aAAa,MAAA;AAAA,IACxB;AAEA,QAAI,MAAM,oBAAoB,OAAO;AACnC,aAAO;AAAA,QACL,aAAa;AAAA,QACb,gBAAgB,yBAAyB,MAAM,eAAe;AAAA,MAAA;AAAA,IAElE;AAEA,QAAI,MAAM,wBAAwB,OAAO;AACvC,aAAO;AAAA,QACL,aAAa;AAAA,QACb,gBAAgB,oEAAoE,MAAM,mBAAmB;AAAA,MAAA;AAAA,IAEjH;AAEA,QAAI,OAAO,iBAAiB,aAAa;AACvC,aAAO;AAAA,QACL,aAAa;AAAA,QACb,gBACE;AAAA,MAAA;AAAA,IAEN;AAEA,UAAM,UAAU,MAAM,aAAa,kBAAkB,kBAAkB,cAAc;AACrF,QAAI,CAAC,QAAQ,WAAW;AACtB,aAAO;AAAA,QACL,aAAa;AAAA,QACb,gBACE;AAAA,MAAA;AAAA,IAEN;AAEA,WAAO,EAAE,aAAa,KAAA;AAAA,EACxB;AACF;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BaseEncoder.d.ts","sourceRoot":"","sources":["../../../src/stages/encode/BaseEncoder.ts"],"names":[],"mappings":"AAEA;;;GAGG;AAEH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,iBAAiB,CAAC;IACzB,QAAQ,EAAE,yBAAyB,CAAC;CACrC;AAED,8BAAsB,WAAW,CAC/B,QAAQ,SAAS,YAAY,GAAG,YAAY,EAC5C,OAAO,SAAS,kBAAkB,GAAG,kBAAkB,EACvD,MAAM,SAAS,UAAU,GAAG,SAAS,EACrC,MAAM,SAAS,iBAAiB,GAAG,iBAAiB,EACpD,SAAS,SAAS,yBAAyB,GAAG,yBAAyB;IAEvE,SAAS,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC;IAC7B,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC;IAC1B,SAAS,CAAC,UAAU,EAAE,gCAAgC,CAAC,YAAY,CAAC,GAAG,IAAI,CAAQ;gBAEvE,MAAM,EAAE,OAAO;IAI3B,SAAS,IAAI,OAAO;IAIpB,SAAS,KAAK,aAAa,IAAI,OAAO,CAErC;IAED,SAAS,CAAC,iBAAiB,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO;IAW/D,SAAS,CAAC,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO;IAiBlD,SAAS,CAAC,YAAY,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO;IAIjD,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAuB3B,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAgCpD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAQtB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAYtB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAe5B,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,SAAS,CAAC,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,GAAG,IAAI;IAehE,SAAS,CAAC,WAAW,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI;IAiBhD,SAAS,CAAC,QAAQ,CAAC,iBAAiB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC;IACtF,SAAS,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,EAAE,WAAW,GAAG,QAAQ;IAC7D,SAAS,CAAC,QAAQ,CAAC,cAAc,IAAI,MAAM;IAG3C,SAAS,CAAC,OAAO,IAAI,IAAI;IAKzB,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAClD,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IAEzD;;;OAGG;IACH,YAAY,IAAI,eAAe,CAAC,MAAM,EAAE,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"BaseEncoder.d.ts","sourceRoot":"","sources":["../../../src/stages/encode/BaseEncoder.ts"],"names":[],"mappings":"AAEA;;;GAGG;AAEH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,iBAAiB,CAAC;IACzB,QAAQ,EAAE,yBAAyB,CAAC;CACrC;AAED,8BAAsB,WAAW,CAC/B,QAAQ,SAAS,YAAY,GAAG,YAAY,EAC5C,OAAO,SAAS,kBAAkB,GAAG,kBAAkB,EACvD,MAAM,SAAS,UAAU,GAAG,SAAS,EACrC,MAAM,SAAS,iBAAiB,GAAG,iBAAiB,EACpD,SAAS,SAAS,yBAAyB,GAAG,yBAAyB;IAEvE,SAAS,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC;IAC7B,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC;IAC1B,SAAS,CAAC,UAAU,EAAE,gCAAgC,CAAC,YAAY,CAAC,GAAG,IAAI,CAAQ;gBAEvE,MAAM,EAAE,OAAO;IAI3B,SAAS,IAAI,OAAO;IAIpB,SAAS,KAAK,aAAa,IAAI,OAAO,CAErC;IAED,SAAS,CAAC,iBAAiB,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO;IAW/D,SAAS,CAAC,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO;IAiBlD,SAAS,CAAC,YAAY,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO;IAIjD,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAuB3B,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAgCpD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAQtB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAYtB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAe5B,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,SAAS,CAAC,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,GAAG,IAAI;IAehE,SAAS,CAAC,WAAW,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI;IAiBhD,SAAS,CAAC,QAAQ,CAAC,iBAAiB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC;IACtF,SAAS,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,EAAE,WAAW,GAAG,QAAQ;IAC7D,SAAS,CAAC,QAAQ,CAAC,cAAc,IAAI,MAAM;IAG3C,SAAS,CAAC,OAAO,IAAI,IAAI;IAKzB,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAClD,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IAEzD;;;OAGG;IACH,YAAY,IAAI,eAAe,CAAC,MAAM,EAAE,YAAY,CAAC;IAuDrD,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;CACrC;AAED,UAAU,WAAW;IACnB,MAAM,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,KAAK,IAAI,CAAC;IAC5C,KAAK,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;CACtC"}
|
|
@@ -39,7 +39,7 @@ class BaseEncoder {
|
|
|
39
39
|
return JSON.stringify(a) === JSON.stringify(b);
|
|
40
40
|
}
|
|
41
41
|
async initialize() {
|
|
42
|
-
console.info("Encoder is initializing
|
|
42
|
+
console.info("Encoder is initializing, config:", this.config);
|
|
43
43
|
if (this.encoder?.state === "configured") {
|
|
44
44
|
console.warn("Encoder is already initialized, skipping initialization");
|
|
45
45
|
return;
|
|
@@ -156,6 +156,7 @@ class BaseEncoder {
|
|
|
156
156
|
},
|
|
157
157
|
transform: async (input) => {
|
|
158
158
|
if (!this.isReady) {
|
|
159
|
+
console.warn("Encoder is not ready, initializing 1...");
|
|
159
160
|
await this.initialize();
|
|
160
161
|
}
|
|
161
162
|
if (this.encoder && this.encoder.encodeQueueSize >= this.encodeQueueThreshold) {
|
|
@@ -171,9 +172,11 @@ class BaseEncoder {
|
|
|
171
172
|
});
|
|
172
173
|
}
|
|
173
174
|
if (!this.isReady) {
|
|
175
|
+
console.warn("Encoder is not ready, initializing 2...");
|
|
174
176
|
await this.initialize();
|
|
175
177
|
}
|
|
176
178
|
if (!this.encoder || this.encoder.state !== "configured") {
|
|
179
|
+
console.error("Encoder not configured, throwing error");
|
|
177
180
|
throw new Error("Encoder not configured");
|
|
178
181
|
}
|
|
179
182
|
const frame = input.frame || input;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BaseEncoder.js","sources":["../../../src/stages/encode/BaseEncoder.ts"],"sourcesContent":["// Base encoder implementation\n\n/**\n * Base encoder class for both video and audio encoding\n * Handles common WebCodecs encoder operations\n */\n\nexport interface EncoderChunk {\n chunk: EncodedVideoChunk;\n metadata: EncodedVideoChunkMetadata;\n}\n\nexport abstract class BaseEncoder<\n TEncoder extends VideoEncoder | AudioEncoder,\n TConfig extends VideoEncoderConfig | AudioEncoderConfig,\n TInput extends VideoFrame | AudioData,\n TChunk extends EncodedVideoChunk | EncodedAudioChunk,\n TMetadata extends EncodedVideoChunkMetadata | EncodedAudioChunkMetadata,\n> {\n protected encoder?: TEncoder;\n protected config: TConfig;\n protected controller: TransformStreamDefaultController<EncoderChunk> | null = null;\n\n constructor(config: TConfig) {\n this.config = config;\n }\n\n getConfig(): TConfig {\n return { ...this.config };\n }\n\n protected get currentConfig(): TConfig {\n return this.config;\n }\n\n protected shouldReconfigure(partial: Partial<TConfig>): boolean {\n const next = { ...this.config, ...partial } as TConfig;\n const keys = Object.keys(partial ?? {}) as Array<keyof TConfig>;\n for (const key of keys) {\n if (partial[key] !== undefined && next[key] !== this.config[key]) {\n return true;\n }\n }\n return false;\n }\n\n protected hasConfigChanged(next: TConfig): boolean {\n const currentEntries = Object.entries(this.config) as Array<[keyof TConfig, any]>;\n for (const [key, value] of currentEntries) {\n if (next[key] !== value) {\n return true;\n }\n }\n\n for (const key of Object.keys(next) as Array<keyof TConfig>) {\n if (this.config[key] !== next[key]) {\n return true;\n }\n }\n\n return false;\n }\n\n protected configsEqual(a: TConfig, b: TConfig): boolean {\n return JSON.stringify(a) === JSON.stringify(b);\n }\n\n async initialize(): Promise<void> {\n console.info('Encoder is initializing...');\n if (this.encoder?.state === 'configured') {\n console.warn('Encoder is already initialized, skipping initialization');\n return;\n }\n\n const isSupported = await this.isConfigSupported(this.config);\n\n if (!isSupported.supported) {\n console.warn('Codec not supported:', JSON.stringify(this.config));\n throw new Error(`Codec not supported: ${JSON.stringify(this.config)}`);\n }\n\n this.encoder = this.createEncoder({\n output: this.handleOutput.bind(this),\n error: this.handleError.bind(this),\n });\n\n (this.encoder as any).configure(this.config);\n console.info('Encoder is initialized');\n }\n\n async reconfigure(config: Partial<TConfig>): Promise<void> {\n console.info('Encoder is reconfiguring...');\n if (!config || Object.keys(config).length === 0) {\n return;\n }\n\n const nextConfig = { ...this.config, ...config } as TConfig;\n\n if (this.configsEqual(this.config, nextConfig)) {\n return;\n }\n\n if (!this.encoder) {\n this.config = nextConfig;\n await this.initialize();\n return;\n }\n\n if (this.encoder.state === 'configured') {\n await this.encoder.flush();\n }\n\n const isSupported = await this.isConfigSupported(nextConfig);\n if (!isSupported.supported) {\n throw new Error(`New configuration not supported: ${nextConfig.codec}`);\n }\n\n this.config = nextConfig;\n (this.encoder as any).configure(this.config);\n console.info('Encoder is reconfigured');\n }\n\n async flush(): Promise<void> {\n if (!this.encoder) {\n return;\n }\n\n await this.encoder.flush();\n }\n\n async reset(): Promise<void> {\n console.info('Encoder is resetting...');\n if (!this.encoder) {\n console.warn('Encoder is not initialized, skipping reset');\n return;\n }\n\n this.encoder.reset();\n this.onReset();\n console.info('Encoder is resetted');\n }\n\n async close(): Promise<void> {\n console.info('Encoder is closing...');\n if (!this.encoder) {\n return;\n }\n\n if (this.encoder.state === 'configured') {\n await this.encoder.flush();\n }\n\n this.encoder.close();\n this.encoder = undefined;\n console.info('Encoder is closed');\n }\n\n get isReady(): boolean {\n return this.encoder?.state === 'configured';\n }\n\n get queueSize(): number {\n return this.encoder?.encodeQueueSize ?? 0;\n }\n\n protected handleOutput(chunk: TChunk, metadata: TMetadata): void {\n // Only enqueue if controller exists and stream is not closed\n if (this.controller) {\n try {\n this.controller.enqueue({ chunk, metadata });\n } catch (error) {\n console.error('Encoder output error:', error);\n // Stream may be closed during flush, ignore enqueue errors\n if (!(error instanceof TypeError && error.message.includes('closed'))) {\n throw error;\n }\n }\n }\n }\n\n protected handleError(error: DOMException): void {\n // Codec reclaimed by browser due to inactivity, let transform re-initialize on next frame\n if (error.message.includes('reclaimed')) {\n console.warn('Encoder reclaimed by browser due to inactivity, skipping error handling');\n return;\n }\n console.error(`[${this.getEncoderType()}Encoder] Encode error:`, {\n name: error.name,\n message: error.message,\n encoderState: this.encoder?.state,\n queueSize: this.queueSize,\n platform: typeof navigator !== 'undefined' ? navigator.platform : 'unknown',\n });\n this.controller?.error(error);\n }\n\n // Abstract methods to be implemented by subclasses\n protected abstract isConfigSupported(config: TConfig): Promise<{ supported: boolean }>;\n protected abstract createEncoder(init: EncoderInit): TEncoder;\n protected abstract getEncoderType(): string;\n\n // Hook for subclasses to handle reset\n protected onReset(): void {\n // Override in subclasses if needed\n }\n\n // Abstract properties for backpressure configuration\n protected abstract readonly highWaterMark: number;\n protected abstract readonly encodeQueueThreshold: number;\n\n /**\n * Create transform stream for encoding\n * Implements common stream logic with backpressure handling\n */\n createStream(): TransformStream<TInput, EncoderChunk> {\n return new TransformStream<TInput, EncoderChunk>(\n {\n start: async (controller) => {\n this.controller = controller;\n },\n\n transform: async (input) => {\n // Lazy init: create encoder on first frame or re-create after codec reclaim\n if (!this.isReady) {\n await this.initialize();\n }\n\n // Backpressure: wait for encoder queue to drain\n if (this.encoder && this.encoder.encodeQueueSize >= this.encodeQueueThreshold) {\n await new Promise<void>((resolve) => {\n const check = () => {\n if (!this.encoder || this.encoder.encodeQueueSize < this.encodeQueueThreshold - 1) {\n resolve();\n } else {\n setTimeout(check, 10);\n }\n };\n check();\n });\n }\n\n // Re-check after backpressure await: codec may be reclaimed during the wait\n if (!this.isReady) {\n await this.initialize();\n }\n if (!this.encoder || this.encoder.state !== 'configured') {\n throw new Error('Encoder not configured');\n }\n\n const frame = (input as any).frame || input;\n this.encode(frame);\n },\n\n flush: async () => {\n await this.flush();\n },\n },\n // Queuing strategy with backpressure configuration\n {\n highWaterMark: this.highWaterMark,\n size: () => 1, // Count-based\n }\n );\n }\n\n // Abstract method for encoding\n abstract encode(input: TInput): void;\n}\n\ninterface EncoderInit {\n output: (chunk: any, metadata: any) => void;\n error: (error: DOMException) => void;\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"BaseEncoder.js","sources":["../../../src/stages/encode/BaseEncoder.ts"],"sourcesContent":["// Base encoder implementation\n\n/**\n * Base encoder class for both video and audio encoding\n * Handles common WebCodecs encoder operations\n */\n\nexport interface EncoderChunk {\n chunk: EncodedVideoChunk;\n metadata: EncodedVideoChunkMetadata;\n}\n\nexport abstract class BaseEncoder<\n TEncoder extends VideoEncoder | AudioEncoder,\n TConfig extends VideoEncoderConfig | AudioEncoderConfig,\n TInput extends VideoFrame | AudioData,\n TChunk extends EncodedVideoChunk | EncodedAudioChunk,\n TMetadata extends EncodedVideoChunkMetadata | EncodedAudioChunkMetadata,\n> {\n protected encoder?: TEncoder;\n protected config: TConfig;\n protected controller: TransformStreamDefaultController<EncoderChunk> | null = null;\n\n constructor(config: TConfig) {\n this.config = config;\n }\n\n getConfig(): TConfig {\n return { ...this.config };\n }\n\n protected get currentConfig(): TConfig {\n return this.config;\n }\n\n protected shouldReconfigure(partial: Partial<TConfig>): boolean {\n const next = { ...this.config, ...partial } as TConfig;\n const keys = Object.keys(partial ?? {}) as Array<keyof TConfig>;\n for (const key of keys) {\n if (partial[key] !== undefined && next[key] !== this.config[key]) {\n return true;\n }\n }\n return false;\n }\n\n protected hasConfigChanged(next: TConfig): boolean {\n const currentEntries = Object.entries(this.config) as Array<[keyof TConfig, any]>;\n for (const [key, value] of currentEntries) {\n if (next[key] !== value) {\n return true;\n }\n }\n\n for (const key of Object.keys(next) as Array<keyof TConfig>) {\n if (this.config[key] !== next[key]) {\n return true;\n }\n }\n\n return false;\n }\n\n protected configsEqual(a: TConfig, b: TConfig): boolean {\n return JSON.stringify(a) === JSON.stringify(b);\n }\n\n async initialize(): Promise<void> {\n console.info('Encoder is initializing, config:', this.config);\n if (this.encoder?.state === 'configured') {\n console.warn('Encoder is already initialized, skipping initialization');\n return;\n }\n\n const isSupported = await this.isConfigSupported(this.config);\n\n if (!isSupported.supported) {\n console.warn('Codec not supported:', JSON.stringify(this.config));\n throw new Error(`Codec not supported: ${JSON.stringify(this.config)}`);\n }\n\n this.encoder = this.createEncoder({\n output: this.handleOutput.bind(this),\n error: this.handleError.bind(this),\n });\n\n (this.encoder as any).configure(this.config);\n console.info('Encoder is initialized');\n }\n\n async reconfigure(config: Partial<TConfig>): Promise<void> {\n console.info('Encoder is reconfiguring...');\n if (!config || Object.keys(config).length === 0) {\n return;\n }\n\n const nextConfig = { ...this.config, ...config } as TConfig;\n\n if (this.configsEqual(this.config, nextConfig)) {\n return;\n }\n\n if (!this.encoder) {\n this.config = nextConfig;\n await this.initialize();\n return;\n }\n\n if (this.encoder.state === 'configured') {\n await this.encoder.flush();\n }\n\n const isSupported = await this.isConfigSupported(nextConfig);\n if (!isSupported.supported) {\n throw new Error(`New configuration not supported: ${nextConfig.codec}`);\n }\n\n this.config = nextConfig;\n (this.encoder as any).configure(this.config);\n console.info('Encoder is reconfigured');\n }\n\n async flush(): Promise<void> {\n if (!this.encoder) {\n return;\n }\n\n await this.encoder.flush();\n }\n\n async reset(): Promise<void> {\n console.info('Encoder is resetting...');\n if (!this.encoder) {\n console.warn('Encoder is not initialized, skipping reset');\n return;\n }\n\n this.encoder.reset();\n this.onReset();\n console.info('Encoder is resetted');\n }\n\n async close(): Promise<void> {\n console.info('Encoder is closing...');\n if (!this.encoder) {\n return;\n }\n\n if (this.encoder.state === 'configured') {\n await this.encoder.flush();\n }\n\n this.encoder.close();\n this.encoder = undefined;\n console.info('Encoder is closed');\n }\n\n get isReady(): boolean {\n return this.encoder?.state === 'configured';\n }\n\n get queueSize(): number {\n return this.encoder?.encodeQueueSize ?? 0;\n }\n\n protected handleOutput(chunk: TChunk, metadata: TMetadata): void {\n // Only enqueue if controller exists and stream is not closed\n if (this.controller) {\n try {\n this.controller.enqueue({ chunk, metadata });\n } catch (error) {\n console.error('Encoder output error:', error);\n // Stream may be closed during flush, ignore enqueue errors\n if (!(error instanceof TypeError && error.message.includes('closed'))) {\n throw error;\n }\n }\n }\n }\n\n protected handleError(error: DOMException): void {\n // Codec reclaimed by browser due to inactivity, let transform re-initialize on next frame\n if (error.message.includes('reclaimed')) {\n console.warn('Encoder reclaimed by browser due to inactivity, skipping error handling');\n return;\n }\n console.error(`[${this.getEncoderType()}Encoder] Encode error:`, {\n name: error.name,\n message: error.message,\n encoderState: this.encoder?.state,\n queueSize: this.queueSize,\n platform: typeof navigator !== 'undefined' ? navigator.platform : 'unknown',\n });\n this.controller?.error(error);\n }\n\n // Abstract methods to be implemented by subclasses\n protected abstract isConfigSupported(config: TConfig): Promise<{ supported: boolean }>;\n protected abstract createEncoder(init: EncoderInit): TEncoder;\n protected abstract getEncoderType(): string;\n\n // Hook for subclasses to handle reset\n protected onReset(): void {\n // Override in subclasses if needed\n }\n\n // Abstract properties for backpressure configuration\n protected abstract readonly highWaterMark: number;\n protected abstract readonly encodeQueueThreshold: number;\n\n /**\n * Create transform stream for encoding\n * Implements common stream logic with backpressure handling\n */\n createStream(): TransformStream<TInput, EncoderChunk> {\n return new TransformStream<TInput, EncoderChunk>(\n {\n start: async (controller) => {\n this.controller = controller;\n },\n\n transform: async (input) => {\n // Lazy init: create encoder on first frame or re-create after codec reclaim\n if (!this.isReady) {\n console.warn('Encoder is not ready, initializing 1...');\n await this.initialize();\n }\n\n // Backpressure: wait for encoder queue to drain\n if (this.encoder && this.encoder.encodeQueueSize >= this.encodeQueueThreshold) {\n await new Promise<void>((resolve) => {\n const check = () => {\n if (!this.encoder || this.encoder.encodeQueueSize < this.encodeQueueThreshold - 1) {\n resolve();\n } else {\n setTimeout(check, 10);\n }\n };\n check();\n });\n }\n\n // Re-check after backpressure await: codec may be reclaimed during the wait\n if (!this.isReady) {\n console.warn('Encoder is not ready, initializing 2...');\n await this.initialize();\n }\n if (!this.encoder || this.encoder.state !== 'configured') {\n console.error('Encoder not configured, throwing error');\n throw new Error('Encoder not configured');\n }\n\n const frame = (input as any).frame || input;\n this.encode(frame);\n },\n\n flush: async () => {\n await this.flush();\n },\n },\n // Queuing strategy with backpressure configuration\n {\n highWaterMark: this.highWaterMark,\n size: () => 1, // Count-based\n }\n );\n }\n\n // Abstract method for encoding\n abstract encode(input: TInput): void;\n}\n\ninterface EncoderInit {\n output: (chunk: any, metadata: any) => void;\n error: (error: DOMException) => void;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { StreamTarget, ArrayBufferTarget, Muxer } from "../../node_modules/.pnpm/mp4-muxer@5.2.2/node_modules/mp4-muxer/build/mp4-muxer.js";
|
|
1
|
+
import { StreamTarget, ArrayBufferTarget, Muxer } from "../../medeo-fe/node_modules/.pnpm/mp4-muxer@5.2.2/node_modules/mp4-muxer/build/mp4-muxer.js";
|
|
2
2
|
import { checkBrowserCompatibility } from "../../utils/platform-utils.js";
|
|
3
3
|
class MP4Muxer {
|
|
4
4
|
muxer;
|
package/dist/utils/mp4box.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as mp4box_all from "../node_modules/.pnpm/mp4box@0.5.4/node_modules/mp4box/dist/mp4box.all.js";
|
|
1
|
+
import * as mp4box_all from "../medeo-fe/node_modules/.pnpm/mp4box@0.5.4/node_modules/mp4box/dist/mp4box.all.js";
|
|
2
2
|
const lib = mp4box_all;
|
|
3
3
|
const MP4Box = lib.default && typeof lib.default.createFile === "function" ? lib.default : lib;
|
|
4
4
|
if (typeof MP4Box.createFile !== "function") {
|
|
@@ -2322,7 +2322,7 @@ class BaseEncoder {
|
|
|
2322
2322
|
return JSON.stringify(a) === JSON.stringify(b);
|
|
2323
2323
|
}
|
|
2324
2324
|
async initialize() {
|
|
2325
|
-
console.info("Encoder is initializing
|
|
2325
|
+
console.info("Encoder is initializing, config:", this.config);
|
|
2326
2326
|
if (this.encoder?.state === "configured") {
|
|
2327
2327
|
console.warn("Encoder is already initialized, skipping initialization");
|
|
2328
2328
|
return;
|
|
@@ -2439,6 +2439,7 @@ class BaseEncoder {
|
|
|
2439
2439
|
},
|
|
2440
2440
|
transform: async (input) => {
|
|
2441
2441
|
if (!this.isReady) {
|
|
2442
|
+
console.warn("Encoder is not ready, initializing 1...");
|
|
2442
2443
|
await this.initialize();
|
|
2443
2444
|
}
|
|
2444
2445
|
if (this.encoder && this.encoder.encodeQueueSize >= this.encodeQueueThreshold) {
|
|
@@ -2454,9 +2455,11 @@ class BaseEncoder {
|
|
|
2454
2455
|
});
|
|
2455
2456
|
}
|
|
2456
2457
|
if (!this.isReady) {
|
|
2458
|
+
console.warn("Encoder is not ready, initializing 2...");
|
|
2457
2459
|
await this.initialize();
|
|
2458
2460
|
}
|
|
2459
2461
|
if (!this.encoder || this.encoder.state !== "configured") {
|
|
2462
|
+
console.error("Encoder not configured, throwing error");
|
|
2460
2463
|
throw new Error("Encoder not configured");
|
|
2461
2464
|
}
|
|
2462
2465
|
const frame = input.frame || input;
|
|
@@ -3240,4 +3243,4 @@ const export_worker = null;
|
|
|
3240
3243
|
export {
|
|
3241
3244
|
export_worker as default
|
|
3242
3245
|
};
|
|
3243
|
-
//# sourceMappingURL=export.worker.
|
|
3246
|
+
//# sourceMappingURL=export.worker.DCStS1mL.js.map
|