@meframe/core 0.0.29 → 0.0.30
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 -30
- package/dist/Meframe.d.ts.map +1 -1
- package/dist/Meframe.js +7 -118
- package/dist/Meframe.js.map +1 -1
- package/dist/cache/CacheManager.d.ts +42 -68
- package/dist/cache/CacheManager.d.ts.map +1 -1
- package/dist/cache/CacheManager.js +224 -188
- package/dist/cache/CacheManager.js.map +1 -1
- package/dist/cache/l1/VideoL1Cache.d.ts +15 -2
- package/dist/cache/l1/VideoL1Cache.d.ts.map +1 -1
- package/dist/cache/l1/VideoL1Cache.js +58 -38
- package/dist/cache/l1/VideoL1Cache.js.map +1 -1
- package/dist/cache/l2/L2Cache.d.ts.map +1 -1
- package/dist/cache/l2/L2OPFSStore.d.ts +37 -0
- package/dist/cache/l2/L2OPFSStore.d.ts.map +1 -0
- package/dist/cache/resource/AudioSampleCache.d.ts +52 -0
- package/dist/cache/resource/AudioSampleCache.d.ts.map +1 -0
- package/dist/cache/resource/AudioSampleCache.js +69 -0
- package/dist/cache/resource/AudioSampleCache.js.map +1 -0
- package/dist/cache/resource/ImageBitmapCache.d.ts +65 -0
- package/dist/cache/resource/ImageBitmapCache.d.ts.map +1 -0
- package/dist/cache/resource/ImageBitmapCache.js +101 -0
- package/dist/cache/resource/ImageBitmapCache.js.map +1 -0
- package/dist/cache/resource/MP4IndexCache.d.ts +48 -0
- package/dist/cache/resource/MP4IndexCache.d.ts.map +1 -0
- package/dist/cache/resource/MP4IndexCache.js +104 -0
- package/dist/cache/resource/MP4IndexCache.js.map +1 -0
- package/dist/cache/resource/ResourceCache.d.ts +46 -0
- package/dist/cache/resource/ResourceCache.d.ts.map +1 -0
- package/dist/cache/resource/ResourceCache.js +92 -0
- package/dist/cache/resource/ResourceCache.js.map +1 -0
- package/dist/cache/storage/indexeddb/ChunkRecordStore.d.ts +75 -0
- package/dist/cache/storage/indexeddb/ChunkRecordStore.d.ts.map +1 -0
- package/dist/cache/storage/opfs/OPFSManager.d.ts +54 -0
- package/dist/cache/storage/opfs/OPFSManager.d.ts.map +1 -0
- package/dist/cache/storage/opfs/OPFSManager.js +133 -0
- package/dist/cache/storage/opfs/OPFSManager.js.map +1 -0
- package/dist/cache/storage/opfs/types.d.ts +16 -0
- package/dist/cache/storage/opfs/types.d.ts.map +1 -0
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +21 -2
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/types.d.ts +28 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/controllers/ExportController.d.ts +16 -0
- package/dist/controllers/ExportController.d.ts.map +1 -0
- package/dist/controllers/ExportController.js +44 -0
- package/dist/controllers/ExportController.js.map +1 -0
- package/dist/controllers/PlaybackController.d.ts +28 -4
- package/dist/controllers/PlaybackController.d.ts.map +1 -1
- package/dist/controllers/PlaybackController.js +115 -51
- package/dist/controllers/PlaybackController.js.map +1 -1
- package/dist/controllers/index.d.ts +2 -3
- package/dist/controllers/index.d.ts.map +1 -1
- package/dist/controllers/types.d.ts +0 -28
- package/dist/controllers/types.d.ts.map +1 -1
- package/dist/event/events.d.ts +8 -0
- package/dist/event/events.d.ts.map +1 -1
- package/dist/event/events.js +1 -0
- package/dist/event/events.js.map +1 -1
- package/dist/model/CompositionModel.d.ts.map +1 -1
- package/dist/model/CompositionModel.js +11 -6
- package/dist/model/CompositionModel.js.map +1 -1
- package/dist/model/RcFrame.d.ts +2 -0
- package/dist/model/RcFrame.d.ts.map +1 -1
- package/dist/model/RcFrame.js +3 -0
- package/dist/model/RcFrame.js.map +1 -1
- package/dist/model/types.d.ts +0 -1
- package/dist/model/types.d.ts.map +1 -1
- package/dist/model/types.js.map +1 -1
- package/dist/orchestrator/ExportScheduler.d.ts +35 -0
- package/dist/orchestrator/ExportScheduler.d.ts.map +1 -0
- package/dist/orchestrator/ExportScheduler.js +241 -0
- package/dist/orchestrator/ExportScheduler.js.map +1 -0
- package/dist/orchestrator/GlobalAudioSession.d.ts +24 -9
- package/dist/orchestrator/GlobalAudioSession.d.ts.map +1 -1
- package/dist/orchestrator/GlobalAudioSession.js +149 -152
- package/dist/orchestrator/GlobalAudioSession.js.map +1 -1
- package/dist/orchestrator/OnDemandVideoSession.d.ts +73 -0
- package/dist/orchestrator/OnDemandVideoSession.d.ts.map +1 -0
- package/dist/orchestrator/OnDemandVideoSession.js +281 -0
- package/dist/orchestrator/OnDemandVideoSession.js.map +1 -0
- package/dist/orchestrator/Orchestrator.d.ts +22 -17
- package/dist/orchestrator/Orchestrator.d.ts.map +1 -1
- package/dist/orchestrator/Orchestrator.js +244 -312
- package/dist/orchestrator/Orchestrator.js.map +1 -1
- package/dist/orchestrator/VideoClipSession.d.ts.map +1 -1
- package/dist/orchestrator/VideoClipSession.js +3 -15
- package/dist/orchestrator/VideoClipSession.js.map +1 -1
- package/dist/orchestrator/index.d.ts +0 -1
- package/dist/orchestrator/index.d.ts.map +1 -1
- package/dist/orchestrator/types.d.ts +4 -4
- package/dist/orchestrator/types.d.ts.map +1 -1
- package/dist/stages/compose/FilterProcessor.d.ts +1 -1
- package/dist/stages/compose/FilterProcessor.d.ts.map +1 -1
- package/dist/stages/compose/FilterProcessor.js +226 -0
- package/dist/stages/compose/FilterProcessor.js.map +1 -0
- package/dist/stages/compose/LayerRenderer.d.ts +1 -1
- package/dist/stages/compose/LayerRenderer.d.ts.map +1 -1
- package/dist/stages/compose/LayerRenderer.js +270 -0
- package/dist/stages/compose/LayerRenderer.js.map +1 -0
- package/dist/stages/compose/TransitionProcessor.d.ts +1 -1
- package/dist/stages/compose/TransitionProcessor.d.ts.map +1 -1
- package/dist/stages/compose/TransitionProcessor.js +189 -0
- package/dist/stages/compose/TransitionProcessor.js.map +1 -0
- package/dist/stages/compose/VideoComposer.d.ts +4 -2
- package/dist/stages/compose/VideoComposer.d.ts.map +1 -1
- package/dist/stages/compose/VideoComposer.js +229 -0
- package/dist/stages/compose/VideoComposer.js.map +1 -0
- package/dist/stages/compose/text-renderers/animation-utils.js +76 -0
- package/dist/stages/compose/text-renderers/animation-utils.js.map +1 -0
- package/dist/stages/compose/text-renderers/basic-text-renderer.d.ts +2 -2
- package/dist/stages/compose/text-renderers/basic-text-renderer.d.ts.map +1 -1
- package/dist/stages/compose/text-renderers/basic-text-renderer.js +93 -0
- package/dist/stages/compose/text-renderers/basic-text-renderer.js.map +1 -0
- package/dist/stages/compose/text-renderers/character-ktv-renderer.d.ts +1 -1
- package/dist/stages/compose/text-renderers/character-ktv-renderer.d.ts.map +1 -1
- package/dist/stages/compose/text-renderers/character-ktv-renderer.js +132 -0
- package/dist/stages/compose/text-renderers/character-ktv-renderer.js.map +1 -0
- package/dist/stages/compose/text-renderers/word-by-word-renderer.d.ts +1 -1
- package/dist/stages/compose/text-renderers/word-by-word-renderer.d.ts.map +1 -1
- package/dist/stages/compose/text-renderers/word-by-word-renderer.js +128 -0
- package/dist/stages/compose/text-renderers/word-by-word-renderer.js.map +1 -0
- package/dist/stages/compose/text-renderers/word-fancy-renderer.d.ts +1 -1
- package/dist/stages/compose/text-renderers/word-fancy-renderer.d.ts.map +1 -1
- package/dist/stages/compose/text-renderers/word-fancy-renderer.js +135 -0
- package/dist/stages/compose/text-renderers/word-fancy-renderer.js.map +1 -0
- package/dist/stages/compose/text-utils/locale-detector.js +16 -0
- package/dist/stages/compose/text-utils/locale-detector.js.map +1 -0
- package/dist/stages/compose/text-utils/text-metrics.js +21 -0
- package/dist/stages/compose/text-utils/text-metrics.js.map +1 -0
- package/dist/stages/compose/text-utils/text-wrapper.js +225 -0
- package/dist/stages/compose/text-utils/text-wrapper.js.map +1 -0
- package/dist/stages/compose/types.d.ts +2 -1
- package/dist/stages/compose/types.d.ts.map +1 -1
- package/dist/stages/decode/BaseDecoder.js +0 -3
- package/dist/stages/decode/BaseDecoder.js.map +1 -1
- package/dist/stages/demux/MP4Demuxer.d.ts +5 -0
- package/dist/stages/demux/MP4Demuxer.d.ts.map +1 -1
- package/dist/stages/demux/MP4Demuxer.js +281 -0
- package/dist/stages/demux/MP4Demuxer.js.map +1 -0
- package/dist/stages/demux/MP4IndexParser.d.ts +71 -0
- package/dist/stages/demux/MP4IndexParser.d.ts.map +1 -0
- package/dist/stages/demux/MP4IndexParser.js +416 -0
- package/dist/stages/demux/MP4IndexParser.js.map +1 -0
- package/dist/stages/demux/types.d.ts +48 -0
- package/dist/stages/demux/types.d.ts.map +1 -1
- package/dist/stages/load/ResourceLoader.d.ts +50 -15
- package/dist/stages/load/ResourceLoader.d.ts.map +1 -1
- package/dist/stages/load/ResourceLoader.js +297 -80
- package/dist/stages/load/ResourceLoader.js.map +1 -1
- package/dist/stages/load/TaskManager.d.ts +6 -2
- package/dist/stages/load/TaskManager.d.ts.map +1 -1
- package/dist/stages/load/TaskManager.js +27 -4
- package/dist/stages/load/TaskManager.js.map +1 -1
- package/dist/stages/load/index.d.ts +0 -1
- package/dist/stages/load/index.d.ts.map +1 -1
- package/dist/stages/load/types.d.ts +9 -9
- package/dist/stages/load/types.d.ts.map +1 -1
- package/dist/stages/mux/MP4Muxer.d.ts +2 -2
- package/dist/stages/mux/MP4Muxer.d.ts.map +1 -1
- package/dist/stages/mux/MP4Muxer.js +24 -13
- package/dist/stages/mux/MP4Muxer.js.map +1 -1
- package/dist/stages/mux/MuxManager.d.ts +10 -21
- package/dist/stages/mux/MuxManager.d.ts.map +1 -1
- package/dist/stages/mux/MuxManager.js +21 -162
- package/dist/stages/mux/MuxManager.js.map +1 -1
- package/dist/stages/mux/index.d.ts +0 -1
- package/dist/stages/mux/index.d.ts.map +1 -1
- package/dist/utils/binary-search.d.ts +12 -4
- package/dist/utils/binary-search.d.ts.map +1 -1
- package/dist/utils/binary-search.js +52 -6
- package/dist/utils/binary-search.js.map +1 -1
- package/dist/workers/{BaseDecoder.BWYu1W0B.js → BaseDecoder.CTW-vr29.js} +1 -4
- package/dist/workers/BaseDecoder.CTW-vr29.js.map +1 -0
- package/dist/workers/{MP4Demuxer.lMOUMWFh.js → MP4Demuxer.BEa6PLJm.js} +9 -2
- package/dist/workers/{MP4Demuxer.lMOUMWFh.js.map → MP4Demuxer.BEa6PLJm.js.map} +1 -1
- package/dist/workers/stages/compose/{video-compose.worker.CIeEIJO7.js → video-compose.worker.DHQ8B105.js} +59 -31
- package/dist/workers/stages/compose/video-compose.worker.DHQ8B105.js.map +1 -0
- package/dist/workers/stages/decode/{audio-decode.worker.DnS17GD9.js → audio-decode.worker.CP8bXXa4.js} +2 -2
- package/dist/workers/stages/decode/{audio-decode.worker.DnS17GD9.js.map → audio-decode.worker.CP8bXXa4.js.map} +1 -1
- package/dist/workers/stages/decode/{video-decode.worker.BEYsjOXp.js → video-decode.worker.BIspTxgV.js} +2 -2
- package/dist/workers/stages/decode/{video-decode.worker.BEYsjOXp.js.map → video-decode.worker.BIspTxgV.js.map} +1 -1
- package/dist/workers/stages/demux/{audio-demux.worker.DcurGC8i.js → audio-demux.worker._VRQdLdv.js} +2 -2
- package/dist/workers/stages/demux/{audio-demux.worker.DcurGC8i.js.map → audio-demux.worker._VRQdLdv.js.map} +1 -1
- package/dist/workers/stages/demux/{video-demux.worker.B1_wntU4.js → video-demux.worker.CSkxGtmx.js} +3 -19
- package/dist/workers/stages/demux/video-demux.worker.CSkxGtmx.js.map +1 -0
- package/dist/workers/worker-manifest.json +5 -5
- package/package.json +1 -1
- package/dist/cache/l2/IndexedDBStore.js +0 -180
- package/dist/cache/l2/IndexedDBStore.js.map +0 -1
- package/dist/cache/l2/L2Cache.js +0 -329
- package/dist/cache/l2/L2Cache.js.map +0 -1
- package/dist/cache/l2/OPFSStore.js +0 -131
- package/dist/cache/l2/OPFSStore.js.map +0 -1
- package/dist/controllers/PreRenderService.d.ts +0 -59
- package/dist/controllers/PreRenderService.d.ts.map +0 -1
- package/dist/controllers/PreRenderService.js +0 -185
- package/dist/controllers/PreRenderService.js.map +0 -1
- package/dist/controllers/PreRenderTaskQueue.d.ts +0 -21
- package/dist/controllers/PreRenderTaskQueue.d.ts.map +0 -1
- package/dist/orchestrator/ClipSessionManager.d.ts +0 -70
- package/dist/orchestrator/ClipSessionManager.d.ts.map +0 -1
- package/dist/orchestrator/ClipSessionManager.js +0 -158
- package/dist/orchestrator/ClipSessionManager.js.map +0 -1
- package/dist/stages/decode/AudioChunkDecoder.js +0 -169
- package/dist/stages/decode/AudioChunkDecoder.js.map +0 -1
- package/dist/stages/load/EventHandlers.d.ts +0 -26
- package/dist/stages/load/EventHandlers.d.ts.map +0 -1
- package/dist/stages/load/EventHandlers.js +0 -42
- package/dist/stages/load/EventHandlers.js.map +0 -1
- package/dist/stages/mux/OPFSWriter.d.ts +0 -46
- package/dist/stages/mux/OPFSWriter.d.ts.map +0 -1
- package/dist/utils/BackpressureAdapter.d.ts +0 -26
- package/dist/utils/BackpressureAdapter.d.ts.map +0 -1
- package/dist/workers/BaseDecoder.BWYu1W0B.js.map +0 -1
- package/dist/workers/stages/compose/video-compose.worker.CIeEIJO7.js.map +0 -1
- package/dist/workers/stages/demux/video-demux.worker.B1_wntU4.js.map +0 -1
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import { VideoClipSession } from "./VideoClipSession.js";
|
|
2
|
+
import { hasResourceId } from "../model/types.js";
|
|
3
|
+
import { MeframeEvent } from "../event/events.js";
|
|
4
|
+
class ExportScheduler {
|
|
5
|
+
deps;
|
|
6
|
+
constructor(deps) {
|
|
7
|
+
this.deps = deps;
|
|
8
|
+
}
|
|
9
|
+
async execute(model, options) {
|
|
10
|
+
const { muxManager, audioSession, resourceLoader, eventBus } = this.deps;
|
|
11
|
+
const signal = options.signal;
|
|
12
|
+
const controller = options.controller;
|
|
13
|
+
const checkStatus = async () => {
|
|
14
|
+
if (signal?.aborted) {
|
|
15
|
+
throw new DOMException("Export aborted", "AbortError");
|
|
16
|
+
}
|
|
17
|
+
if (controller?.isPaused()) {
|
|
18
|
+
while (controller.isPaused()) {
|
|
19
|
+
if (signal?.aborted) throw new DOMException("Export aborted", "AbortError");
|
|
20
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
const width = options.width || model.renderConfig?.width || 720;
|
|
25
|
+
const height = options.height || model.renderConfig?.height || 1280;
|
|
26
|
+
const fps = options.fps || model.fps || 30;
|
|
27
|
+
eventBus.emit(MeframeEvent.ExportStart, {
|
|
28
|
+
format: options.format || "mp4",
|
|
29
|
+
width,
|
|
30
|
+
height,
|
|
31
|
+
fps,
|
|
32
|
+
durationUs: model.durationUs
|
|
33
|
+
});
|
|
34
|
+
try {
|
|
35
|
+
muxManager.start({
|
|
36
|
+
width,
|
|
37
|
+
height,
|
|
38
|
+
fps
|
|
39
|
+
});
|
|
40
|
+
for (const track of model.tracks) {
|
|
41
|
+
if (track.kind === "audio") {
|
|
42
|
+
for (const clip of track.clips) {
|
|
43
|
+
if (hasResourceId(clip)) {
|
|
44
|
+
resourceLoader.fetch(clip.resourceId, {
|
|
45
|
+
priority: "high",
|
|
46
|
+
clipId: clip.id,
|
|
47
|
+
trackId: clip.trackId
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const videoTrack = model.tracks.find((t) => t.kind === "video");
|
|
54
|
+
if (videoTrack && videoTrack.clips.length > 0) {
|
|
55
|
+
await this.processVideoClipsSequentially(
|
|
56
|
+
videoTrack.clips,
|
|
57
|
+
muxManager,
|
|
58
|
+
model,
|
|
59
|
+
checkStatus,
|
|
60
|
+
audioSession
|
|
61
|
+
);
|
|
62
|
+
} else {
|
|
63
|
+
console.warn("[ExportScheduler] No video clips found");
|
|
64
|
+
}
|
|
65
|
+
await audioSession.finalizeExportAudio();
|
|
66
|
+
if (signal?.aborted) {
|
|
67
|
+
throw new DOMException("Export aborted", "AbortError");
|
|
68
|
+
}
|
|
69
|
+
const blob = await muxManager.finalize();
|
|
70
|
+
eventBus.emit(MeframeEvent.ExportComplete, {
|
|
71
|
+
size: blob.size,
|
|
72
|
+
durationMs: model.durationUs / 1e3,
|
|
73
|
+
format: options.format || "mp4"
|
|
74
|
+
});
|
|
75
|
+
return blob;
|
|
76
|
+
} catch (error) {
|
|
77
|
+
eventBus.emit(MeframeEvent.ExportError, {
|
|
78
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
79
|
+
stage: "export"
|
|
80
|
+
});
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
async processVideoClipsSequentially(clips, muxManager, model, checkStatus, audioSession) {
|
|
85
|
+
let accumulatedDurationUs = 0;
|
|
86
|
+
for (let i = 0; i < clips.length; i++) {
|
|
87
|
+
const clip = clips[i];
|
|
88
|
+
const nextClip = clips[i + 1];
|
|
89
|
+
await checkStatus();
|
|
90
|
+
if (nextClip && hasResourceId(nextClip)) {
|
|
91
|
+
this.deps.resourceLoader.fetch(nextClip.resourceId, {
|
|
92
|
+
priority: "normal",
|
|
93
|
+
clipId: nextClip.id,
|
|
94
|
+
trackId: nextClip.trackId,
|
|
95
|
+
isMainTrack: true
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
const sessionId = `${clip.id}-export`;
|
|
99
|
+
let streamFinishedResolver;
|
|
100
|
+
let streamFinishedRejecter;
|
|
101
|
+
const streamFinishedPromise = new Promise((resolve, reject) => {
|
|
102
|
+
streamFinishedResolver = resolve;
|
|
103
|
+
streamFinishedRejecter = reject;
|
|
104
|
+
});
|
|
105
|
+
let audioFinishedResolver;
|
|
106
|
+
const audioFinishedPromise = new Promise((resolve) => {
|
|
107
|
+
audioFinishedResolver = resolve;
|
|
108
|
+
});
|
|
109
|
+
let audioStreamStarted = false;
|
|
110
|
+
const session = await VideoClipSession.create({
|
|
111
|
+
clipId: clip.id,
|
|
112
|
+
sessionId,
|
|
113
|
+
forL2Only: true,
|
|
114
|
+
planner: this.deps.planner,
|
|
115
|
+
workerPool: this.deps.workerPool,
|
|
116
|
+
cacheManager: this.deps.cacheManager,
|
|
117
|
+
compositionModel: model,
|
|
118
|
+
workerConfigs: this.deps.workerConfigsProvider(),
|
|
119
|
+
callbacks: {
|
|
120
|
+
onComposedStreamReady: async () => {
|
|
121
|
+
},
|
|
122
|
+
onEncodedStreamReady: async (stream, track) => {
|
|
123
|
+
if (track === "video") {
|
|
124
|
+
const reader = stream.getReader();
|
|
125
|
+
try {
|
|
126
|
+
while (true) {
|
|
127
|
+
await checkStatus();
|
|
128
|
+
const { done, value } = await reader.read();
|
|
129
|
+
if (done) break;
|
|
130
|
+
if (value) {
|
|
131
|
+
const originalChunk = value.chunk;
|
|
132
|
+
const metadata = value.metadata;
|
|
133
|
+
const buffer = new ArrayBuffer(originalChunk.byteLength);
|
|
134
|
+
originalChunk.copyTo(buffer);
|
|
135
|
+
const remappedChunk = new EncodedVideoChunk({
|
|
136
|
+
type: originalChunk.type,
|
|
137
|
+
timestamp: originalChunk.timestamp + accumulatedDurationUs,
|
|
138
|
+
duration: originalChunk.duration ?? void 0,
|
|
139
|
+
data: buffer
|
|
140
|
+
});
|
|
141
|
+
muxManager.writeVideoChunk(remappedChunk, metadata);
|
|
142
|
+
const progress = Math.min(
|
|
143
|
+
1,
|
|
144
|
+
(accumulatedDurationUs + originalChunk.timestamp) / model.durationUs
|
|
145
|
+
);
|
|
146
|
+
this.deps.eventBus.emit(MeframeEvent.ExportProgress, {
|
|
147
|
+
progress,
|
|
148
|
+
stage: "muxing",
|
|
149
|
+
timeUs: accumulatedDurationUs + originalChunk.timestamp
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
streamFinishedResolver();
|
|
154
|
+
} catch (error) {
|
|
155
|
+
if (error instanceof DOMException && error.name === "AbortError") {
|
|
156
|
+
streamFinishedRejecter(error);
|
|
157
|
+
} else {
|
|
158
|
+
console.error(`[ExportScheduler] Stream error for clip ${clip.id}:`, error);
|
|
159
|
+
streamFinishedRejecter(error);
|
|
160
|
+
}
|
|
161
|
+
} finally {
|
|
162
|
+
reader.releaseLock();
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
onAudioStreamReady: (stream, metadata) => {
|
|
167
|
+
audioStreamStarted = true;
|
|
168
|
+
const reader = stream.getReader();
|
|
169
|
+
const pump = async () => {
|
|
170
|
+
try {
|
|
171
|
+
while (true) {
|
|
172
|
+
const { done, value } = await reader.read();
|
|
173
|
+
if (done) break;
|
|
174
|
+
if (value) {
|
|
175
|
+
this.deps.cacheManager.putClipAudioData(
|
|
176
|
+
clip.id,
|
|
177
|
+
// Use clip.id, NOT sessionId (which is clipId-export)
|
|
178
|
+
value,
|
|
179
|
+
metadata.clipDurationUs
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
} catch (e) {
|
|
184
|
+
console.error("[ExportScheduler] Audio stream error", e);
|
|
185
|
+
} finally {
|
|
186
|
+
reader.releaseLock();
|
|
187
|
+
audioFinishedResolver();
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
pump();
|
|
191
|
+
},
|
|
192
|
+
onPipelineReady: async (attachmentResourceIds) => {
|
|
193
|
+
if (hasResourceId(clip)) {
|
|
194
|
+
await this.deps.resourceLoader.fetch(clip.resourceId, {
|
|
195
|
+
priority: "high",
|
|
196
|
+
sessionId,
|
|
197
|
+
clipId: clip.id,
|
|
198
|
+
trackId: clip.trackId,
|
|
199
|
+
isMainTrack: true
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
if (attachmentResourceIds) {
|
|
203
|
+
for (const rid of attachmentResourceIds) {
|
|
204
|
+
await this.deps.resourceLoader.fetch(rid, {
|
|
205
|
+
priority: "normal",
|
|
206
|
+
sessionId,
|
|
207
|
+
clipId: clip.id,
|
|
208
|
+
isMainTrack: false
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
try {
|
|
216
|
+
await session.activate();
|
|
217
|
+
await streamFinishedPromise;
|
|
218
|
+
if (audioStreamStarted) {
|
|
219
|
+
await Promise.race([
|
|
220
|
+
audioFinishedPromise,
|
|
221
|
+
new Promise((resolve) => setTimeout(resolve, 5e3))
|
|
222
|
+
// 5s timeout for audio tail
|
|
223
|
+
]);
|
|
224
|
+
} else {
|
|
225
|
+
}
|
|
226
|
+
await audioSession.mixAndEncodeSegment(
|
|
227
|
+
accumulatedDurationUs,
|
|
228
|
+
accumulatedDurationUs + clip.durationUs,
|
|
229
|
+
(chunk, meta) => muxManager.writeAudioChunk(chunk, meta)
|
|
230
|
+
);
|
|
231
|
+
} finally {
|
|
232
|
+
await session.dispose();
|
|
233
|
+
}
|
|
234
|
+
accumulatedDurationUs += clip.durationUs;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
export {
|
|
239
|
+
ExportScheduler
|
|
240
|
+
};
|
|
241
|
+
//# sourceMappingURL=ExportScheduler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExportScheduler.js","sources":["../../src/orchestrator/ExportScheduler.ts"],"sourcesContent":["import { CompositionModel } 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 { GlobalAudioSession } from './GlobalAudioSession';\nimport { VideoClipSession } from './VideoClipSession';\nimport { WorkerType } from '../worker/types';\nimport { hasResourceId } from '../model/types';\nimport type { ExportController } from '../controllers/ExportController';\nimport { EventBus } from '../event/EventBus';\nimport { MeframeEvent, EventPayloadMap } from '../event/events';\n\ninterface ExportSchedulerDeps {\n workerPool: WorkerPool;\n planner: CompositionPlanner;\n cacheManager: CacheManager;\n resourceLoader: ResourceLoader;\n muxManager: MuxManager;\n audioSession: GlobalAudioSession;\n workerConfigsProvider: () => Record<WorkerType, any>;\n eventBus: EventBus<EventPayloadMap>;\n}\n\ninterface ExtendedExportOptions extends ExportOptions {\n signal?: AbortSignal;\n controller?: ExportController;\n}\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> {\n const { muxManager, audioSession, resourceLoader, eventBus } = this.deps;\n const signal = options.signal;\n const controller = options.controller;\n\n const checkStatus = async () => {\n if (signal?.aborted) {\n throw new DOMException('Export aborted', 'AbortError');\n }\n if (controller?.isPaused()) {\n // Wait until resumed\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 try {\n // 1. Start Muxer\n muxManager.start({\n width,\n height,\n fps,\n });\n\n // 2. Preload Audio Tracks (BGM/Speech)\n // Identify pure audio clips and start downloading them immediately\n // This ensures BGM is ready when we need to mix it with video clips\n for (const track of model.tracks) {\n if (track.kind === 'audio') {\n for (const clip of track.clips) {\n if (hasResourceId(clip)) {\n // Fire and forget - we don't await here, let them download in background\n // GlobalAudioSession will wait for them if needed during mixing\n resourceLoader.fetch(clip.resourceId, {\n priority: 'high',\n clipId: clip.id,\n trackId: clip.trackId,\n });\n }\n }\n }\n }\n\n // 3. Process Video Clips (Sequential) and Audio (Interleaved)\n const videoTrack = model.tracks.find((t) => t.kind === 'video');\n if (videoTrack && videoTrack.clips.length > 0) {\n await this.processVideoClipsSequentially(\n videoTrack.clips,\n muxManager,\n model,\n checkStatus,\n audioSession\n );\n } else {\n console.warn('[ExportScheduler] No video clips found');\n }\n\n // Finalize audio session (close encoder)\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,\n durationMs: model.durationUs / 1000,\n format: options.format || 'mp4',\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 }\n }\n\n private async processVideoClipsSequentially(\n clips: any[],\n muxManager: MuxManager,\n model: CompositionModel,\n checkStatus: () => Promise<void>,\n audioSession: GlobalAudioSession\n ) {\n let accumulatedDurationUs = 0;\n\n for (let i = 0; i < clips.length; i++) {\n const clip = clips[i];\n const nextClip = clips[i + 1];\n\n await checkStatus(); // Check before starting new clip\n\n // --- Preload Next Clip ---\n // Start downloading next clip's resource while current clip is processing\n if (nextClip && hasResourceId(nextClip)) {\n // Fire and forget - ResourceLoader handles deduping\n this.deps.resourceLoader.fetch(nextClip.resourceId, {\n priority: 'normal',\n clipId: nextClip.id,\n trackId: nextClip.trackId,\n isMainTrack: true,\n });\n }\n // -------------------------\n\n const sessionId = `${clip.id}-export`;\n let streamFinishedResolver: () => void;\n let streamFinishedRejecter: (err: any) => void;\n const streamFinishedPromise = new Promise<void>((resolve, reject) => {\n streamFinishedResolver = resolve;\n streamFinishedRejecter = reject;\n });\n\n let audioFinishedResolver: () => void;\n const audioFinishedPromise = new Promise<void>((resolve) => {\n audioFinishedResolver = resolve;\n });\n let audioStreamStarted = false;\n\n const session = await VideoClipSession.create({\n clipId: clip.id,\n sessionId,\n forL2Only: true,\n planner: this.deps.planner,\n workerPool: this.deps.workerPool,\n cacheManager: this.deps.cacheManager,\n compositionModel: model,\n workerConfigs: this.deps.workerConfigsProvider(),\n callbacks: {\n onComposedStreamReady: async () => {},\n onEncodedStreamReady: async (stream, track) => {\n if (track === 'video') {\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) {\n const originalChunk = value.chunk;\n const metadata = value.metadata;\n\n const buffer = new ArrayBuffer(originalChunk.byteLength);\n originalChunk.copyTo(buffer);\n\n const remappedChunk = new EncodedVideoChunk({\n type: originalChunk.type,\n timestamp: originalChunk.timestamp + accumulatedDurationUs,\n duration: originalChunk.duration ?? undefined,\n data: buffer,\n });\n\n muxManager.writeVideoChunk(remappedChunk, metadata);\n\n // Emit progress\n const progress = Math.min(\n 1.0,\n (accumulatedDurationUs + originalChunk.timestamp) / model.durationUs\n );\n this.deps.eventBus.emit(MeframeEvent.ExportProgress, {\n progress,\n stage: 'muxing',\n timeUs: accumulatedDurationUs + originalChunk.timestamp,\n });\n }\n }\n streamFinishedResolver();\n } catch (error) {\n if (error instanceof DOMException && error.name === 'AbortError') {\n streamFinishedRejecter(error);\n } else {\n console.error(`[ExportScheduler] Stream error for clip ${clip.id}:`, error);\n streamFinishedRejecter(error);\n }\n } finally {\n reader.releaseLock();\n }\n }\n },\n onAudioStreamReady: (stream, metadata) => {\n audioStreamStarted = true;\n // Handle audio stream from VideoClipSession (AudioDecodeWorker)\n const reader = stream.getReader();\n const pump = async () => {\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n if (value) {\n // Put into CacheManager immediately so GlobalAudioSession can find it\n // Use clipId as sessionId because GlobalAudioSession expects that\n this.deps.cacheManager.putClipAudioData(\n clip.id, // Use clip.id, NOT sessionId (which is clipId-export)\n value,\n metadata.clipDurationUs\n );\n }\n }\n } catch (e) {\n console.error('[ExportScheduler] Audio stream error', e);\n } finally {\n reader.releaseLock();\n audioFinishedResolver(); // Signal audio stream completion\n }\n };\n pump();\n },\n onPipelineReady: async (attachmentResourceIds) => {\n // Load Main Track Resource\n if (hasResourceId(clip)) {\n await this.deps.resourceLoader.fetch(clip.resourceId, {\n priority: 'high',\n sessionId,\n clipId: clip.id,\n trackId: clip.trackId,\n isMainTrack: true,\n });\n }\n\n // Load Attachment Resources\n if (attachmentResourceIds) {\n for (const rid of attachmentResourceIds) {\n await this.deps.resourceLoader.fetch(rid, {\n priority: 'normal',\n sessionId,\n clipId: clip.id,\n isMainTrack: false,\n });\n }\n }\n },\n },\n });\n\n try {\n await session.activate();\n\n await streamFinishedPromise;\n\n // If audio stream started, we wait for it to finish.\n // This ensures we capture the tail of the audio.\n if (audioStreamStarted) {\n // Use a race with timeout to prevent hanging indefinitely if audio stream is stuck\n await Promise.race([\n audioFinishedPromise,\n new Promise((resolve) => setTimeout(resolve, 5000)), // 5s timeout for audio tail\n ]);\n } else {\n // If audio didn't start, maybe it's a silent clip, or audio init failed.\n // We just proceed.\n }\n\n // Mix and encode audio for this segment\n await audioSession.mixAndEncodeSegment(\n accumulatedDurationUs,\n accumulatedDurationUs + clip.durationUs,\n (chunk, meta) => muxManager.writeAudioChunk(chunk, meta)\n );\n } finally {\n await session.dispose();\n }\n\n accumulatedDurationUs += clip.durationUs;\n }\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -14,10 +14,9 @@ interface AudioDataMessage {
|
|
|
14
14
|
}
|
|
15
15
|
interface AudioSessionDeps {
|
|
16
16
|
cacheManager: CacheManager;
|
|
17
|
-
|
|
17
|
+
workerPool: WorkerPool;
|
|
18
18
|
resourceLoader: ResourceLoader;
|
|
19
19
|
eventBus: EventBus<EventPayloadMap>;
|
|
20
|
-
getModel: () => CompositionModel | null;
|
|
21
20
|
buildWorkerConfigs: () => any;
|
|
22
21
|
}
|
|
23
22
|
export declare class GlobalAudioSession {
|
|
@@ -25,6 +24,7 @@ export declare class GlobalAudioSession {
|
|
|
25
24
|
private activeClips;
|
|
26
25
|
private streamEndedClips;
|
|
27
26
|
private deps;
|
|
27
|
+
private model;
|
|
28
28
|
private audioContext;
|
|
29
29
|
private audioSources;
|
|
30
30
|
private audioGainNodes;
|
|
@@ -32,9 +32,11 @@ export declare class GlobalAudioSession {
|
|
|
32
32
|
private playbackRate;
|
|
33
33
|
private isPlaying;
|
|
34
34
|
private currentPlaybackTimeUs;
|
|
35
|
-
private
|
|
35
|
+
private ensuringClips;
|
|
36
36
|
constructor(deps: AudioSessionDeps);
|
|
37
|
+
setModel(model: CompositionModel): void;
|
|
37
38
|
onAudioData(message: AudioDataMessage): void;
|
|
39
|
+
ensureAudioForTime(timeUs: TimeUs): Promise<void>;
|
|
38
40
|
activateAllAudioClips(): Promise<void>;
|
|
39
41
|
deactivateClip(clipId: string): Promise<void>;
|
|
40
42
|
restartPlayingClip(clipId: string, currentTimeUs?: TimeUs): void;
|
|
@@ -47,9 +49,14 @@ export declare class GlobalAudioSession {
|
|
|
47
49
|
setPlaybackRate(rate: number): void;
|
|
48
50
|
reset(): void;
|
|
49
51
|
/**
|
|
50
|
-
*
|
|
52
|
+
* Mix and encode audio for a specific segment (used by ExportScheduler)
|
|
51
53
|
*/
|
|
52
|
-
|
|
54
|
+
mixAndEncodeSegment(startUs: TimeUs, endUs: TimeUs, onChunk: (chunk: EncodedAudioChunk, metadata?: EncodedAudioChunkMetadata) => void): Promise<void>;
|
|
55
|
+
private exportEncoder;
|
|
56
|
+
private exportEncoderStream;
|
|
57
|
+
private exportEncoderWriter;
|
|
58
|
+
private startExportEncoderReader;
|
|
59
|
+
finalizeExportAudio(): Promise<void>;
|
|
53
60
|
/**
|
|
54
61
|
* Create export audio stream
|
|
55
62
|
*/
|
|
@@ -59,14 +66,22 @@ export declare class GlobalAudioSession {
|
|
|
59
66
|
private startAllActiveClips;
|
|
60
67
|
private checkAndStartNewClips;
|
|
61
68
|
private startClipPlayback;
|
|
62
|
-
private continueClipPlayback;
|
|
63
69
|
private stopAllAudioSources;
|
|
64
70
|
private getActiveAudioClips;
|
|
65
71
|
/**
|
|
66
|
-
* Ensure PCM for a clip is available
|
|
67
|
-
*
|
|
72
|
+
* Ensure PCM for a clip is available
|
|
73
|
+
* Priority: AudioSampleCache (Resource) > L2 > None
|
|
68
74
|
*/
|
|
69
|
-
|
|
75
|
+
ensureClipAudio(clipId: string): Promise<void>;
|
|
76
|
+
/**
|
|
77
|
+
* Ensure PCM from AudioSampleCache (Resource-level)
|
|
78
|
+
* Returns true if successful
|
|
79
|
+
*/
|
|
80
|
+
private ensureClipAudioFromResource;
|
|
81
|
+
/**
|
|
82
|
+
* Decode audio samples to PCM and cache
|
|
83
|
+
*/
|
|
84
|
+
private decodeAudioSamples;
|
|
70
85
|
private pcmToAudioBuffer;
|
|
71
86
|
private audioBufferToAudioData;
|
|
72
87
|
private interleavePlanarData;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GlobalAudioSession.d.ts","sourceRoot":"","sources":["../../src/orchestrator/GlobalAudioSession.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAa,MAAM,gBAAgB,CAAC;AAExD,OAAO,KAAK,EAAE,gBAAgB,EAAQ,MAAM,UAAU,CAAC;AACvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"GlobalAudioSession.d.ts","sourceRoot":"","sources":["../../src/orchestrator/GlobalAudioSession.ts"],"names":[],"mappings":"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"}
|