@meframe/core 0.0.28 → 0.0.30-beta
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 -13
- package/dist/Meframe.d.ts.map +1 -1
- package/dist/Meframe.js +6 -100
- package/dist/Meframe.js.map +1 -1
- package/dist/cache/CacheManager.d.ts +35 -19
- package/dist/cache/CacheManager.d.ts.map +1 -1
- package/dist/cache/CacheManager.js +223 -134
- 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/L2Cache.js +5 -5
- package/dist/cache/l2/L2Cache.js.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/l2/L2OPFSStore.js +89 -0
- package/dist/cache/l2/L2OPFSStore.js.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/{l2/IndexedDBStore.js → storage/indexeddb/ChunkRecordStore.js} +3 -3
- package/dist/cache/storage/indexeddb/ChunkRecordStore.js.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 +117 -52
- 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/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 +21 -7
- package/dist/orchestrator/GlobalAudioSession.d.ts.map +1 -1
- package/dist/orchestrator/GlobalAudioSession.js +132 -140
- 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 +234 -301
- 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/FrameRateConverter.d.ts +68 -0
- package/dist/stages/compose/FrameRateConverter.d.ts.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 +6 -4
- 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/encode/index.d.ts +0 -1
- package/dist/stages/encode/index.d.ts.map +1 -1
- package/dist/stages/load/ResourceLoader.d.ts +44 -2
- package/dist/stages/load/ResourceLoader.d.ts.map +1 -1
- package/dist/stages/load/ResourceLoader.js +281 -37
- 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/types.d.ts +7 -0
- 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.CFHDkPYc.js → MP4Demuxer.BEa6PLJm.js} +10 -3
- package/dist/workers/{MP4Demuxer.CFHDkPYc.js.map → MP4Demuxer.BEa6PLJm.js.map} +1 -1
- package/dist/workers/stages/compose/{video-compose.worker.M5uomNVr.js → video-compose.worker.DHQ8B105.js} +260 -83
- 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.BTFPcY7P.js → audio-demux.worker._VRQdLdv.js} +2 -2
- package/dist/workers/stages/demux/{audio-demux.worker.BTFPcY7P.js.map → audio-demux.worker._VRQdLdv.js.map} +1 -1
- package/dist/workers/stages/demux/{video-demux.worker.D_WeHPkt.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.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/encode/ClipEncoderManager.d.ts +0 -64
- package/dist/stages/encode/ClipEncoderManager.d.ts.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/utils/time-utils.js +0 -45
- package/dist/utils/time-utils.js.map +0 -1
- package/dist/workers/BaseDecoder.BWYu1W0B.js.map +0 -1
- package/dist/workers/stages/compose/video-compose.worker.M5uomNVr.js.map +0 -1
- package/dist/workers/stages/demux/video-demux.worker.D_WeHPkt.js.map +0 -1
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
import { EventBus } from "../event/EventBus.js";
|
|
2
2
|
import { WorkerPool } from "../worker/WorkerPool.js";
|
|
3
3
|
import { applyPatch } from "../model/patch.js";
|
|
4
|
-
import { ResourceLoader
|
|
4
|
+
import { ResourceLoader } from "../stages/load/ResourceLoader.js";
|
|
5
5
|
import { CacheManager } from "../cache/CacheManager.js";
|
|
6
6
|
import { ConfigLoader } from "../config/ConfigLoader.js";
|
|
7
|
-
import { hasResourceId } from "../model/types.js";
|
|
7
|
+
import { isVideoClip, hasResourceId } from "../model/types.js";
|
|
8
8
|
import { MeframeEvent } from "../event/events.js";
|
|
9
9
|
import { CompositionPlanner } from "./CompositionPlanner.js";
|
|
10
|
-
import { VideoClipSession } from "./VideoClipSession.js";
|
|
11
|
-
import { ClipSessionManager } from "./ClipSessionManager.js";
|
|
12
10
|
import { GlobalAudioSession } from "./GlobalAudioSession.js";
|
|
13
11
|
import { MuxManager } from "../stages/mux/MuxManager.js";
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
12
|
+
import { OnDemandVideoSession } from "./OnDemandVideoSession.js";
|
|
13
|
+
import { ExportScheduler } from "./ExportScheduler.js";
|
|
16
14
|
class Orchestrator {
|
|
17
15
|
workers;
|
|
18
16
|
eventBus;
|
|
@@ -22,13 +20,11 @@ class Orchestrator {
|
|
|
22
20
|
planner;
|
|
23
21
|
audioSession;
|
|
24
22
|
muxManager;
|
|
25
|
-
|
|
23
|
+
exportScheduler;
|
|
26
24
|
isInitialized = false;
|
|
27
25
|
config = ConfigLoader.getInstance().getConfig();
|
|
28
|
-
clipSessionManager;
|
|
29
|
-
currentClipId = null;
|
|
30
26
|
ensureCacheDebounceTimer = null;
|
|
31
|
-
|
|
27
|
+
currentClipId = null;
|
|
32
28
|
events;
|
|
33
29
|
constructor(config) {
|
|
34
30
|
this.eventBus = config.eventBus || new EventBus();
|
|
@@ -64,13 +60,6 @@ class Orchestrator {
|
|
|
64
60
|
},
|
|
65
61
|
this.eventBus
|
|
66
62
|
);
|
|
67
|
-
this.clipSessionManager = new ClipSessionManager({
|
|
68
|
-
maxConcurrent: 2,
|
|
69
|
-
factory: {
|
|
70
|
-
createSession: (clipId) => this.createSession(clipId)
|
|
71
|
-
},
|
|
72
|
-
cacheManager: this.cacheManager
|
|
73
|
-
});
|
|
74
63
|
this.audioSession = new GlobalAudioSession({
|
|
75
64
|
cacheManager: this.cacheManager,
|
|
76
65
|
workers: this.workers,
|
|
@@ -84,26 +73,48 @@ class Orchestrator {
|
|
|
84
73
|
this.audioSession,
|
|
85
74
|
this.config.encode.audio
|
|
86
75
|
);
|
|
76
|
+
this.exportScheduler = new ExportScheduler({
|
|
77
|
+
workerPool: this.workers,
|
|
78
|
+
planner: this.planner,
|
|
79
|
+
cacheManager: this.cacheManager,
|
|
80
|
+
resourceLoader: this.resourceLoader,
|
|
81
|
+
muxManager: this.muxManager,
|
|
82
|
+
audioSession: this.audioSession,
|
|
83
|
+
workerConfigsProvider: () => this.buildWorkerConfigs(),
|
|
84
|
+
eventBus: this.eventBus
|
|
85
|
+
});
|
|
86
|
+
this.setupResourceFirstFrameHandler();
|
|
87
|
+
this.setupPreloadHandlers();
|
|
87
88
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
89
|
+
setupResourceFirstFrameHandler() {
|
|
90
|
+
this.eventBus.on(MeframeEvent.ResourceFirstFrameReady, async (payload) => {
|
|
91
|
+
const { resourceId, clipId, index, chunks } = payload;
|
|
92
|
+
if (!this.compositionModel) return;
|
|
93
|
+
const clip = this.compositionModel.findClip(clipId);
|
|
94
|
+
if (!clip || !clip.trackId) return;
|
|
95
|
+
if (clip.startUs === 0) {
|
|
96
|
+
const fps = this.compositionModel.fps ?? 30;
|
|
97
|
+
await OnDemandVideoSession.decodeAndCacheFirstFrame(
|
|
98
|
+
resourceId,
|
|
99
|
+
chunks,
|
|
100
|
+
index,
|
|
101
|
+
clip,
|
|
102
|
+
this.cacheManager,
|
|
103
|
+
fps
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
setupPreloadHandlers() {
|
|
109
|
+
this.eventBus.on(MeframeEvent.PlaybackPlay, () => {
|
|
110
|
+
this.resourceLoader.setPreloadingEnabled(false);
|
|
111
|
+
});
|
|
112
|
+
this.eventBus.on(MeframeEvent.PlaybackPause, () => {
|
|
113
|
+
this.resourceLoader.setPreloadingEnabled(true);
|
|
114
|
+
});
|
|
115
|
+
this.eventBus.on(MeframeEvent.PlaybackStop, () => {
|
|
116
|
+
this.resourceLoader.setPreloadingEnabled(true);
|
|
117
|
+
});
|
|
107
118
|
}
|
|
108
119
|
async initialize() {
|
|
109
120
|
if (this.isInitialized) return;
|
|
@@ -130,31 +141,25 @@ class Orchestrator {
|
|
|
130
141
|
}
|
|
131
142
|
this.compositionModel = model;
|
|
132
143
|
this.planner.setModel(model);
|
|
133
|
-
this.currentClipId = null;
|
|
134
144
|
this.eventBus.emit(MeframeEvent.ModelSet, model);
|
|
135
145
|
this.eventBus.emit(MeframeEvent.CompositionUpdated, {
|
|
136
146
|
trackCount: model.tracks.length,
|
|
137
147
|
clipCount: model.tracks.reduce((acc, track) => acc + track.clips.length, 0),
|
|
138
148
|
durationUs: model.durationUs
|
|
139
149
|
});
|
|
140
|
-
await this.audioSession.activateAllAudioClips();
|
|
141
150
|
}
|
|
142
151
|
async applyPatch(patch) {
|
|
143
152
|
if (!this.compositionModel) {
|
|
144
153
|
throw new Error("No composition model set");
|
|
145
154
|
}
|
|
146
155
|
const affectedClipIds = applyPatch(this.compositionModel, patch);
|
|
147
|
-
|
|
156
|
+
this.planner.applyPatch(patch, affectedClipIds);
|
|
148
157
|
this.eventBus.emit(MeframeEvent.PatchApplied, {
|
|
149
158
|
operations: patch.operations.length,
|
|
150
159
|
affectedClips: Array.from(affectedClipIds)
|
|
151
160
|
});
|
|
152
|
-
for (const
|
|
153
|
-
|
|
154
|
-
this.activeClips.delete(update.clipId);
|
|
155
|
-
}
|
|
156
|
-
this.cacheManager.invalidateClip(update.clipId);
|
|
157
|
-
await this.clipSessionManager.handlePlannerUpdate(update.clipId, update);
|
|
161
|
+
for (const clipId of affectedClipIds) {
|
|
162
|
+
this.cacheManager.invalidateClip(clipId);
|
|
158
163
|
}
|
|
159
164
|
const reactivatedAudioClips = [];
|
|
160
165
|
const reactivatedVideoClips = [];
|
|
@@ -185,62 +190,10 @@ class Orchestrator {
|
|
|
185
190
|
if (state !== "ready") {
|
|
186
191
|
return;
|
|
187
192
|
}
|
|
188
|
-
const resource = this.compositionModel.getResource(resourceId);
|
|
189
|
-
if (!resource) {
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
if (resource.type === "video" || resource.type === "audio") {
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
|
-
const clipIds = this.compositionModel.getClipIdsByResourceId(resourceId);
|
|
196
|
-
for (const clipId of clipIds) {
|
|
197
|
-
if (!this.clipSessionManager.isClipActive(clipId)) {
|
|
198
|
-
continue;
|
|
199
|
-
}
|
|
200
|
-
const clip = this.compositionModel.findClip(clipId);
|
|
201
|
-
if (!clip) {
|
|
202
|
-
continue;
|
|
203
|
-
}
|
|
204
|
-
const instructions = this.planner.getInstructions(clipId);
|
|
205
|
-
if (!instructions) {
|
|
206
|
-
continue;
|
|
207
|
-
}
|
|
208
|
-
const session = this.clipSessionManager.getSession(clipId);
|
|
209
|
-
const composeWorker = session?.composeWorker;
|
|
210
|
-
if (composeWorker) {
|
|
211
|
-
composeWorker.send("install_instructions", instructions);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
async restartWorker(type, clipId) {
|
|
216
|
-
const clipLocalTypes = [
|
|
217
|
-
"videoDemux",
|
|
218
|
-
"audioDemux",
|
|
219
|
-
"videoDecode",
|
|
220
|
-
"audioDecode",
|
|
221
|
-
"videoCompose",
|
|
222
|
-
"videoEncode"
|
|
223
|
-
];
|
|
224
|
-
if (clipLocalTypes.includes(type) && !clipId) {
|
|
225
|
-
throw new Error(`clipId required for restarting ${type} worker`);
|
|
226
|
-
}
|
|
227
|
-
this.workers.terminate(type, clipId);
|
|
228
|
-
const worker = await this.workers.getOrCreate(type, clipId);
|
|
229
|
-
this.eventBus.emit(MeframeEvent.WorkerRestarted, {
|
|
230
|
-
type,
|
|
231
|
-
workerId: worker.getWorkerId(),
|
|
232
|
-
reason: "Manual restart"
|
|
233
|
-
});
|
|
234
|
-
if (clipId) {
|
|
235
|
-
const session = this.clipSessionManager.getSession(clipId);
|
|
236
|
-
if (session) {
|
|
237
|
-
await session.activate();
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
193
|
}
|
|
241
|
-
async
|
|
194
|
+
async getFrame(timeUs, options) {
|
|
242
195
|
const signal = options?.signal;
|
|
243
|
-
const
|
|
196
|
+
const preheat = options?.preheat ?? false;
|
|
244
197
|
if (!this.compositionModel) {
|
|
245
198
|
throw new Error("No composition model set");
|
|
246
199
|
}
|
|
@@ -248,113 +201,89 @@ class Orchestrator {
|
|
|
248
201
|
if (!clip) {
|
|
249
202
|
return null;
|
|
250
203
|
}
|
|
251
|
-
if (this.currentClipId !== clip.id) {
|
|
252
|
-
this.currentClipId = clip.id;
|
|
253
|
-
void this.ensureClipCache(timeUs, immediate);
|
|
254
|
-
}
|
|
255
204
|
let relativeTimeUs = options?.relativeTimeUs ?? timeUs - clip.startUs;
|
|
256
|
-
relativeTimeUs = quantizeTimestampToFrame(relativeTimeUs, 0, this.compositionModel.fps);
|
|
257
205
|
relativeTimeUs = Math.min(relativeTimeUs, clip.durationUs - 1);
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
this.
|
|
206
|
+
if (!preheat) {
|
|
207
|
+
this.cacheManager.setWindow(timeUs);
|
|
208
|
+
const cachedFrame = this.cacheManager.getFrame(relativeTimeUs, clip.id);
|
|
209
|
+
if (cachedFrame) {
|
|
210
|
+
this.preheatNextClip(clip);
|
|
211
|
+
this.eventBus.emit(MeframeEvent.CacheHit, {
|
|
212
|
+
timeUs,
|
|
213
|
+
level: "L1",
|
|
214
|
+
key: `${clip.id}-${relativeTimeUs}`
|
|
215
|
+
});
|
|
216
|
+
return cachedFrame;
|
|
217
|
+
}
|
|
218
|
+
this.eventBus.emit(MeframeEvent.CacheMiss, {
|
|
261
219
|
timeUs,
|
|
262
220
|
level: "L1",
|
|
263
221
|
key: `${clip.id}-${relativeTimeUs}`
|
|
264
222
|
});
|
|
265
|
-
return cachedFrame;
|
|
266
223
|
}
|
|
267
|
-
this.eventBus.emit(MeframeEvent.CacheMiss, {
|
|
268
|
-
timeUs,
|
|
269
|
-
level: "L1",
|
|
270
|
-
key: `${clip.id}-${relativeTimeUs}`
|
|
271
|
-
});
|
|
272
224
|
if (signal?.aborted) {
|
|
273
225
|
throw new DOMException("Render aborted", "AbortError");
|
|
274
226
|
}
|
|
275
|
-
const
|
|
276
|
-
|
|
277
|
-
void this.ensureAudioFromL2(clip.id);
|
|
278
|
-
return l2Frame;
|
|
279
|
-
}
|
|
280
|
-
return null;
|
|
281
|
-
}
|
|
282
|
-
async ensureAudioFromL2(clipId) {
|
|
283
|
-
try {
|
|
284
|
-
if (this.cacheManager.hasClipPCM(clipId)) {
|
|
285
|
-
return;
|
|
286
|
-
}
|
|
287
|
-
const hasAudio = await this.cacheManager.hasClipInL2(clipId, "audio");
|
|
288
|
-
if (!hasAudio) return;
|
|
289
|
-
await this.audioSession.ensureClipAudioFromL2(clipId);
|
|
290
|
-
} catch (error) {
|
|
291
|
-
console.warn("[Orchestrator] ensureAudioFromL2IfNeeded error:", error);
|
|
292
|
-
}
|
|
227
|
+
const resourceFrame = await this.decodeFromResource(clip, relativeTimeUs, timeUs, options);
|
|
228
|
+
return resourceFrame;
|
|
293
229
|
}
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
const
|
|
298
|
-
|
|
299
|
-
this.
|
|
300
|
-
]
|
|
301
|
-
if (
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
width: metadata.codedWidth,
|
|
307
|
-
height: metadata.codedHeight,
|
|
308
|
-
description: metadata.description,
|
|
309
|
-
hardwareAcceleration: metadata.hardwareAcceleration || "no-preference",
|
|
310
|
-
thread: "main"
|
|
311
|
-
});
|
|
312
|
-
try {
|
|
313
|
-
const decodeStream = chunkStream.pipeThrough(decoder.createStream());
|
|
314
|
-
let targetFrame = null;
|
|
315
|
-
await this.cacheManager.receiveComposedFrames(decodeStream, {
|
|
316
|
-
clipId: id,
|
|
317
|
-
trackId: trackId || this.compositionModel?.mainTrackId || "main",
|
|
318
|
-
fps: this.compositionModel?.fps ?? 30,
|
|
319
|
-
clipStartUs: startUs,
|
|
320
|
-
onFrame: (info) => {
|
|
321
|
-
if (info.timeUs === timeUs) {
|
|
322
|
-
targetFrame = this.cacheManager.getFrame(timeUs, id);
|
|
323
|
-
}
|
|
324
|
-
}
|
|
230
|
+
async preheatNextClip(clip) {
|
|
231
|
+
if (clip.id === this.currentClipId) return;
|
|
232
|
+
this.currentClipId = clip.id;
|
|
233
|
+
const nextClip = this.compositionModel?.getClipsAtTime(
|
|
234
|
+
clip.startUs + clip.durationUs,
|
|
235
|
+
this.compositionModel?.mainTrackId
|
|
236
|
+
)[0];
|
|
237
|
+
if (nextClip && isVideoClip(nextClip)) {
|
|
238
|
+
this.resourceLoader.fetch(nextClip.resourceId, {
|
|
239
|
+
priority: "normal",
|
|
240
|
+
clipId: nextClip.id,
|
|
241
|
+
trackId: nextClip.trackId
|
|
325
242
|
});
|
|
326
|
-
return targetFrame;
|
|
327
|
-
} finally {
|
|
328
|
-
await decoder.close();
|
|
329
243
|
}
|
|
330
244
|
}
|
|
331
245
|
/**
|
|
332
|
-
*
|
|
333
|
-
*
|
|
334
|
-
* @param timeUs - Target time for cache window
|
|
335
|
-
* @param immediate - Skip debounce if true (used for initial load)
|
|
246
|
+
* Compose frame from OPFS resource (on-demand decoding)
|
|
247
|
+
* This is the new path for long clips with window caching
|
|
336
248
|
*/
|
|
337
|
-
async
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
249
|
+
async decodeFromResource(clip, relativeTimeUs, globalTimeUs, options) {
|
|
250
|
+
if (!hasResourceId(clip)) return null;
|
|
251
|
+
const resourceId = clip.resourceId;
|
|
252
|
+
const resource = this.compositionModel?.getResource(resourceId);
|
|
253
|
+
const isReady = resource?.state === "ready";
|
|
254
|
+
const fetchOptions = {
|
|
255
|
+
priority: "high",
|
|
256
|
+
clipId: clip.id,
|
|
257
|
+
trackId: clip.trackId
|
|
343
258
|
};
|
|
344
|
-
if (
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
}
|
|
348
|
-
if (immediate) {
|
|
349
|
-
return executeCache();
|
|
259
|
+
if (options?.immediate && !isReady) {
|
|
260
|
+
this.resourceLoader.fetch(resourceId, fetchOptions);
|
|
261
|
+
return null;
|
|
350
262
|
}
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
263
|
+
await this.resourceLoader.fetch(resourceId, fetchOptions);
|
|
264
|
+
const session = await OnDemandVideoSession.create({
|
|
265
|
+
clipId: clip.id,
|
|
266
|
+
resourceId,
|
|
267
|
+
targetTimeUs: relativeTimeUs,
|
|
268
|
+
globalTimeUs,
|
|
269
|
+
resourceCache: this.cacheManager.resourceCache,
|
|
270
|
+
mp4IndexCache: this.cacheManager.mp4IndexCache,
|
|
271
|
+
cacheManager: this.cacheManager,
|
|
272
|
+
compositionModel: this.compositionModel,
|
|
273
|
+
fps: this.compositionModel?.fps ?? 30
|
|
357
274
|
});
|
|
275
|
+
try {
|
|
276
|
+
const DECODE_WINDOW_SIZE = 3e6;
|
|
277
|
+
const windowStart = relativeTimeUs;
|
|
278
|
+
const windowEnd = Math.min(clip.durationUs, relativeTimeUs + DECODE_WINDOW_SIZE);
|
|
279
|
+
await session.decodeWindow(windowStart, windowEnd);
|
|
280
|
+
return this.cacheManager.getFrame(relativeTimeUs, clip.id);
|
|
281
|
+
} catch (error) {
|
|
282
|
+
console.error("[Orchestrator] Error composing from resource:", error);
|
|
283
|
+
return null;
|
|
284
|
+
} finally {
|
|
285
|
+
await session.dispose();
|
|
286
|
+
}
|
|
358
287
|
}
|
|
359
288
|
/**
|
|
360
289
|
* Wait for clip cache to be ready for playback
|
|
@@ -375,115 +304,7 @@ class Orchestrator {
|
|
|
375
304
|
return this.cacheManager.waitForClipReady(currentClip.id, {
|
|
376
305
|
minFrameCount: options?.minFrameCount ?? 5,
|
|
377
306
|
timeoutMs: options?.timeoutMs ?? 5e3
|
|
378
|
-
// Don't pass startTimeUs - count all frames in the clip
|
|
379
|
-
});
|
|
380
|
-
}
|
|
381
|
-
// TODO: move to @ClipSessionManager
|
|
382
|
-
async renderClipForL2(clipId) {
|
|
383
|
-
const sessionId = `${clipId}#l2`;
|
|
384
|
-
let session = null;
|
|
385
|
-
return new Promise((resolve, reject) => {
|
|
386
|
-
this.createSession(sessionId, {
|
|
387
|
-
forL2Only: true,
|
|
388
|
-
clipId,
|
|
389
|
-
onL2Complete: () => {
|
|
390
|
-
resolve(true);
|
|
391
|
-
},
|
|
392
|
-
onL2Error: (error) => {
|
|
393
|
-
console.error("[Orchestrator] L2 rendering failed for", clipId, error);
|
|
394
|
-
reject(error);
|
|
395
|
-
}
|
|
396
|
-
}).then((s) => {
|
|
397
|
-
session = s;
|
|
398
|
-
return session.activate();
|
|
399
|
-
}).catch(async (error) => {
|
|
400
|
-
if (session) {
|
|
401
|
-
await session.dispose();
|
|
402
|
-
}
|
|
403
|
-
if (error instanceof ResourceConflictError) {
|
|
404
|
-
resolve(false);
|
|
405
|
-
} else {
|
|
406
|
-
reject(error);
|
|
407
|
-
}
|
|
408
|
-
});
|
|
409
|
-
});
|
|
410
|
-
}
|
|
411
|
-
// TODO: move to @ClipSessionManager
|
|
412
|
-
async createSession(sessionId, options) {
|
|
413
|
-
const clipId = options?.clipId ?? sessionId;
|
|
414
|
-
const clip = this.compositionModel?.findClip(clipId);
|
|
415
|
-
if (!clip) {
|
|
416
|
-
throw new Error(`Clip ${clipId} not found`);
|
|
417
|
-
}
|
|
418
|
-
const session = await VideoClipSession.create({
|
|
419
|
-
clipId,
|
|
420
|
-
sessionId,
|
|
421
|
-
forL2Only: options?.forL2Only ?? false,
|
|
422
|
-
planner: this.planner,
|
|
423
|
-
workerPool: this.workers,
|
|
424
|
-
cacheManager: this.cacheManager,
|
|
425
|
-
compositionModel: this.compositionModel,
|
|
426
|
-
workerConfigs: this.buildWorkerConfigs(),
|
|
427
|
-
resourceLoader: this.resourceLoader,
|
|
428
|
-
callbacks: {
|
|
429
|
-
onComposedStreamReady: async (stream, fps) => {
|
|
430
|
-
await this.cacheManager.receiveComposedFrames(stream, {
|
|
431
|
-
clipId,
|
|
432
|
-
trackId: this.compositionModel.mainTrackId,
|
|
433
|
-
fps,
|
|
434
|
-
clipStartUs: clip.startUs,
|
|
435
|
-
onFrame: () => {
|
|
436
|
-
}
|
|
437
|
-
});
|
|
438
|
-
},
|
|
439
|
-
onEncodedStreamReady: async (stream, track) => {
|
|
440
|
-
await this.cacheManager.receiveEncodedChunks(stream, clipId, track, {
|
|
441
|
-
onComplete: () => {
|
|
442
|
-
session.dispose();
|
|
443
|
-
if (track === "video" && options?.onL2Complete) {
|
|
444
|
-
options.onL2Complete();
|
|
445
|
-
}
|
|
446
|
-
},
|
|
447
|
-
onError: (error) => {
|
|
448
|
-
console.error(`[Orchestrator] L2 encode stream error for ${clipId} ${track}:`, error);
|
|
449
|
-
session.dispose();
|
|
450
|
-
if (options?.onL2Error) {
|
|
451
|
-
options.onL2Error(error);
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
});
|
|
455
|
-
},
|
|
456
|
-
onAudioStreamReady: (stream, metadata) => {
|
|
457
|
-
if (options?.forL2Only) {
|
|
458
|
-
stream.cancel();
|
|
459
|
-
} else {
|
|
460
|
-
this.audioSession.handleAudioStream(stream, metadata);
|
|
461
|
-
}
|
|
462
|
-
},
|
|
463
|
-
onPipelineReady: async (attachmentResourceIds) => {
|
|
464
|
-
const clip2 = this.compositionModel?.findClip(clipId);
|
|
465
|
-
if (clip2 && hasResourceId(clip2)) {
|
|
466
|
-
await this.resourceLoader.fetch(clip2.resourceId, {
|
|
467
|
-
priority: options?.forL2Only ? "low" : "high",
|
|
468
|
-
sessionId,
|
|
469
|
-
trackId: clip2.trackId,
|
|
470
|
-
isMainTrack: true
|
|
471
|
-
});
|
|
472
|
-
}
|
|
473
|
-
if (attachmentResourceIds && attachmentResourceIds.length > 0) {
|
|
474
|
-
for (const resourceId of attachmentResourceIds) {
|
|
475
|
-
await this.resourceLoader.fetch(resourceId, {
|
|
476
|
-
priority: "normal",
|
|
477
|
-
sessionId,
|
|
478
|
-
isMainTrack: false
|
|
479
|
-
});
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
307
|
});
|
|
485
|
-
this.activeClips.add(sessionId);
|
|
486
|
-
return session;
|
|
487
308
|
}
|
|
488
309
|
async dispose() {
|
|
489
310
|
if (this.ensureCacheDebounceTimer !== null) {
|
|
@@ -491,10 +312,7 @@ class Orchestrator {
|
|
|
491
312
|
this.ensureCacheDebounceTimer = null;
|
|
492
313
|
}
|
|
493
314
|
this.resourceLoader.dispose();
|
|
494
|
-
await this.clipSessionManager.dispose();
|
|
495
315
|
await this.cacheManager.clear();
|
|
496
|
-
this.currentClipId = null;
|
|
497
|
-
this.activeClips.clear();
|
|
498
316
|
this.workers.terminateAll();
|
|
499
317
|
this.compositionModel = null;
|
|
500
318
|
this.eventBus.dispose();
|
|
@@ -504,6 +322,7 @@ class Orchestrator {
|
|
|
504
322
|
const defaultCanvasWidth = config.global?.defaultCanvasWidth ?? 720;
|
|
505
323
|
const defaultCanvasHeight = config.global?.defaultCanvasHeight ?? 1280;
|
|
506
324
|
const defaultFps = config.global?.defaultFps ?? 30;
|
|
325
|
+
const targetFps = this.compositionModel?.fps ?? defaultFps;
|
|
507
326
|
return {
|
|
508
327
|
videoDemux: {
|
|
509
328
|
highWaterMark: config.demux?.backpressure?.highWaterMark ?? 10
|
|
@@ -516,7 +335,7 @@ class Orchestrator {
|
|
|
516
335
|
videoCompose: {
|
|
517
336
|
width: config.compose?.canvas?.width ?? defaultCanvasWidth,
|
|
518
337
|
height: config.compose?.canvas?.height ?? defaultCanvasHeight,
|
|
519
|
-
fps:
|
|
338
|
+
fps: targetFps,
|
|
520
339
|
backgroundColor: config.compose?.canvas?.backgroundColor ?? "#000000",
|
|
521
340
|
enableSmoothing: config.compose?.visual?.enableSmoothing ?? true,
|
|
522
341
|
enableHardwareAcceleration: config.compose?.visual?.enableHardwareAcceleration ?? true,
|
|
@@ -531,7 +350,7 @@ class Orchestrator {
|
|
|
531
350
|
width: config.compose?.canvas?.width || defaultCanvasWidth,
|
|
532
351
|
height: config.compose?.canvas?.height || defaultCanvasHeight,
|
|
533
352
|
bitrate: config.encode?.video?.bitrateKbps ? config.encode.video.bitrateKbps * 1e3 : 12e6,
|
|
534
|
-
framerate:
|
|
353
|
+
framerate: targetFps,
|
|
535
354
|
latencyMode: "quality",
|
|
536
355
|
bitrateMode: "variable",
|
|
537
356
|
hardwareAcceleration: "no-preference",
|
|
@@ -540,7 +359,121 @@ class Orchestrator {
|
|
|
540
359
|
};
|
|
541
360
|
}
|
|
542
361
|
async export(model, options) {
|
|
543
|
-
return this.
|
|
362
|
+
return this.exportScheduler.execute(model, options);
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Get render state for real-time composition
|
|
366
|
+
* Returns layers ready for VideoComposer
|
|
367
|
+
*/
|
|
368
|
+
async getRenderState(timeUs, options) {
|
|
369
|
+
if (!this.compositionModel) {
|
|
370
|
+
return null;
|
|
371
|
+
}
|
|
372
|
+
const frame = await this.getFrame(timeUs, options);
|
|
373
|
+
if (options?.immediate && !frame) {
|
|
374
|
+
return null;
|
|
375
|
+
}
|
|
376
|
+
const clip = this.compositionModel.getClipsAtTime(timeUs, this.compositionModel.mainTrackId)[0];
|
|
377
|
+
if (!clip) {
|
|
378
|
+
return null;
|
|
379
|
+
}
|
|
380
|
+
const relativeTimeUs = timeUs - clip.startUs;
|
|
381
|
+
const instructions = this.planner.getInstructions(clip.id);
|
|
382
|
+
if (!instructions) {
|
|
383
|
+
return null;
|
|
384
|
+
}
|
|
385
|
+
const layers = [];
|
|
386
|
+
const activeLayers = instructions.layers.filter((layer) => {
|
|
387
|
+
if (!layer.payload.attachmentId) {
|
|
388
|
+
return true;
|
|
389
|
+
}
|
|
390
|
+
if (layer.status !== "ready") {
|
|
391
|
+
return false;
|
|
392
|
+
}
|
|
393
|
+
return layer.activeRanges.some(
|
|
394
|
+
(range) => relativeTimeUs >= range.startUs && relativeTimeUs < range.endUs
|
|
395
|
+
);
|
|
396
|
+
});
|
|
397
|
+
for (const layerPlan of activeLayers) {
|
|
398
|
+
const layer = this.materializeLayer(layerPlan, clip, relativeTimeUs, timeUs);
|
|
399
|
+
if (layer) {
|
|
400
|
+
layers.push(layer);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
return { layers };
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Materialize a serialized layer plan into concrete Layer
|
|
407
|
+
*/
|
|
408
|
+
materializeLayer(layerPlan, clip, clipRelativeTimeUs, globalTimeUs) {
|
|
409
|
+
const baseLayer = {
|
|
410
|
+
id: layerPlan.layerId,
|
|
411
|
+
type: layerPlan.type,
|
|
412
|
+
zIndex: layerPlan.zIndex ?? 0,
|
|
413
|
+
visible: true,
|
|
414
|
+
opacity: layerPlan.opacity ?? 1
|
|
415
|
+
};
|
|
416
|
+
if (layerPlan.type === "video" && !layerPlan.payload.attachmentId) {
|
|
417
|
+
const rcFrame = this.cacheManager.getFrame(clipRelativeTimeUs, clip.id);
|
|
418
|
+
if (!rcFrame) {
|
|
419
|
+
console.warn("[Orchestrator] Video frame not found in L1:", clip.id, clipRelativeTimeUs);
|
|
420
|
+
return null;
|
|
421
|
+
}
|
|
422
|
+
return {
|
|
423
|
+
...baseLayer,
|
|
424
|
+
type: "video",
|
|
425
|
+
rcFrame
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
if (layerPlan.type === "text") {
|
|
429
|
+
const payload = layerPlan.payload;
|
|
430
|
+
return {
|
|
431
|
+
...baseLayer,
|
|
432
|
+
type: "text",
|
|
433
|
+
text: payload.text,
|
|
434
|
+
localeCode: payload.localeCode,
|
|
435
|
+
fontConfig: payload.fontConfig,
|
|
436
|
+
animation: payload.animation,
|
|
437
|
+
wordTimings: payload.wordTimings,
|
|
438
|
+
letterCase: payload.letterCase
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
if (layerPlan.type === "image") {
|
|
442
|
+
const payload = layerPlan.payload;
|
|
443
|
+
const resourceId = payload.resourceId;
|
|
444
|
+
const source = this.cacheManager.imageBitmapCache.get(resourceId);
|
|
445
|
+
const imageLayer = {
|
|
446
|
+
...baseLayer,
|
|
447
|
+
type: "image",
|
|
448
|
+
source,
|
|
449
|
+
attachmentId: payload.attachmentId
|
|
450
|
+
};
|
|
451
|
+
if (payload.targetWidth !== void 0) {
|
|
452
|
+
imageLayer.targetWidth = payload.targetWidth;
|
|
453
|
+
}
|
|
454
|
+
if (payload.targetHeight !== void 0) {
|
|
455
|
+
imageLayer.targetHeight = payload.targetHeight;
|
|
456
|
+
}
|
|
457
|
+
if (payload.animation) {
|
|
458
|
+
const { position, keyframes, overlayClipStartUs } = payload.animation;
|
|
459
|
+
const relativeTimeUs = globalTimeUs - overlayClipStartUs;
|
|
460
|
+
if (relativeTimeUs < 0 || relativeTimeUs > keyframes[keyframes.length - 1].time) {
|
|
461
|
+
return null;
|
|
462
|
+
}
|
|
463
|
+
const rotationRad = 0;
|
|
464
|
+
imageLayer.transform = {
|
|
465
|
+
x: position.x,
|
|
466
|
+
y: position.y,
|
|
467
|
+
scaleX: 1,
|
|
468
|
+
scaleY: 1,
|
|
469
|
+
rotation: rotationRad,
|
|
470
|
+
anchorX: 0.5,
|
|
471
|
+
anchorY: 0.5
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
return imageLayer;
|
|
475
|
+
}
|
|
476
|
+
return baseLayer;
|
|
544
477
|
}
|
|
545
478
|
}
|
|
546
479
|
export {
|