@meframe/core 0.0.29 → 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 +116 -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/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 +231 -297
- 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 +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.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.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/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,54 @@
|
|
|
1
|
+
import { OPFSPrefix, OPFSPath } from './types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* OPFSManager - Unified OPFS management infrastructure
|
|
5
|
+
*
|
|
6
|
+
* Supports:
|
|
7
|
+
* - Directory isolation by prefix (l2/resource)
|
|
8
|
+
* - Range reads for on-demand decoding
|
|
9
|
+
* - Streaming writes
|
|
10
|
+
* - File operations (exists, delete, getFileSize)
|
|
11
|
+
*/
|
|
12
|
+
export declare class OPFSManager {
|
|
13
|
+
private opfsRoot;
|
|
14
|
+
private initPromise;
|
|
15
|
+
init(): Promise<void>;
|
|
16
|
+
private initStorage;
|
|
17
|
+
/**
|
|
18
|
+
* Get project directory by prefix
|
|
19
|
+
*/
|
|
20
|
+
getProjectDir(projectId: string, prefix: OPFSPrefix): Promise<FileSystemDirectoryHandle>;
|
|
21
|
+
/**
|
|
22
|
+
* Write file (ArrayBuffer or ReadableStream)
|
|
23
|
+
*/
|
|
24
|
+
writeFile(path: OPFSPath, data: ArrayBuffer | ReadableStream<Uint8Array>): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Read entire file
|
|
27
|
+
*/
|
|
28
|
+
readFile(path: OPFSPath): Promise<ArrayBuffer>;
|
|
29
|
+
/**
|
|
30
|
+
* Read byte range from file (for on-demand decoding)
|
|
31
|
+
*/
|
|
32
|
+
readRange(path: OPFSPath, start: number, end: number): Promise<ArrayBuffer>;
|
|
33
|
+
/**
|
|
34
|
+
* Delete file
|
|
35
|
+
*/
|
|
36
|
+
deleteFile(path: OPFSPath): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Check if file exists
|
|
39
|
+
*/
|
|
40
|
+
exists(path: OPFSPath): Promise<boolean>;
|
|
41
|
+
/**
|
|
42
|
+
* Get file size
|
|
43
|
+
*/
|
|
44
|
+
getFileSize(path: OPFSPath): Promise<number>;
|
|
45
|
+
/**
|
|
46
|
+
* Create writable stream for streaming writes
|
|
47
|
+
*/
|
|
48
|
+
createWritableStream(path: OPFSPath): Promise<FileSystemWritableFileStream>;
|
|
49
|
+
/**
|
|
50
|
+
* Delete entire project directory
|
|
51
|
+
*/
|
|
52
|
+
deleteProjectDirectory(projectId: string, prefix: OPFSPrefix): Promise<void>;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=OPFSManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OPFSManager.d.ts","sourceRoot":"","sources":["../../../../src/cache/storage/opfs/OPFSManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEpD;;;;;;;;GAQG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAA0C;IAC1D,OAAO,CAAC,WAAW,CAA8B;IAE3C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YAOb,WAAW;IAIzB;;OAEG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAS9F;;OAEG;IACG,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,GAAG,cAAc,CAAC,UAAU,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IA+B9F;;OAEG;IACG,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,WAAW,CAAC;IAOpD;;OAEG;IACG,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAQjF;;OAEG;IACG,UAAU,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAW/C;;OAEG;IACG,MAAM,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;IAa9C;;OAEG;IACG,WAAW,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC;IAOlD;;OAEG;IACG,oBAAoB,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,4BAA4B,CAAC;IAMjF;;OAEG;IACG,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;CAYnF"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
class OPFSManager {
|
|
2
|
+
opfsRoot = null;
|
|
3
|
+
initPromise = null;
|
|
4
|
+
async init() {
|
|
5
|
+
if (this.initPromise) return this.initPromise;
|
|
6
|
+
this.initPromise = this.initStorage();
|
|
7
|
+
return this.initPromise;
|
|
8
|
+
}
|
|
9
|
+
async initStorage() {
|
|
10
|
+
this.opfsRoot = await navigator.storage.getDirectory();
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Get project directory by prefix
|
|
14
|
+
*/
|
|
15
|
+
async getProjectDir(projectId, prefix) {
|
|
16
|
+
if (!this.opfsRoot) {
|
|
17
|
+
throw new Error("[OPFSManager] Not initialized");
|
|
18
|
+
}
|
|
19
|
+
const dirName = `meframe-${prefix}-${projectId}`;
|
|
20
|
+
return this.opfsRoot.getDirectoryHandle(dirName, { create: true });
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Write file (ArrayBuffer or ReadableStream)
|
|
24
|
+
*/
|
|
25
|
+
async writeFile(path, data) {
|
|
26
|
+
const projectDir = await this.getProjectDir(path.projectId, path.prefix);
|
|
27
|
+
const fileHandle = await projectDir.getFileHandle(path.fileName, { create: true });
|
|
28
|
+
const writable = await fileHandle.createWritable();
|
|
29
|
+
if (data instanceof ArrayBuffer) {
|
|
30
|
+
await writable.write(data);
|
|
31
|
+
} else {
|
|
32
|
+
const reader = data.getReader();
|
|
33
|
+
try {
|
|
34
|
+
while (true) {
|
|
35
|
+
const { done, value } = await reader.read();
|
|
36
|
+
if (done) break;
|
|
37
|
+
if (value) {
|
|
38
|
+
const buffer = value.buffer.slice(
|
|
39
|
+
value.byteOffset,
|
|
40
|
+
value.byteOffset + value.byteLength
|
|
41
|
+
);
|
|
42
|
+
await writable.write(buffer);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
} finally {
|
|
46
|
+
reader.releaseLock();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
await writable.close();
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Read entire file
|
|
53
|
+
*/
|
|
54
|
+
async readFile(path) {
|
|
55
|
+
const projectDir = await this.getProjectDir(path.projectId, path.prefix);
|
|
56
|
+
const fileHandle = await projectDir.getFileHandle(path.fileName, { create: false });
|
|
57
|
+
const file = await fileHandle.getFile();
|
|
58
|
+
return await file.arrayBuffer();
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Read byte range from file (for on-demand decoding)
|
|
62
|
+
*/
|
|
63
|
+
async readRange(path, start, end) {
|
|
64
|
+
const projectDir = await this.getProjectDir(path.projectId, path.prefix);
|
|
65
|
+
const fileHandle = await projectDir.getFileHandle(path.fileName, { create: false });
|
|
66
|
+
const file = await fileHandle.getFile();
|
|
67
|
+
const slice = file.slice(start, end);
|
|
68
|
+
return await slice.arrayBuffer();
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Delete file
|
|
72
|
+
*/
|
|
73
|
+
async deleteFile(path) {
|
|
74
|
+
try {
|
|
75
|
+
const projectDir = await this.getProjectDir(path.projectId, path.prefix);
|
|
76
|
+
await projectDir.removeEntry(path.fileName);
|
|
77
|
+
} catch (error) {
|
|
78
|
+
if (error?.name !== "NotFoundError") {
|
|
79
|
+
console.warn(`[OPFSManager] Failed to delete file ${path.fileName}:`, error);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Check if file exists
|
|
85
|
+
*/
|
|
86
|
+
async exists(path) {
|
|
87
|
+
try {
|
|
88
|
+
const projectDir = await this.getProjectDir(path.projectId, path.prefix);
|
|
89
|
+
await projectDir.getFileHandle(path.fileName, { create: false });
|
|
90
|
+
return true;
|
|
91
|
+
} catch (error) {
|
|
92
|
+
if (error?.name === "NotFoundError") {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
throw error;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Get file size
|
|
100
|
+
*/
|
|
101
|
+
async getFileSize(path) {
|
|
102
|
+
const projectDir = await this.getProjectDir(path.projectId, path.prefix);
|
|
103
|
+
const fileHandle = await projectDir.getFileHandle(path.fileName, { create: false });
|
|
104
|
+
const file = await fileHandle.getFile();
|
|
105
|
+
return file.size;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Create writable stream for streaming writes
|
|
109
|
+
*/
|
|
110
|
+
async createWritableStream(path) {
|
|
111
|
+
const projectDir = await this.getProjectDir(path.projectId, path.prefix);
|
|
112
|
+
const fileHandle = await projectDir.getFileHandle(path.fileName, { create: true });
|
|
113
|
+
return await fileHandle.createWritable();
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Delete entire project directory
|
|
117
|
+
*/
|
|
118
|
+
async deleteProjectDirectory(projectId, prefix) {
|
|
119
|
+
if (!this.opfsRoot) return;
|
|
120
|
+
try {
|
|
121
|
+
const dirName = `meframe-${prefix}-${projectId}`;
|
|
122
|
+
await this.opfsRoot.removeEntry(dirName, { recursive: true });
|
|
123
|
+
} catch (error) {
|
|
124
|
+
if (error?.name !== "NotFoundError") {
|
|
125
|
+
console.warn(`[OPFSManager] Failed to remove directory ${prefix}-${projectId}:`, error);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
export {
|
|
131
|
+
OPFSManager
|
|
132
|
+
};
|
|
133
|
+
//# sourceMappingURL=OPFSManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OPFSManager.js","sources":["../../../../src/cache/storage/opfs/OPFSManager.ts"],"sourcesContent":["import type { OPFSPrefix, OPFSPath } from './types';\n\n/**\n * OPFSManager - Unified OPFS management infrastructure\n *\n * Supports:\n * - Directory isolation by prefix (l2/resource)\n * - Range reads for on-demand decoding\n * - Streaming writes\n * - File operations (exists, delete, getFileSize)\n */\nexport class OPFSManager {\n private opfsRoot: FileSystemDirectoryHandle | null = null;\n private initPromise: Promise<void> | null = null;\n\n async init(): Promise<void> {\n if (this.initPromise) return this.initPromise;\n\n this.initPromise = this.initStorage();\n return this.initPromise;\n }\n\n private async initStorage(): Promise<void> {\n this.opfsRoot = await navigator.storage.getDirectory();\n }\n\n /**\n * Get project directory by prefix\n */\n async getProjectDir(projectId: string, prefix: OPFSPrefix): Promise<FileSystemDirectoryHandle> {\n if (!this.opfsRoot) {\n throw new Error('[OPFSManager] Not initialized');\n }\n\n const dirName = `meframe-${prefix}-${projectId}`;\n return this.opfsRoot.getDirectoryHandle(dirName, { create: true });\n }\n\n /**\n * Write file (ArrayBuffer or ReadableStream)\n */\n async writeFile(path: OPFSPath, data: ArrayBuffer | ReadableStream<Uint8Array>): Promise<void> {\n const projectDir = await this.getProjectDir(path.projectId, path.prefix);\n const fileHandle = await projectDir.getFileHandle(path.fileName, { create: true });\n const writable = await fileHandle.createWritable();\n\n if (data instanceof ArrayBuffer) {\n await writable.write(data);\n } else {\n // Stream mode\n const reader = data.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n if (value) {\n // Convert Uint8Array to ArrayBuffer for FileSystemWritableFileStream\n const buffer = value.buffer.slice(\n value.byteOffset,\n value.byteOffset + value.byteLength\n );\n await writable.write(buffer as ArrayBuffer);\n }\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n await writable.close();\n }\n\n /**\n * Read entire file\n */\n async readFile(path: OPFSPath): Promise<ArrayBuffer> {\n const projectDir = await this.getProjectDir(path.projectId, path.prefix);\n const fileHandle = await projectDir.getFileHandle(path.fileName, { create: false });\n const file = await fileHandle.getFile();\n return await file.arrayBuffer();\n }\n\n /**\n * Read byte range from file (for on-demand decoding)\n */\n async readRange(path: OPFSPath, start: number, end: number): Promise<ArrayBuffer> {\n const projectDir = await this.getProjectDir(path.projectId, path.prefix);\n const fileHandle = await projectDir.getFileHandle(path.fileName, { create: false });\n const file = await fileHandle.getFile();\n const slice = file.slice(start, end);\n return await slice.arrayBuffer();\n }\n\n /**\n * Delete file\n */\n async deleteFile(path: OPFSPath): Promise<void> {\n try {\n const projectDir = await this.getProjectDir(path.projectId, path.prefix);\n await projectDir.removeEntry(path.fileName);\n } catch (error) {\n if ((error as any)?.name !== 'NotFoundError') {\n console.warn(`[OPFSManager] Failed to delete file ${path.fileName}:`, error);\n }\n }\n }\n\n /**\n * Check if file exists\n */\n async exists(path: OPFSPath): Promise<boolean> {\n try {\n const projectDir = await this.getProjectDir(path.projectId, path.prefix);\n await projectDir.getFileHandle(path.fileName, { create: false });\n return true;\n } catch (error) {\n if ((error as any)?.name === 'NotFoundError') {\n return false;\n }\n throw error;\n }\n }\n\n /**\n * Get file size\n */\n async getFileSize(path: OPFSPath): Promise<number> {\n const projectDir = await this.getProjectDir(path.projectId, path.prefix);\n const fileHandle = await projectDir.getFileHandle(path.fileName, { create: false });\n const file = await fileHandle.getFile();\n return file.size;\n }\n\n /**\n * Create writable stream for streaming writes\n */\n async createWritableStream(path: OPFSPath): Promise<FileSystemWritableFileStream> {\n const projectDir = await this.getProjectDir(path.projectId, path.prefix);\n const fileHandle = await projectDir.getFileHandle(path.fileName, { create: true });\n return await fileHandle.createWritable();\n }\n\n /**\n * Delete entire project directory\n */\n async deleteProjectDirectory(projectId: string, prefix: OPFSPrefix): Promise<void> {\n if (!this.opfsRoot) return;\n\n try {\n const dirName = `meframe-${prefix}-${projectId}`;\n await this.opfsRoot.removeEntry(dirName, { recursive: true });\n } catch (error) {\n if ((error as any)?.name !== 'NotFoundError') {\n console.warn(`[OPFSManager] Failed to remove directory ${prefix}-${projectId}:`, error);\n }\n }\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { TimeUs } from '../../../model/types';
|
|
2
|
+
|
|
3
|
+
export type OPFSPrefix = 'l2' | 'resource';
|
|
4
|
+
export interface OPFSPath {
|
|
5
|
+
projectId: string;
|
|
6
|
+
prefix: OPFSPrefix;
|
|
7
|
+
fileName: string;
|
|
8
|
+
}
|
|
9
|
+
export interface ChunkBatch {
|
|
10
|
+
startUs: TimeUs;
|
|
11
|
+
durationUs: TimeUs;
|
|
12
|
+
byteOffset: number;
|
|
13
|
+
byteLength: number;
|
|
14
|
+
type: 'key' | 'delta';
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/cache/storage/opfs/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAEnD,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,UAAU,CAAC;AAE3C,MAAM,WAAW,QAAQ;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,KAAK,GAAG,OAAO,CAAC;CACvB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../src/config/defaults.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAU9C;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,EAAE,
|
|
1
|
+
{"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../src/config/defaults.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAU9C;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,EAAE,cAoF5B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc;IACzB;;;OAGG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA8BH;;;OAGG;;;;;;;;;;;;;;;;;;;;;;;;;qCAyBmC,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE;;;;;;;;;;;;;;IAezD;;;OAGG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BK,CAAC"}
|
package/dist/config/defaults.js
CHANGED
|
@@ -64,8 +64,27 @@ const DEFAULT_CONFIG = {
|
|
|
64
64
|
audio: {}
|
|
65
65
|
},
|
|
66
66
|
cache: {
|
|
67
|
-
l1: {
|
|
68
|
-
|
|
67
|
+
l1: {
|
|
68
|
+
windowSizeUs: 6e6,
|
|
69
|
+
// ±3 seconds window
|
|
70
|
+
maxMemoryMB: 200
|
|
71
|
+
},
|
|
72
|
+
l2: {
|
|
73
|
+
autoFill: true,
|
|
74
|
+
fillPriority: "low"
|
|
75
|
+
},
|
|
76
|
+
opfs: {
|
|
77
|
+
enabled: true,
|
|
78
|
+
resource: {
|
|
79
|
+
maxSizeMB: 5120,
|
|
80
|
+
// 5GB for original resources
|
|
81
|
+
evictionPolicy: "lru"
|
|
82
|
+
},
|
|
83
|
+
l2: {
|
|
84
|
+
maxSizeMB: 2048
|
|
85
|
+
// 2GB for encoded chunks
|
|
86
|
+
}
|
|
87
|
+
}
|
|
69
88
|
},
|
|
70
89
|
mux: {}
|
|
71
90
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defaults.js","sources":["../../src/config/defaults.ts"],"sourcesContent":["import type { ResolvedConfig } from './types';\nimport { CANVAS_PRESETS } from './presets';\n\n/**\n * Detect if running in development mode\n * In dev mode, workers are loaded from source (Vite dev server)\n * In prod mode, workers are loaded from dist\n */\nconst isDev = import.meta.env?.DEV ?? false;\n\n/**\n * Default configuration values based on mobile 1080p30 memory budget\n *\n * Note: Canvas dimensions are fixed for the entire project.\n * All video clips will be scaled/fitted to this resolution.\n * Choose based on your primary content type:\n * - 720×1280: Mobile vertical video\n * - 1080×1920: HD vertical video (TikTok, Instagram Reels) ← default\n * - 1920×1080: HD horizontal video (YouTube)\n */\nexport const DEFAULT_CONFIG: ResolvedConfig = {\n global: {\n projectId: `project-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,\n logLevel: 'info',\n enablePerfMonitor: false,\n defaultCanvasWidth: CANVAS_PRESETS.MOBILE_PORTRAIT.width,\n defaultCanvasHeight: CANVAS_PRESETS.MOBILE_PORTRAIT.height,\n defaultFps: 30,\n workerPath: isDev ? '/src' : '/meframe-workers',\n workerExtension: isDev ? '.ts' : '.js',\n },\n\n load: {\n maxConcurrent: 2,\n backpressure: {\n highWaterMark: 64 * 1024, // 64 KB\n stallTimeoutMs: 500,\n },\n retry: {\n maxAttempts: 3,\n baseDelayMs: 500,\n },\n window: {\n maxInflightPerClip: 1,\n maxInflight: 4,\n chunkSize: 1 * 1024 * 1024, // 1 MB\n },\n },\n\n demux: {\n backpressure: {\n highWaterMark: 10, // 10 EncodedChunks\n },\n },\n\n decode: {\n video: {\n backpressure: {\n highWaterMark: 4, // 4 EncodedVideoChunks\n decodeQueueThreshold: 16, // Pause when decoder has 16+ chunks\n },\n maxGOPs: 4, // Cache 4 GOPs for seeking\n },\n audio: {\n backpressure: {\n highWaterMark: 20, // 20 EncodedAudioChunks\n },\n },\n },\n\n compose: {\n visual: {},\n audio: {\n enableDucking: false, // Default: no ducking\n },\n },\n\n encode: {\n video: {},\n audio: {},\n },\n\n cache: {\n l1: {},\n l2: {},\n },\n\n mux: {},\n};\n\n/**\n * Tuning presets for common scenarios\n */\nexport const TUNING_PRESETS = {\n /**\n * Low-latency live streaming\n * Minimize buffering for real-time playback\n */\n lowLatency: {\n global: {\n logLevel: 'info' as const,\n },\n load: {\n backpressure: {\n highWaterMark: 16 * 1024, // 16 KB\n },\n },\n demux: {\n backpressure: {\n highWaterMark: 3,\n },\n },\n decode: {\n video: {\n backpressure: {\n highWaterMark: 2,\n decodeQueueThreshold: 4,\n },\n },\n audio: {\n backpressure: {\n highWaterMark: 10,\n },\n },\n },\n },\n\n /**\n * 4K60 playback/export\n * Larger buffers for high bitrate content\n */\n highQuality: {\n global: {\n logLevel: 'info' as const,\n },\n load: {\n backpressure: {\n highWaterMark: 256 * 1024, // 256 KB\n },\n retry: {\n maxAttempts: 3,\n baseDelayMs: 500,\n },\n },\n demux: {\n backpressure: {\n highWaterMark: 20,\n },\n },\n decode: {\n video: {\n backpressure: {\n highWaterMark: 8,\n decodeQueueThreshold: 24,\n },\n codecHints: ['h264', 'hevc'] as ('h264' | 'hevc')[],\n },\n audio: {\n backpressure: {\n highWaterMark: 30,\n },\n },\n },\n cache: {\n l2: {\n quotaGb: 1,\n },\n },\n },\n\n /**\n * Batch offline transcode\n * Maximum throughput, memory not a concern\n */\n offline: {\n global: {\n logLevel: 'warn' as const,\n },\n load: {\n backpressure: {\n highWaterMark: 512 * 1024, // 512 KB\n },\n },\n demux: {\n backpressure: {\n highWaterMark: 25,\n },\n },\n decode: {\n video: {\n backpressure: {\n highWaterMark: 12,\n decodeQueueThreshold: 32,\n },\n },\n audio: {\n backpressure: {\n highWaterMark: 40,\n },\n },\n },\n },\n} as const;\n"],"names":[],"mappings":";AAoBO,MAAM,iBAAiC;AAAA,EAC5C,QAAQ;AAAA,IACN,WAAW,WAAW,KAAK,IAAA,CAAK,IAAI,KAAK,OAAA,EAAS,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AAAA,IAC1E,UAAU;AAAA,IACV,mBAAmB;AAAA,IACnB,oBAAoB,eAAe,gBAAgB;AAAA,IACnD,qBAAqB,eAAe,gBAAgB;AAAA,IACpD,YAAY;AAAA,IACZ,YAA6B;AAAA,IAC7B,iBAAiC;AAAA,EAAA;AAAA,EAGnC,MAAM;AAAA,IACJ,eAAe;AAAA,IACf,cAAc;AAAA,MACZ,eAAe,KAAK;AAAA;AAAA,MACpB,gBAAgB;AAAA,IAAA;AAAA,IAElB,OAAO;AAAA,MACL,aAAa;AAAA,MACb,aAAa;AAAA,IAAA;AAAA,IAEf,QAAQ;AAAA,MACN,oBAAoB;AAAA,MACpB,aAAa;AAAA,MACb,WAAW,IAAI,OAAO;AAAA;AAAA,IAAA;AAAA,EACxB;AAAA,EAGF,OAAO;AAAA,IACL,cAAc;AAAA,MACZ,eAAe;AAAA;AAAA,IAAA;AAAA,EACjB;AAAA,EAGF,QAAQ;AAAA,IACN,OAAO;AAAA,MACL,cAAc;AAAA,QACZ,eAAe;AAAA;AAAA,QACf,sBAAsB;AAAA;AAAA,MAAA;AAAA,MAExB,SAAS;AAAA;AAAA,IAAA;AAAA,IAEX,OAAO;AAAA,MACL,cAAc;AAAA,QACZ,eAAe;AAAA;AAAA,MAAA;AAAA,IACjB;AAAA,EACF;AAAA,EAGF,SAAS;AAAA,IACP,QAAQ,CAAA;AAAA,IACR,OAAO;AAAA,MACL,eAAe;AAAA;AAAA,IAAA;AAAA,EACjB;AAAA,EAGF,QAAQ;AAAA,IACN,OAAO,CAAA;AAAA,IACP,OAAO,CAAA;AAAA,EAAC;AAAA,EAGV,OAAO;AAAA,IACL,IAAI,
|
|
1
|
+
{"version":3,"file":"defaults.js","sources":["../../src/config/defaults.ts"],"sourcesContent":["import type { ResolvedConfig } from './types';\nimport { CANVAS_PRESETS } from './presets';\n\n/**\n * Detect if running in development mode\n * In dev mode, workers are loaded from source (Vite dev server)\n * In prod mode, workers are loaded from dist\n */\nconst isDev = import.meta.env?.DEV ?? false;\n\n/**\n * Default configuration values based on mobile 1080p30 memory budget\n *\n * Note: Canvas dimensions are fixed for the entire project.\n * All video clips will be scaled/fitted to this resolution.\n * Choose based on your primary content type:\n * - 720×1280: Mobile vertical video\n * - 1080×1920: HD vertical video (TikTok, Instagram Reels) ← default\n * - 1920×1080: HD horizontal video (YouTube)\n */\nexport const DEFAULT_CONFIG: ResolvedConfig = {\n global: {\n projectId: `project-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,\n logLevel: 'info',\n enablePerfMonitor: false,\n defaultCanvasWidth: CANVAS_PRESETS.MOBILE_PORTRAIT.width,\n defaultCanvasHeight: CANVAS_PRESETS.MOBILE_PORTRAIT.height,\n defaultFps: 30,\n workerPath: isDev ? '/src' : '/meframe-workers',\n workerExtension: isDev ? '.ts' : '.js',\n },\n\n load: {\n maxConcurrent: 2,\n backpressure: {\n highWaterMark: 64 * 1024, // 64 KB\n stallTimeoutMs: 500,\n },\n retry: {\n maxAttempts: 3,\n baseDelayMs: 500,\n },\n window: {\n maxInflightPerClip: 1,\n maxInflight: 4,\n chunkSize: 1 * 1024 * 1024, // 1 MB\n },\n },\n\n demux: {\n backpressure: {\n highWaterMark: 10, // 10 EncodedChunks\n },\n },\n\n decode: {\n video: {\n backpressure: {\n highWaterMark: 4, // 4 EncodedVideoChunks\n decodeQueueThreshold: 16, // Pause when decoder has 16+ chunks\n },\n maxGOPs: 4, // Cache 4 GOPs for seeking\n },\n audio: {\n backpressure: {\n highWaterMark: 20, // 20 EncodedAudioChunks\n },\n },\n },\n\n compose: {\n visual: {},\n audio: {\n enableDucking: false, // Default: no ducking\n },\n },\n\n encode: {\n video: {},\n audio: {},\n },\n\n cache: {\n l1: {\n windowSizeUs: 6_000_000, // ±3 seconds window\n maxMemoryMB: 200,\n },\n l2: {\n autoFill: true,\n fillPriority: 'low' as const,\n },\n opfs: {\n enabled: true,\n resource: {\n maxSizeMB: 5120, // 5GB for original resources\n evictionPolicy: 'lru' as const,\n },\n l2: {\n maxSizeMB: 2048, // 2GB for encoded chunks\n },\n },\n },\n\n mux: {},\n};\n\n/**\n * Tuning presets for common scenarios\n */\nexport const TUNING_PRESETS = {\n /**\n * Low-latency live streaming\n * Minimize buffering for real-time playback\n */\n lowLatency: {\n global: {\n logLevel: 'info' as const,\n },\n load: {\n backpressure: {\n highWaterMark: 16 * 1024, // 16 KB\n },\n },\n demux: {\n backpressure: {\n highWaterMark: 3,\n },\n },\n decode: {\n video: {\n backpressure: {\n highWaterMark: 2,\n decodeQueueThreshold: 4,\n },\n },\n audio: {\n backpressure: {\n highWaterMark: 10,\n },\n },\n },\n },\n\n /**\n * 4K60 playback/export\n * Larger buffers for high bitrate content\n */\n highQuality: {\n global: {\n logLevel: 'info' as const,\n },\n load: {\n backpressure: {\n highWaterMark: 256 * 1024, // 256 KB\n },\n retry: {\n maxAttempts: 3,\n baseDelayMs: 500,\n },\n },\n demux: {\n backpressure: {\n highWaterMark: 20,\n },\n },\n decode: {\n video: {\n backpressure: {\n highWaterMark: 8,\n decodeQueueThreshold: 24,\n },\n codecHints: ['h264', 'hevc'] as ('h264' | 'hevc')[],\n },\n audio: {\n backpressure: {\n highWaterMark: 30,\n },\n },\n },\n cache: {\n l2: {\n quotaGb: 1,\n },\n },\n },\n\n /**\n * Batch offline transcode\n * Maximum throughput, memory not a concern\n */\n offline: {\n global: {\n logLevel: 'warn' as const,\n },\n load: {\n backpressure: {\n highWaterMark: 512 * 1024, // 512 KB\n },\n },\n demux: {\n backpressure: {\n highWaterMark: 25,\n },\n },\n decode: {\n video: {\n backpressure: {\n highWaterMark: 12,\n decodeQueueThreshold: 32,\n },\n },\n audio: {\n backpressure: {\n highWaterMark: 40,\n },\n },\n },\n },\n} as const;\n"],"names":[],"mappings":"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"}
|
package/dist/config/types.d.ts
CHANGED
|
@@ -112,9 +112,23 @@ export interface MeframeConfig {
|
|
|
112
112
|
cache?: {
|
|
113
113
|
l1?: {
|
|
114
114
|
maxFrames?: number;
|
|
115
|
+
windowSizeUs?: number;
|
|
116
|
+
maxMemoryMB?: number;
|
|
115
117
|
};
|
|
116
118
|
l2?: {
|
|
117
119
|
quotaGb?: number;
|
|
120
|
+
autoFill?: boolean;
|
|
121
|
+
fillPriority?: 'low' | 'normal' | 'high';
|
|
122
|
+
};
|
|
123
|
+
opfs?: {
|
|
124
|
+
enabled?: boolean;
|
|
125
|
+
resource?: {
|
|
126
|
+
maxSizeMB?: number;
|
|
127
|
+
evictionPolicy?: 'lru' | 'fifo';
|
|
128
|
+
};
|
|
129
|
+
l2?: {
|
|
130
|
+
maxSizeMB?: number;
|
|
131
|
+
};
|
|
118
132
|
};
|
|
119
133
|
};
|
|
120
134
|
/** Mux/export stage */
|
|
@@ -197,9 +211,23 @@ export interface ResolvedConfig {
|
|
|
197
211
|
cache: {
|
|
198
212
|
l1: {
|
|
199
213
|
maxFrames?: number;
|
|
214
|
+
windowSizeUs: number;
|
|
215
|
+
maxMemoryMB: number;
|
|
200
216
|
};
|
|
201
217
|
l2: {
|
|
202
218
|
quotaGb?: number;
|
|
219
|
+
autoFill: boolean;
|
|
220
|
+
fillPriority: 'low' | 'normal' | 'high';
|
|
221
|
+
};
|
|
222
|
+
opfs: {
|
|
223
|
+
enabled: boolean;
|
|
224
|
+
resource: {
|
|
225
|
+
maxSizeMB: number;
|
|
226
|
+
evictionPolicy: 'lru' | 'fifo';
|
|
227
|
+
};
|
|
228
|
+
l2: {
|
|
229
|
+
maxSizeMB: number;
|
|
230
|
+
};
|
|
203
231
|
};
|
|
204
232
|
};
|
|
205
233
|
mux: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { IOrchestrator } from '../orchestrator/types';
|
|
2
|
+
import { ExportOptions } from '../types';
|
|
3
|
+
import { CompositionModel } from '../model';
|
|
4
|
+
|
|
5
|
+
export declare class ExportController {
|
|
6
|
+
private orchestrator;
|
|
7
|
+
private abortController;
|
|
8
|
+
private paused;
|
|
9
|
+
constructor(orchestrator: IOrchestrator);
|
|
10
|
+
export(model: CompositionModel, options: ExportOptions): Promise<Blob>;
|
|
11
|
+
cancel(): void;
|
|
12
|
+
pause(): void;
|
|
13
|
+
resume(): void;
|
|
14
|
+
isPaused(): boolean;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=ExportController.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExportController.d.ts","sourceRoot":"","sources":["../../src/controllers/ExportController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAEjD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,YAAY,CAAgB;IACpC,OAAO,CAAC,eAAe,CAAgC;IACvD,OAAO,CAAC,MAAM,CAAS;gBAEX,YAAY,EAAE,aAAa;IAIjC,MAAM,CAAC,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAsB5E,MAAM,IAAI,IAAI;IAOd,KAAK,IAAI,IAAI;IAOb,MAAM,IAAI,IAAI;IAId,QAAQ,IAAI,OAAO;CAGpB"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
class ExportController {
|
|
2
|
+
orchestrator;
|
|
3
|
+
abortController = null;
|
|
4
|
+
paused = false;
|
|
5
|
+
constructor(orchestrator) {
|
|
6
|
+
this.orchestrator = orchestrator;
|
|
7
|
+
}
|
|
8
|
+
async export(model, options) {
|
|
9
|
+
this.abortController = new AbortController();
|
|
10
|
+
this.paused = false;
|
|
11
|
+
try {
|
|
12
|
+
const extendedOptions = {
|
|
13
|
+
...options,
|
|
14
|
+
signal: this.abortController.signal,
|
|
15
|
+
controller: this
|
|
16
|
+
// Pass controller reference to allow polling paused state? Or event based?
|
|
17
|
+
// Ideally ExportScheduler checks `signal.aborted` and maybe a `paused` flag or callback.
|
|
18
|
+
};
|
|
19
|
+
return await this.orchestrator.export(model, extendedOptions);
|
|
20
|
+
} finally {
|
|
21
|
+
this.abortController = null;
|
|
22
|
+
this.paused = false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
cancel() {
|
|
26
|
+
if (this.abortController) {
|
|
27
|
+
this.abortController.abort();
|
|
28
|
+
this.abortController = null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
pause() {
|
|
32
|
+
this.paused = true;
|
|
33
|
+
}
|
|
34
|
+
resume() {
|
|
35
|
+
this.paused = false;
|
|
36
|
+
}
|
|
37
|
+
isPaused() {
|
|
38
|
+
return this.paused;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export {
|
|
42
|
+
ExportController
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=ExportController.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExportController.js","sources":["../../src/controllers/ExportController.ts"],"sourcesContent":["import type { IOrchestrator } from '../orchestrator/types';\nimport type { ExportOptions } from '../types';\nimport type { CompositionModel } from '../model';\n\nexport class ExportController {\n private orchestrator: IOrchestrator;\n private abortController: AbortController | null = null;\n private paused = false;\n\n constructor(orchestrator: IOrchestrator) {\n this.orchestrator = orchestrator;\n }\n\n async export(model: CompositionModel, options: ExportOptions): Promise<Blob> {\n this.abortController = new AbortController();\n this.paused = false;\n\n try {\n // Pass abort signal to orchestrator (ExportScheduler needs to handle it)\n // Note: ExportOptions type currently doesn't have 'signal', we might need to extend it or pass separately\n // For now, assume Orchestrator.export supports an extended options object internally\n const extendedOptions = {\n ...options,\n signal: this.abortController.signal,\n controller: this, // Pass controller reference to allow polling paused state? Or event based?\n // Ideally ExportScheduler checks `signal.aborted` and maybe a `paused` flag or callback.\n };\n\n return await this.orchestrator.export(model, extendedOptions as any);\n } finally {\n this.abortController = null;\n this.paused = false;\n }\n }\n\n cancel(): void {\n if (this.abortController) {\n this.abortController.abort();\n this.abortController = null;\n }\n }\n\n pause(): void {\n this.paused = true;\n // Notify scheduler?\n // Since ExportScheduler is running a loop, we need a way to signal it.\n // Ideally we pass an interface to check status.\n }\n\n resume(): void {\n this.paused = false;\n }\n\n isPaused(): boolean {\n return this.paused;\n }\n}\n"],"names":[],"mappings":"AAIO,MAAM,iBAAiB;AAAA,EACpB;AAAA,EACA,kBAA0C;AAAA,EAC1C,SAAS;AAAA,EAEjB,YAAY,cAA6B;AACvC,SAAK,eAAe;AAAA,EACtB;AAAA,EAEA,MAAM,OAAO,OAAyB,SAAuC;AAC3E,SAAK,kBAAkB,IAAI,gBAAA;AAC3B,SAAK,SAAS;AAEd,QAAI;AAIF,YAAM,kBAAkB;AAAA,QACtB,GAAG;AAAA,QACH,QAAQ,KAAK,gBAAgB;AAAA,QAC7B,YAAY;AAAA;AAAA;AAAA,MAAA;AAId,aAAO,MAAM,KAAK,aAAa,OAAO,OAAO,eAAsB;AAAA,IACrE,UAAA;AACE,WAAK,kBAAkB;AACvB,WAAK,SAAS;AAAA,IAChB;AAAA,EACF;AAAA,EAEA,SAAe;AACb,QAAI,KAAK,iBAAiB;AACxB,WAAK,gBAAgB,MAAA;AACrB,WAAK,kBAAkB;AAAA,IACzB;AAAA,EACF;AAAA,EAEA,QAAc;AACZ,SAAK,SAAS;AAAA,EAIhB;AAAA,EAEA,SAAe;AACb,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,WAAoB;AAClB,WAAO,KAAK;AAAA,EACd;AACF;"}
|
|
@@ -10,14 +10,14 @@ export declare class PlaybackController implements IPlaybackController, PreviewH
|
|
|
10
10
|
private orchestrator;
|
|
11
11
|
private eventBus;
|
|
12
12
|
private canvas;
|
|
13
|
-
private
|
|
13
|
+
private videoComposer;
|
|
14
14
|
currentTimeUs: TimeUs;
|
|
15
15
|
private state;
|
|
16
16
|
private playbackRate;
|
|
17
17
|
private volume;
|
|
18
18
|
private loop;
|
|
19
19
|
private rafId;
|
|
20
|
-
private
|
|
20
|
+
private startTimeUs;
|
|
21
21
|
private frameCount;
|
|
22
22
|
private lastFrameTime;
|
|
23
23
|
private fps;
|
|
@@ -26,7 +26,12 @@ export declare class PlaybackController implements IPlaybackController, PreviewH
|
|
|
26
26
|
private isBuffering;
|
|
27
27
|
private currentSeekId;
|
|
28
28
|
private wasPlayingBeforeSeek;
|
|
29
|
+
private windowEnd;
|
|
30
|
+
private readonly WINDOW_DURATION;
|
|
31
|
+
private readonly PREHEAT_DISTANCE;
|
|
32
|
+
private preheatInProgress;
|
|
29
33
|
constructor(orchestrator: Orchestrator, eventBus: IEventBus, options: PlaybackOptions);
|
|
34
|
+
renderCover(): void;
|
|
30
35
|
play(): void;
|
|
31
36
|
private startPlayback;
|
|
32
37
|
pause(): void;
|
|
@@ -42,13 +47,32 @@ export declare class PlaybackController implements IPlaybackController, PreviewH
|
|
|
42
47
|
resume(): void;
|
|
43
48
|
on(event: string, handler: (payload: any) => void): void;
|
|
44
49
|
off(event: string, handler: (payload: any) => void): void;
|
|
45
|
-
private setupListeners;
|
|
46
50
|
private playbackLoop;
|
|
47
51
|
private updateTime;
|
|
48
|
-
|
|
52
|
+
/**
|
|
53
|
+
* Initialize window at given time (called on play/seek)
|
|
54
|
+
*/
|
|
55
|
+
private initWindow;
|
|
56
|
+
/**
|
|
57
|
+
* Check if approaching window end and trigger preheat for next window
|
|
58
|
+
*
|
|
59
|
+
* Strategy: Sliding window
|
|
60
|
+
* - Current window: [windowStart, windowEnd] (3s duration)
|
|
61
|
+
* - When playback reaches windowEnd - 1s, preheat next window
|
|
62
|
+
* - Next window: [windowEnd, windowEnd + 3s]
|
|
63
|
+
*/
|
|
64
|
+
private checkAndPreheatWindow;
|
|
65
|
+
/**
|
|
66
|
+
* Preheat next window by decoding from current windowEnd
|
|
67
|
+
* Updates windowStart and windowEnd after preheat completes
|
|
68
|
+
*/
|
|
69
|
+
private preheatNextWindow;
|
|
70
|
+
renderCurrentFrame(timeUs: TimeUs): Promise<void>;
|
|
49
71
|
private handlePlaybackBuffering;
|
|
50
72
|
private clampTime;
|
|
51
73
|
dispose(): void;
|
|
74
|
+
private onCacheCover;
|
|
75
|
+
private setupEventListeners;
|
|
52
76
|
private ensureAudioContext;
|
|
53
77
|
}
|
|
54
78
|
//# sourceMappingURL=PlaybackController.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlaybackController.d.ts","sourceRoot":"","sources":["../../src/controllers/PlaybackController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EAEnB,eAAe,EACf,SAAS,EACT,aAAa,EACb,MAAM,EACP,MAAM,SAAS,CAAC;AAEjB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"PlaybackController.d.ts","sourceRoot":"","sources":["../../src/controllers/PlaybackController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EAEnB,eAAe,EACf,SAAS,EACT,aAAa,EACb,MAAM,EACP,MAAM,SAAS,CAAC;AAEjB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAIpD;;;GAGG;AACH,qBAAa,kBAAmB,YAAW,mBAAmB,EAAE,aAAa;IAC3E,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAY;IAC5B,OAAO,CAAC,MAAM,CAAsC;IACpD,OAAO,CAAC,aAAa,CAA8B;IAGnD,aAAa,EAAE,MAAM,CAAK;IAC1B,OAAO,CAAC,KAAK,CAAyB;IACtC,OAAO,CAAC,YAAY,CAAO;IAC3B,OAAO,CAAC,MAAM,CAAO;IACrB,OAAO,CAAC,IAAI,CAAS;IAGrB,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,WAAW,CAAa;IAGhC,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,GAAG,CAAK;IAChB,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,YAAY,CAAmC;IAGvD,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,oBAAoB,CAAS;IAGrC,OAAO,CAAC,SAAS,CAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAa;IAC7C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAa;IAC9C,OAAO,CAAC,iBAAiB,CAAS;gBAEtB,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,eAAe;IAoCrF,WAAW,IAAI,IAAI;IAMnB,IAAI,IAAI,IAAI;YAOE,aAAa;IAkC3B,KAAK,IAAI,IAAI;IAgBb,IAAI,IAAI,IAAI;IAuBN,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiDzC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAW3B,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAO/B,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAQ7B,OAAO,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI;IAI5B,IAAI,QAAQ,IAAI,MAAM,CAOrB;IAED,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,eAAe,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI;IAKlD,MAAM,IAAI,IAAI;IAId,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,IAAI,GAAG,IAAI;IAIxD,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,IAAI,GAAG,IAAI;IAKzD,OAAO,CAAC,YAAY;IA8CpB,OAAO,CAAC,UAAU;IA2BlB;;OAEG;IACH,OAAO,CAAC,UAAU;IAKlB;;;;;;;OAOG;IACH,OAAO,CAAC,qBAAqB;IAuB7B;;;OAGG;YACW,iBAAiB;IAiBzB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAiCzC,uBAAuB;IAwDrC,OAAO,CAAC,SAAS;IAKjB,OAAO,IAAI,IAAI;IASf,OAAO,CAAC,YAAY,CASlB;IAEF,OAAO,CAAC,mBAAmB;YAIb,kBAAkB;CAOjC"}
|