@meframe/core 0.0.1 → 0.0.3

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.
Files changed (159) hide show
  1. package/README.md +17 -4
  2. package/dist/Meframe.d.ts.map +1 -1
  3. package/dist/Meframe.js +2 -4
  4. package/dist/Meframe.js.map +1 -1
  5. package/dist/cache/CacheManager.d.ts.map +1 -1
  6. package/dist/cache/CacheManager.js +8 -1
  7. package/dist/cache/CacheManager.js.map +1 -1
  8. package/dist/config/defaults.d.ts.map +1 -1
  9. package/dist/config/defaults.js +2 -9
  10. package/dist/config/defaults.js.map +1 -1
  11. package/dist/config/types.d.ts +3 -4
  12. package/dist/config/types.d.ts.map +1 -1
  13. package/dist/controllers/PlaybackController.d.ts +4 -2
  14. package/dist/controllers/PlaybackController.d.ts.map +1 -1
  15. package/dist/controllers/PlaybackController.js +7 -13
  16. package/dist/controllers/PlaybackController.js.map +1 -1
  17. package/dist/controllers/PreRenderService.d.ts +3 -2
  18. package/dist/controllers/PreRenderService.d.ts.map +1 -1
  19. package/dist/controllers/PreRenderService.js.map +1 -1
  20. package/dist/controllers/PreviewHandle.d.ts +2 -0
  21. package/dist/controllers/PreviewHandle.d.ts.map +1 -1
  22. package/dist/controllers/PreviewHandle.js +6 -0
  23. package/dist/controllers/PreviewHandle.js.map +1 -1
  24. package/dist/controllers/index.d.ts +1 -1
  25. package/dist/controllers/index.d.ts.map +1 -1
  26. package/dist/controllers/types.d.ts +2 -12
  27. package/dist/controllers/types.d.ts.map +1 -1
  28. package/dist/event/events.d.ts +5 -59
  29. package/dist/event/events.d.ts.map +1 -1
  30. package/dist/event/events.js +1 -6
  31. package/dist/event/events.js.map +1 -1
  32. package/dist/model/CompositionModel.js +1 -2
  33. package/dist/model/CompositionModel.js.map +1 -1
  34. package/dist/orchestrator/CompositionPlanner.d.ts.map +1 -1
  35. package/dist/orchestrator/CompositionPlanner.js +1 -0
  36. package/dist/orchestrator/CompositionPlanner.js.map +1 -1
  37. package/dist/orchestrator/Orchestrator.d.ts.map +1 -1
  38. package/dist/orchestrator/Orchestrator.js +3 -13
  39. package/dist/orchestrator/Orchestrator.js.map +1 -1
  40. package/dist/orchestrator/VideoClipSession.d.ts.map +1 -1
  41. package/dist/orchestrator/VideoClipSession.js +4 -5
  42. package/dist/orchestrator/VideoClipSession.js.map +1 -1
  43. package/dist/orchestrator/types.d.ts +1 -1
  44. package/dist/orchestrator/types.d.ts.map +1 -1
  45. package/dist/stages/compose/GlobalAudioSession.d.ts.map +1 -1
  46. package/dist/stages/compose/GlobalAudioSession.js +3 -2
  47. package/dist/stages/compose/GlobalAudioSession.js.map +1 -1
  48. package/dist/stages/compose/VideoComposer.d.ts.map +1 -1
  49. package/dist/stages/compose/types.d.ts +3 -1
  50. package/dist/stages/compose/types.d.ts.map +1 -1
  51. package/dist/stages/decode/AudioChunkDecoder.d.ts.map +1 -1
  52. package/dist/stages/decode/VideoChunkDecoder.d.ts +0 -1
  53. package/dist/stages/decode/VideoChunkDecoder.d.ts.map +1 -1
  54. package/dist/stages/demux/MP4Demuxer.d.ts +2 -1
  55. package/dist/stages/demux/MP4Demuxer.d.ts.map +1 -1
  56. package/dist/stages/load/EventHandlers.d.ts +2 -11
  57. package/dist/stages/load/EventHandlers.d.ts.map +1 -1
  58. package/dist/stages/load/EventHandlers.js +1 -24
  59. package/dist/stages/load/EventHandlers.js.map +1 -1
  60. package/dist/stages/load/ResourceLoader.d.ts.map +1 -1
  61. package/dist/stages/load/ResourceLoader.js +11 -13
  62. package/dist/stages/load/ResourceLoader.js.map +1 -1
  63. package/dist/stages/load/TaskManager.d.ts +1 -1
  64. package/dist/stages/load/TaskManager.d.ts.map +1 -1
  65. package/dist/stages/load/TaskManager.js +3 -2
  66. package/dist/stages/load/TaskManager.js.map +1 -1
  67. package/dist/stages/load/types.d.ts +2 -0
  68. package/dist/stages/load/types.d.ts.map +1 -1
  69. package/dist/utils/time-utils.d.ts +3 -2
  70. package/dist/utils/time-utils.d.ts.map +1 -1
  71. package/dist/utils/time-utils.js +2 -1
  72. package/dist/utils/time-utils.js.map +1 -1
  73. package/dist/vite-plugin.d.ts +19 -0
  74. package/dist/vite-plugin.d.ts.map +1 -0
  75. package/dist/vite-plugin.js +145 -0
  76. package/dist/vite-plugin.js.map +1 -0
  77. package/dist/worker/WorkerPool.d.ts +7 -4
  78. package/dist/worker/WorkerPool.d.ts.map +1 -1
  79. package/dist/worker/WorkerPool.js +29 -18
  80. package/dist/worker/WorkerPool.js.map +1 -1
  81. package/dist/{stages/demux → workers}/MP4Demuxer.js +17 -15
  82. package/dist/workers/MP4Demuxer.js.map +1 -0
  83. package/dist/workers/WorkerChannel.js +486 -0
  84. package/dist/workers/WorkerChannel.js.map +1 -0
  85. package/dist/workers/mp4box.all.js +7049 -0
  86. package/dist/workers/mp4box.all.js.map +1 -0
  87. package/dist/workers/stages/compose/audio-compose.worker.js +1063 -0
  88. package/dist/workers/stages/compose/audio-compose.worker.js.map +1 -0
  89. package/dist/workers/stages/compose/video-compose.worker.js +1209 -0
  90. package/dist/workers/stages/compose/video-compose.worker.js.map +1 -0
  91. package/dist/{stages → workers/stages}/decode/decode.worker.js +401 -20
  92. package/dist/workers/stages/decode/decode.worker.js.map +1 -0
  93. package/dist/{stages → workers/stages}/demux/audio-demux.worker.js +184 -4
  94. package/dist/workers/stages/demux/audio-demux.worker.js.map +1 -0
  95. package/dist/{stages → workers/stages}/demux/video-demux.worker.js +7 -30
  96. package/dist/workers/stages/demux/video-demux.worker.js.map +1 -0
  97. package/dist/{stages → workers/stages}/encode/encode.worker.js +238 -5
  98. package/dist/workers/stages/encode/encode.worker.js.map +1 -0
  99. package/dist/{stages/mux/MP4Muxer.js → workers/stages/mux/mux.worker.js} +244 -5
  100. package/dist/workers/stages/mux/mux.worker.js.map +1 -0
  101. package/package.json +27 -21
  102. package/dist/model/types.js +0 -5
  103. package/dist/model/types.js.map +0 -1
  104. package/dist/plugins/BackpressureMonitor.js +0 -62
  105. package/dist/plugins/BackpressureMonitor.js.map +0 -1
  106. package/dist/stages/compose/AudioDucker.js +0 -161
  107. package/dist/stages/compose/AudioDucker.js.map +0 -1
  108. package/dist/stages/compose/AudioMixer.js +0 -373
  109. package/dist/stages/compose/AudioMixer.js.map +0 -1
  110. package/dist/stages/compose/FilterProcessor.js +0 -226
  111. package/dist/stages/compose/FilterProcessor.js.map +0 -1
  112. package/dist/stages/compose/LayerRenderer.js +0 -215
  113. package/dist/stages/compose/LayerRenderer.js.map +0 -1
  114. package/dist/stages/compose/TransitionProcessor.js +0 -189
  115. package/dist/stages/compose/TransitionProcessor.js.map +0 -1
  116. package/dist/stages/compose/VideoComposer.js +0 -186
  117. package/dist/stages/compose/VideoComposer.js.map +0 -1
  118. package/dist/stages/compose/audio-compose.worker.d.ts +0 -79
  119. package/dist/stages/compose/audio-compose.worker.d.ts.map +0 -1
  120. package/dist/stages/compose/audio-compose.worker.js +0 -541
  121. package/dist/stages/compose/audio-compose.worker.js.map +0 -1
  122. package/dist/stages/compose/video-compose.worker.d.ts +0 -60
  123. package/dist/stages/compose/video-compose.worker.d.ts.map +0 -1
  124. package/dist/stages/compose/video-compose.worker.js +0 -369
  125. package/dist/stages/compose/video-compose.worker.js.map +0 -1
  126. package/dist/stages/decode/AudioChunkDecoder.js +0 -83
  127. package/dist/stages/decode/AudioChunkDecoder.js.map +0 -1
  128. package/dist/stages/decode/BaseDecoder.js +0 -130
  129. package/dist/stages/decode/BaseDecoder.js.map +0 -1
  130. package/dist/stages/decode/VideoChunkDecoder.js +0 -209
  131. package/dist/stages/decode/VideoChunkDecoder.js.map +0 -1
  132. package/dist/stages/decode/decode.worker.d.ts +0 -70
  133. package/dist/stages/decode/decode.worker.d.ts.map +0 -1
  134. package/dist/stages/decode/decode.worker.js.map +0 -1
  135. package/dist/stages/demux/MP3FrameParser.js +0 -186
  136. package/dist/stages/demux/MP3FrameParser.js.map +0 -1
  137. package/dist/stages/demux/MP4Demuxer.js.map +0 -1
  138. package/dist/stages/demux/audio-demux.worker.d.ts +0 -51
  139. package/dist/stages/demux/audio-demux.worker.d.ts.map +0 -1
  140. package/dist/stages/demux/audio-demux.worker.js.map +0 -1
  141. package/dist/stages/demux/video-demux.worker.d.ts +0 -48
  142. package/dist/stages/demux/video-demux.worker.d.ts.map +0 -1
  143. package/dist/stages/demux/video-demux.worker.js.map +0 -1
  144. package/dist/stages/encode/AudioChunkEncoder.js +0 -37
  145. package/dist/stages/encode/AudioChunkEncoder.js.map +0 -1
  146. package/dist/stages/encode/BaseEncoder.js +0 -164
  147. package/dist/stages/encode/BaseEncoder.js.map +0 -1
  148. package/dist/stages/encode/VideoChunkEncoder.js +0 -50
  149. package/dist/stages/encode/VideoChunkEncoder.js.map +0 -1
  150. package/dist/stages/encode/encode.worker.d.ts +0 -3
  151. package/dist/stages/encode/encode.worker.d.ts.map +0 -1
  152. package/dist/stages/encode/encode.worker.js.map +0 -1
  153. package/dist/stages/mux/MP4Muxer.js.map +0 -1
  154. package/dist/stages/mux/mux.worker.d.ts +0 -65
  155. package/dist/stages/mux/mux.worker.d.ts.map +0 -1
  156. package/dist/stages/mux/mux.worker.js +0 -219
  157. package/dist/stages/mux/mux.worker.js.map +0 -1
  158. package/dist/stages/mux/utils.js +0 -34
  159. package/dist/stages/mux/utils.js.map +0 -1
@@ -0,0 +1,145 @@
1
+ import { existsSync, readFileSync, readdirSync, statSync, mkdirSync, copyFileSync } from "fs";
2
+ import { join, dirname, resolve } from "path";
3
+ const DEFAULT_WORKER_PATH = "meframe-workers";
4
+ function findCoreWorkerFiles() {
5
+ const findWorkers = (dir) => {
6
+ if (!existsSync(dir)) return [];
7
+ const files = [];
8
+ const entries = readdirSync(dir);
9
+ for (const entry of entries) {
10
+ const fullPath = join(dir, entry);
11
+ const stat = statSync(fullPath);
12
+ if (stat.isDirectory()) {
13
+ files.push(...findWorkers(fullPath));
14
+ } else if (entry.endsWith(".worker.js") || entry.endsWith(".worker.js.map")) {
15
+ files.push(fullPath);
16
+ }
17
+ }
18
+ return files;
19
+ };
20
+ try {
21
+ const corePackagePath = require.resolve("@meframe/core/package.json");
22
+ const coreDir = dirname(corePackagePath);
23
+ const workersDir = join(coreDir, "dist", "workers");
24
+ if (!existsSync(workersDir)) {
25
+ return null;
26
+ }
27
+ const files = findWorkers(workersDir);
28
+ return files.length > 0 ? { dir: workersDir, files } : null;
29
+ } catch {
30
+ const monorepoPath = resolve(process.cwd(), "../core/dist/workers");
31
+ if (!existsSync(monorepoPath)) {
32
+ return null;
33
+ }
34
+ const files = findWorkers(monorepoPath);
35
+ return files.length > 0 ? { dir: monorepoPath, files } : null;
36
+ }
37
+ }
38
+ function meframePlugin(options = {}) {
39
+ const { workerPath = DEFAULT_WORKER_PATH, verbose = false } = options;
40
+ let config;
41
+ let coreWorkers = null;
42
+ return {
43
+ name: "vite-plugin-meframe",
44
+ configResolved(resolvedConfig) {
45
+ config = resolvedConfig;
46
+ coreWorkers = findCoreWorkerFiles();
47
+ if (!coreWorkers && config.command === "serve") {
48
+ console.warn("[meframe] Cannot find @meframe/core worker files");
49
+ console.warn("[meframe] Make sure @meframe/core is installed and built");
50
+ }
51
+ },
52
+ configureServer(server) {
53
+ const workers = findCoreWorkerFiles();
54
+ if (!workers) {
55
+ console.warn("[meframe] Worker files not found for development");
56
+ return;
57
+ }
58
+ const workersSourceDir = workers.dir;
59
+ server.middlewares.use((req, res, next) => {
60
+ const url = req.url;
61
+ if (!url || !url.startsWith(`/${workerPath}/`)) {
62
+ next();
63
+ return;
64
+ }
65
+ const relativePath = url.substring(`/${workerPath}/`.length).split("?")[0];
66
+ if (!relativePath) {
67
+ next();
68
+ return;
69
+ }
70
+ const filePath = join(workersSourceDir, relativePath);
71
+ if (existsSync(filePath)) {
72
+ try {
73
+ const content = readFileSync(filePath);
74
+ const isSourceMap = relativePath.endsWith(".map");
75
+ res.setHeader(
76
+ "Content-Type",
77
+ isSourceMap ? "application/json" : "application/javascript"
78
+ );
79
+ res.setHeader("Cache-Control", "no-cache");
80
+ res.end(content);
81
+ if (verbose) {
82
+ console.log(`[meframe] Served: ${relativePath}`);
83
+ }
84
+ return;
85
+ } catch (error) {
86
+ console.error(`[meframe] Error serving ${relativePath}:`, error);
87
+ res.statusCode = 500;
88
+ res.end("Internal Server Error");
89
+ return;
90
+ }
91
+ }
92
+ next();
93
+ });
94
+ console.log(`[meframe] Development: serving worker files from ${workersSourceDir}`);
95
+ },
96
+ closeBundle() {
97
+ if (config.command !== "build" || !coreWorkers) {
98
+ return;
99
+ }
100
+ try {
101
+ const copyDir = (src, dest) => {
102
+ if (!existsSync(src)) return;
103
+ mkdirSync(dest, { recursive: true });
104
+ const entries = readdirSync(src);
105
+ for (const entry of entries) {
106
+ const srcPath = join(src, entry);
107
+ const destPath = join(dest, entry);
108
+ const stat = statSync(srcPath);
109
+ if (stat.isDirectory()) {
110
+ copyDir(srcPath, destPath);
111
+ } else {
112
+ copyFileSync(srcPath, destPath);
113
+ }
114
+ }
115
+ };
116
+ const workersSourceDir = coreWorkers.dir;
117
+ const outDir = config.build.outDir || "dist";
118
+ const outputDir = join(process.cwd(), outDir, workerPath);
119
+ copyDir(workersSourceDir, outputDir);
120
+ console.log(`
121
+ [meframe] ✓ Copied worker files to ${outDir}/${workerPath}/`);
122
+ } catch (error) {
123
+ console.error("[meframe] Error in meframePlugin:", error);
124
+ }
125
+ },
126
+ config() {
127
+ return {
128
+ worker: {
129
+ format: "es"
130
+ },
131
+ server: {
132
+ fs: {
133
+ // Allow access to @meframe/core in node_modules
134
+ allow: [".."]
135
+ }
136
+ }
137
+ };
138
+ }
139
+ };
140
+ }
141
+ export {
142
+ meframePlugin as default,
143
+ meframePlugin
144
+ };
145
+ //# sourceMappingURL=vite-plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vite-plugin.js","sources":["../src/vite-plugin.ts"],"sourcesContent":["/**\n * Vite Plugin for @meframe/core\n *\n * Provides unified worker file access in both development and production:\n * - Development: Serves workers via middleware from node_modules\n * - Production: Copies workers to output directory\n *\n * This ensures workers are always accessible at a consistent path.\n *\n * Usage:\n * ```typescript\n * // vite.config.ts\n * import { meframePlugin } from '@meframe/core/vite-plugin';\n *\n * export default defineConfig({\n * plugins: [meframePlugin()]\n * });\n * ```\n */\n\nimport type { Plugin, ResolvedConfig, ViteDevServer } from 'vite';\nimport { copyFileSync, mkdirSync, existsSync, readdirSync, statSync, readFileSync } from 'fs';\nimport { join, dirname, resolve } from 'path';\n\n/**\n * Default worker path (matches config/defaults.ts)\n */\nconst DEFAULT_WORKER_PATH = 'meframe-workers';\n\nexport interface MeframePluginOptions {\n /**\n * Virtual path prefix for worker files\n * Workers will be accessible at /{workerPath}/xxx.worker.js\n * Must match the workerPath in Meframe global config\n * @default 'meframe-workers'\n */\n workerPath?: string;\n\n /**\n * Enable verbose logging\n * @default false\n */\n verbose?: boolean;\n}\n\n/**\n * Find @meframe/core worker files\n * Workers are in dist/workers/ (built separately)\n */\nfunction findCoreWorkerFiles(): { dir: string; files: string[] } | null {\n const findWorkers = (dir: string): string[] => {\n if (!existsSync(dir)) return [];\n\n const files: string[] = [];\n const entries = readdirSync(dir);\n\n for (const entry of entries) {\n const fullPath = join(dir, entry);\n const stat = statSync(fullPath);\n\n if (stat.isDirectory()) {\n files.push(...findWorkers(fullPath));\n } else if (entry.endsWith('.worker.js') || entry.endsWith('.worker.js.map')) {\n files.push(fullPath);\n }\n }\n\n return files;\n };\n\n try {\n // Try to resolve from node_modules\n const corePackagePath = require.resolve('@meframe/core/package.json');\n const coreDir = dirname(corePackagePath);\n const workersDir = join(coreDir, 'dist', 'workers');\n\n if (!existsSync(workersDir)) {\n return null;\n }\n\n const files = findWorkers(workersDir);\n return files.length > 0 ? { dir: workersDir, files } : null;\n } catch {\n // Fallback for monorepo development\n const monorepoPath = resolve(process.cwd(), '../core/dist/workers');\n if (!existsSync(monorepoPath)) {\n return null;\n }\n\n const files = findWorkers(monorepoPath);\n return files.length > 0 ? { dir: monorepoPath, files } : null;\n }\n}\n\nexport function meframePlugin(options: MeframePluginOptions = {}): Plugin {\n const { workerPath = DEFAULT_WORKER_PATH, verbose = false } = options;\n let config: ResolvedConfig;\n let coreWorkers: { dir: string; files: string[] } | null = null;\n\n return {\n name: 'vite-plugin-meframe',\n\n configResolved(resolvedConfig) {\n config = resolvedConfig;\n coreWorkers = findCoreWorkerFiles();\n\n if (!coreWorkers && config.command === 'serve') {\n console.warn('[meframe] Cannot find @meframe/core worker files');\n console.warn('[meframe] Make sure @meframe/core is installed and built');\n }\n },\n\n configureServer(server: ViteDevServer) {\n // Development mode: Serve worker files via middleware\n const workers = findCoreWorkerFiles();\n\n if (!workers) {\n console.warn('[meframe] Worker files not found for development');\n return;\n }\n\n const workersSourceDir = workers.dir; // dist/workers\n\n // Middleware to serve files from dist/workers\n server.middlewares.use((req, res, next) => {\n const url = req.url;\n if (!url || !url.startsWith(`/${workerPath}/`)) {\n next();\n return;\n }\n\n // Remove the workerPath prefix to get relative path\n // e.g., /meframe-workers/stages/decode/decode.worker.js -> stages/decode/decode.worker.js\n const relativePath = url.substring(`/${workerPath}/`.length).split('?')[0];\n\n if (!relativePath) {\n next();\n return;\n }\n\n const filePath = join(workersSourceDir, relativePath);\n\n // Check if file exists\n if (existsSync(filePath)) {\n try {\n const content = readFileSync(filePath);\n const isSourceMap = relativePath.endsWith('.map');\n\n res.setHeader(\n 'Content-Type',\n isSourceMap ? 'application/json' : 'application/javascript'\n );\n res.setHeader('Cache-Control', 'no-cache');\n res.end(content);\n\n if (verbose) {\n console.log(`[meframe] Served: ${relativePath}`);\n }\n return;\n } catch (error) {\n console.error(`[meframe] Error serving ${relativePath}:`, error);\n res.statusCode = 500;\n res.end('Internal Server Error');\n return;\n }\n }\n\n next();\n });\n\n console.log(`[meframe] Development: serving worker files from ${workersSourceDir}`);\n },\n\n closeBundle() {\n // Only run in build mode\n if (config.command !== 'build' || !coreWorkers) {\n return;\n }\n\n try {\n const copyDir = (src: string, dest: string) => {\n if (!existsSync(src)) return;\n\n mkdirSync(dest, { recursive: true });\n const entries = readdirSync(src);\n\n for (const entry of entries) {\n const srcPath = join(src, entry);\n const destPath = join(dest, entry);\n const stat = statSync(srcPath);\n\n if (stat.isDirectory()) {\n copyDir(srcPath, destPath);\n } else {\n copyFileSync(srcPath, destPath);\n }\n }\n };\n\n const workersSourceDir = coreWorkers.dir; // dist/workers\n const outDir = config.build.outDir || 'dist';\n const outputDir = join(process.cwd(), outDir, workerPath);\n\n // Copy entire dist/workers structure\n copyDir(workersSourceDir, outputDir);\n\n // Log results\n console.log(`\\n[meframe] ✓ Copied worker files to ${outDir}/${workerPath}/`);\n } catch (error) {\n console.error('[meframe] Error in meframePlugin:', error);\n }\n },\n\n config() {\n return {\n worker: {\n format: 'es',\n },\n server: {\n fs: {\n // Allow access to @meframe/core in node_modules\n allow: ['..'],\n },\n },\n };\n },\n };\n}\n\nexport default meframePlugin;\n"],"names":[],"mappings":"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"}
@@ -4,18 +4,21 @@ import { EventBus } from '../event/EventBus';
4
4
  import { EventPayloadMap } from '../event/events';
5
5
 
6
6
  export interface WorkerPoolConfig {
7
- baseUrl: string;
8
7
  eventBus: EventBus<EventPayloadMap>;
9
8
  workerConfigs?: Record<WorkerType, any>;
10
- workerExtension?: string;
9
+ /** Worker files base path (default: '/meframe-workers') */
10
+ workerPath?: string;
11
11
  }
12
12
  export declare class WorkerPool {
13
13
  private pool;
14
- private baseUrl;
15
14
  private eventBus;
16
15
  private workerConfigs;
17
- private extension;
16
+ private workerPath;
18
17
  constructor(config: WorkerPoolConfig);
18
+ /**
19
+ * Get worker URL for a specific worker type
20
+ */
21
+ private getWorkerUrl;
19
22
  /**
20
23
  * Get or create a worker instance
21
24
  * @param type - Worker type
@@ -1 +1 @@
1
- {"version":3,"file":"WorkerPool.d.ts","sourceRoot":"","sources":["../../src/worker/WorkerPool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAA0B,MAAM,SAAS,CAAC;AAEhF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEvD,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,QAAQ,CAAC,eAAe,CAAC,CAAC;IACpC,aAAa,CAAC,EAAE,MAAM,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IACxC,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,IAAI,CAAiC;IAC7C,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAA4B;IAC5C,OAAO,CAAC,aAAa,CAAsB;IAC3C,OAAO,CAAC,SAAS,CAAS;gBAEd,MAAM,EAAE,gBAAgB;IAOpC;;;;;;OAMG;IACG,GAAG,CACP,IAAI,EAAE,UAAU,EAChB,EAAE,CAAC,EAAE,MAAM,EACX,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,cAAc,CAAC,EAAE,OAAO,CAAA;KAAE,GACrD,OAAO,CAAC,UAAU,CAAC;IAsDhB,SAAS,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB7D;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI;IAU9C;;OAEG;IACH,YAAY,IAAI,IAAI;IAOpB;;OAEG;IACH,IAAI,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,UAAU,CAAC,CAAC,CAQrD;IAED;;OAEG;IACH,IAAI,aAAa,IAAI,MAAM,EAAE,CAE5B;IAED;;OAEG;IACH,GAAG,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO;CAI5C"}
1
+ {"version":3,"file":"WorkerPool.d.ts","sourceRoot":"","sources":["../../src/worker/WorkerPool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAA0B,MAAM,SAAS,CAAC;AAEhF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEvD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,QAAQ,CAAC,eAAe,CAAC,CAAC;IACpC,aAAa,CAAC,EAAE,MAAM,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IACxC,2DAA2D;IAC3D,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAeD,qBAAa,UAAU;IACrB,OAAO,CAAC,IAAI,CAAiC;IAC7C,OAAO,CAAC,QAAQ,CAA4B;IAC5C,OAAO,CAAC,aAAa,CAAsB;IAC3C,OAAO,CAAC,UAAU,CAAS;gBAEf,MAAM,EAAE,gBAAgB;IAMpC;;OAEG;IACH,OAAO,CAAC,YAAY;IAmBpB;;;;;;OAMG;IACG,GAAG,CACP,IAAI,EAAE,UAAU,EAChB,EAAE,CAAC,EAAE,MAAM,EACX,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,cAAc,CAAC,EAAE,OAAO,CAAA;KAAE,GACrD,OAAO,CAAC,UAAU,CAAC;IAsChB,SAAS,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB7D;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI;IAU9C;;OAEG;IACH,YAAY,IAAI,IAAI;IAOpB;;OAEG;IACH,IAAI,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,UAAU,CAAC,CAAC,CAQrD;IAED;;OAEG;IACH,IAAI,aAAa,IAAI,MAAM,EAAE,CAE5B;IAED;;OAEG;IACH,GAAG,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO;CAI5C"}
@@ -1,16 +1,40 @@
1
1
  import { BaseWorker } from "./BaseWorker.js";
2
2
  import { WorkerMessageType } from "./types.js";
3
+ const WORKER_FILE_NAMES = {
4
+ videoDemux: "video-demux",
5
+ audioDemux: "audio-demux",
6
+ decode: "decode",
7
+ videoCompose: "video-compose",
8
+ audioCompose: "audio-compose",
9
+ encode: "encode",
10
+ mux: "mux"
11
+ };
3
12
  class WorkerPool {
4
13
  pool = /* @__PURE__ */ new Map();
5
- baseUrl;
6
14
  eventBus;
7
15
  workerConfigs;
8
- extension;
16
+ workerPath;
9
17
  constructor(config) {
10
- this.baseUrl = config.baseUrl;
11
18
  this.eventBus = config.eventBus;
12
19
  this.workerConfigs = config.workerConfigs || {};
13
- this.extension = config.workerExtension || ".js";
20
+ this.workerPath = config.workerPath || "/meframe-workers";
21
+ }
22
+ /**
23
+ * Get worker URL for a specific worker type
24
+ */
25
+ getWorkerUrl(type) {
26
+ const fileName = WORKER_FILE_NAMES[type];
27
+ const stageMap = {
28
+ "video-demux": "demux",
29
+ "audio-demux": "demux",
30
+ decode: "decode",
31
+ "video-compose": "compose",
32
+ "audio-compose": "compose",
33
+ encode: "encode",
34
+ mux: "mux"
35
+ };
36
+ const stage = stageMap[fileName];
37
+ return `${this.workerPath}/stages/${stage}/${fileName}.worker.js`;
14
38
  }
15
39
  /**
16
40
  * Get or create a worker instance
@@ -23,20 +47,7 @@ class WorkerPool {
23
47
  const key = id ? `${type}#${id}` : type;
24
48
  const existing = this.pool.get(key);
25
49
  if (!existing) {
26
- const workerPaths = {
27
- videoDemux: "demux/video-demux.worker",
28
- audioDemux: "demux/audio-demux.worker",
29
- decode: "decode/decode.worker",
30
- videoCompose: "compose/video-compose.worker",
31
- audioCompose: "compose/audio-compose.worker",
32
- encode: "encode/encode.worker",
33
- mux: "mux/mux.worker"
34
- };
35
- const path = workerPaths[type];
36
- if (!path) {
37
- throw new Error(`Unknown worker type: ${type}`);
38
- }
39
- const url = `${this.baseUrl}/${path}${this.extension}`;
50
+ const url = this.getWorkerUrl(type);
40
51
  const worker = new BaseWorker({
41
52
  type,
42
53
  url,
@@ -1 +1 @@
1
- {"version":3,"file":"WorkerPool.js","sources":["../../src/worker/WorkerPool.ts"],"sourcesContent":["/**\n * WorkerPool: Manages worker instances with key-based access\n * Provides lazy creation and unified management of workers\n */\n\nimport { BaseWorker } from './BaseWorker';\nimport type { WorkerType, WorkerStatus, WorkerConfigurePayload } from './types';\nimport { WorkerMessageType } from './types';\nimport type { EventBus } from '../event/EventBus';\nimport type { EventPayloadMap } from '../event/events';\n\nexport interface WorkerPoolConfig {\n baseUrl: string; // Base URL for workers (e.g., '/src/stages' or '/dist/stages')\n eventBus: EventBus<EventPayloadMap>;\n workerConfigs?: Record<WorkerType, any>;\n workerExtension?: string; // Optional: file extension (.ts or .js)\n}\n\nexport class WorkerPool {\n private pool = new Map<string, BaseWorker>();\n private baseUrl: string;\n private eventBus: EventBus<EventPayloadMap>;\n private workerConfigs: Record<string, any>;\n private extension: string;\n\n constructor(config: WorkerPoolConfig) {\n this.baseUrl = config.baseUrl;\n this.eventBus = config.eventBus;\n this.workerConfigs = config.workerConfigs || {};\n this.extension = config.workerExtension || '.js';\n }\n\n /**\n * Get or create a worker instance\n * @param type - Worker type\n * @param id - Optional ID for per-resource or per-clip workers\n * @param options - Optional configuration\n * - lazy: If true, skip initial configure (default: false)\n */\n async get(\n type: WorkerType,\n id?: string,\n options?: { lazy?: boolean; skipInitialize?: boolean }\n ): Promise<BaseWorker> {\n const key = id ? `${type}#${id}` : type;\n\n const existing = this.pool.get(key);\n if (!existing) {\n // Convention: worker paths follow a standard structure\n const workerPaths: Record<WorkerType, string> = {\n videoDemux: 'demux/video-demux.worker',\n audioDemux: 'demux/audio-demux.worker',\n decode: 'decode/decode.worker',\n videoCompose: 'compose/video-compose.worker',\n audioCompose: 'compose/audio-compose.worker',\n encode: 'encode/encode.worker',\n mux: 'mux/mux.worker',\n };\n\n const path = workerPaths[type];\n if (!path) {\n throw new Error(`Unknown worker type: ${type}`);\n }\n\n // Build full URL: baseUrl + path + extension\n const url = `${this.baseUrl}/${path}${this.extension}`;\n\n const worker = new BaseWorker({\n type,\n url,\n eventBus: this.eventBus,\n clipId: id,\n });\n\n // Only initialize if not in lazy mode\n if (!options?.lazy && !options?.skipInitialize) {\n const config = this.workerConfigs[type];\n await worker.initialize(config);\n }\n\n this.pool.set(key, worker);\n return worker;\n }\n\n if (!options?.lazy && !options?.skipInitialize) {\n const config = this.workerConfigs[type];\n if (config) {\n await existing.send(WorkerMessageType.Configure, {\n config,\n initial: false,\n } as WorkerConfigurePayload);\n }\n }\n\n return existing;\n }\n\n async setConfig(type: WorkerType, config: any): Promise<void> {\n const existing = this.workerConfigs[type] || {};\n const mergedConfig = { ...existing, ...config };\n\n this.workerConfigs[type] = mergedConfig;\n\n for (const [key, worker] of this.pool.entries()) {\n if (key === type || key.startsWith(`${type}#`)) {\n await worker.send(WorkerMessageType.Configure, {\n config: mergedConfig,\n initial: false,\n } as WorkerConfigurePayload);\n }\n }\n }\n\n /**\n * Terminate a specific worker\n */\n terminate(type: WorkerType, id?: string): void {\n const key = id ? `${type}#${id}` : type;\n const worker = this.pool.get(key);\n\n if (worker) {\n worker.terminate();\n this.pool.delete(key);\n }\n }\n\n /**\n * Terminate all workers\n */\n terminateAll(): void {\n for (const worker of this.pool.values()) {\n worker.terminate();\n }\n this.pool.clear();\n }\n\n /**\n * Get status of all workers\n */\n get status(): Record<string, WorkerStatus[WorkerType]> {\n const result: Record<string, WorkerStatus[WorkerType]> = {};\n\n for (const [key, worker] of this.pool.entries()) {\n result[key] = worker.status;\n }\n\n return result;\n }\n\n /**\n * Get list of active worker keys\n */\n get activeWorkers(): string[] {\n return Array.from(this.pool.keys());\n }\n\n /**\n * Check if a worker exists\n */\n has(type: WorkerType, id?: string): boolean {\n const key = id ? `${type}#${id}` : type;\n return this.pool.has(key);\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"WorkerPool.js","sources":["../../src/worker/WorkerPool.ts"],"sourcesContent":["/**\n * WorkerPool: Manages worker instances with key-based access\n * Provides lazy creation and unified management of workers\n */\n\nimport { BaseWorker } from './BaseWorker';\nimport type { WorkerType, WorkerStatus, WorkerConfigurePayload } from './types';\nimport { WorkerMessageType } from './types';\nimport type { EventBus } from '../event/EventBus';\nimport type { EventPayloadMap } from '../event/events';\n\nexport interface WorkerPoolConfig {\n eventBus: EventBus<EventPayloadMap>;\n workerConfigs?: Record<WorkerType, any>;\n /** Worker files base path (default: '/meframe-workers') */\n workerPath?: string;\n}\n\n/**\n * Worker name mapping (worker type -> file name)\n */\nconst WORKER_FILE_NAMES: Record<WorkerType, string> = {\n videoDemux: 'video-demux',\n audioDemux: 'audio-demux',\n decode: 'decode',\n videoCompose: 'video-compose',\n audioCompose: 'audio-compose',\n encode: 'encode',\n mux: 'mux',\n};\n\nexport class WorkerPool {\n private pool = new Map<string, BaseWorker>();\n private eventBus: EventBus<EventPayloadMap>;\n private workerConfigs: Record<string, any>;\n private workerPath: string;\n\n constructor(config: WorkerPoolConfig) {\n this.eventBus = config.eventBus;\n this.workerConfigs = config.workerConfigs || {};\n this.workerPath = config.workerPath || '/meframe-workers';\n }\n\n /**\n * Get worker URL for a specific worker type\n */\n private getWorkerUrl(type: WorkerType): string {\n const fileName = WORKER_FILE_NAMES[type];\n\n // Map worker type to its stage directory\n const stageMap: Record<string, string> = {\n 'video-demux': 'demux',\n 'audio-demux': 'demux',\n decode: 'decode',\n 'video-compose': 'compose',\n 'audio-compose': 'compose',\n encode: 'encode',\n mux: 'mux',\n };\n const stage = stageMap[fileName];\n\n // Workers are in stages subdirectory\n return `${this.workerPath}/stages/${stage}/${fileName}.worker.js`;\n }\n\n /**\n * Get or create a worker instance\n * @param type - Worker type\n * @param id - Optional ID for per-resource or per-clip workers\n * @param options - Optional configuration\n * - lazy: If true, skip initial configure (default: false)\n */\n async get(\n type: WorkerType,\n id?: string,\n options?: { lazy?: boolean; skipInitialize?: boolean }\n ): Promise<BaseWorker> {\n const key = id ? `${type}#${id}` : type;\n\n const existing = this.pool.get(key);\n if (!existing) {\n // Generate worker URL based on worker path and type\n const url = this.getWorkerUrl(type);\n\n const worker = new BaseWorker({\n type,\n url,\n eventBus: this.eventBus,\n clipId: id,\n });\n\n // Only initialize if not in lazy mode\n if (!options?.lazy && !options?.skipInitialize) {\n const config = this.workerConfigs[type];\n await worker.initialize(config);\n }\n\n this.pool.set(key, worker);\n return worker;\n }\n\n if (!options?.lazy && !options?.skipInitialize) {\n const config = this.workerConfigs[type];\n if (config) {\n await existing.send(WorkerMessageType.Configure, {\n config,\n initial: false,\n } as WorkerConfigurePayload);\n }\n }\n\n return existing;\n }\n\n async setConfig(type: WorkerType, config: any): Promise<void> {\n const existing = this.workerConfigs[type] || {};\n const mergedConfig = { ...existing, ...config };\n\n this.workerConfigs[type] = mergedConfig;\n\n for (const [key, worker] of this.pool.entries()) {\n if (key === type || key.startsWith(`${type}#`)) {\n await worker.send(WorkerMessageType.Configure, {\n config: mergedConfig,\n initial: false,\n } as WorkerConfigurePayload);\n }\n }\n }\n\n /**\n * Terminate a specific worker\n */\n terminate(type: WorkerType, id?: string): void {\n const key = id ? `${type}#${id}` : type;\n const worker = this.pool.get(key);\n\n if (worker) {\n worker.terminate();\n this.pool.delete(key);\n }\n }\n\n /**\n * Terminate all workers\n */\n terminateAll(): void {\n for (const worker of this.pool.values()) {\n worker.terminate();\n }\n this.pool.clear();\n }\n\n /**\n * Get status of all workers\n */\n get status(): Record<string, WorkerStatus[WorkerType]> {\n const result: Record<string, WorkerStatus[WorkerType]> = {};\n\n for (const [key, worker] of this.pool.entries()) {\n result[key] = worker.status;\n }\n\n return result;\n }\n\n /**\n * Get list of active worker keys\n */\n get activeWorkers(): string[] {\n return Array.from(this.pool.keys());\n }\n\n /**\n * Check if a worker exists\n */\n has(type: WorkerType, id?: string): boolean {\n const key = id ? `${type}#${id}` : type;\n return this.pool.has(key);\n }\n}\n"],"names":[],"mappings":"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"}
@@ -1,19 +1,17 @@
1
- import "../../node_modules/.pnpm/mp4box@0.5.4/node_modules/mp4box/dist/mp4box.all.js";
2
- import { BackpressureMonitor } from "../../plugins/BackpressureMonitor.js";
3
- import { __exports as mp4box_all } from "../../_virtual/mp4box.all.js";
1
+ import { m as mp4box_all } from "./mp4box.all.js";
4
2
  class MP4Demuxer {
5
3
  mp4boxFile;
6
4
  tracks = /* @__PURE__ */ new Map();
7
5
  isReady = false;
8
6
  videoController;
9
7
  audioController;
10
- backpressureMonitor;
11
8
  demuxHighWaterMark;
12
9
  onReadyCallback;
13
10
  fileOffset = 0;
11
+ videoTimestampOffset = null;
12
+ audioTimestampOffset = null;
14
13
  constructor(config = {}) {
15
14
  this.mp4boxFile = mp4box_all.createFile();
16
- this.backpressureMonitor = new BackpressureMonitor();
17
15
  this.onReadyCallback = config.onReady;
18
16
  const DEFAULT_HIGH_WATER_MARK = 10;
19
17
  this.demuxHighWaterMark = config.highWaterMark ?? DEFAULT_HIGH_WATER_MARK;
@@ -69,13 +67,17 @@ class MP4Demuxer {
69
67
  if (!track) return;
70
68
  const timescale = track.timescale || 9e4;
71
69
  for (const sample of samples) {
72
- const timestamp = sample.cts * 1e6 / timescale;
70
+ const rawTimestamp = sample.cts * 1e6 / timescale;
73
71
  const duration = sample.duration * 1e6 / timescale;
74
72
  if (track.type === "video") {
75
73
  if (!this.videoController) {
76
74
  console.error("[MP4Demuxer] videoController is null when trying to output chunk!");
77
75
  return;
78
76
  }
77
+ if (this.videoTimestampOffset === null) {
78
+ this.videoTimestampOffset = rawTimestamp;
79
+ }
80
+ const timestamp = rawTimestamp - this.videoTimestampOffset;
79
81
  const chunk = new EncodedVideoChunk({
80
82
  type: sample.is_sync ? "key" : "delta",
81
83
  timestamp,
@@ -84,6 +86,10 @@ class MP4Demuxer {
84
86
  });
85
87
  this.videoController.enqueue(chunk);
86
88
  } else if (track.type === "audio" && this.audioController) {
89
+ if (this.audioTimestampOffset === null) {
90
+ this.audioTimestampOffset = rawTimestamp;
91
+ }
92
+ const timestamp = rawTimestamp - this.audioTimestampOffset;
87
93
  const chunk = new EncodedAudioChunk({
88
94
  type: "key",
89
95
  timestamp,
@@ -145,9 +151,7 @@ class MP4Demuxer {
145
151
  start: (controller) => {
146
152
  this.videoController = controller;
147
153
  },
148
- transform: (chunk, controller) => {
149
- const desiredSize = controller.desiredSize ?? this.demuxHighWaterMark;
150
- this.backpressureMonitor.updateMetrics("demux-video", desiredSize);
154
+ transform: (chunk, _controller) => {
151
155
  const chunkData = new Uint8Array(chunk);
152
156
  this.appendBuffer(chunkData);
153
157
  this.mp4boxFile.flush();
@@ -155,7 +159,6 @@ class MP4Demuxer {
155
159
  flush: async () => {
156
160
  this.mp4boxFile.flush();
157
161
  await new Promise((resolve) => setTimeout(resolve, 100));
158
- console.log("[MP4Demuxer] Video stream flush complete");
159
162
  }
160
163
  },
161
164
  // Queuing strategy: use configuration
@@ -177,9 +180,7 @@ class MP4Demuxer {
177
180
  start: (controller) => {
178
181
  this.audioController = controller;
179
182
  },
180
- transform: (chunk, controller) => {
181
- const desiredSize = controller.desiredSize ?? this.demuxHighWaterMark;
182
- this.backpressureMonitor.updateMetrics("demux-audio", desiredSize);
183
+ transform: (chunk, _controller) => {
183
184
  const chunkData = new Uint8Array(chunk);
184
185
  this.appendBuffer(chunkData);
185
186
  this.mp4boxFile.flush();
@@ -217,11 +218,12 @@ class MP4Demuxer {
217
218
  this.mp4boxFile?.stop();
218
219
  this.mp4boxFile = null;
219
220
  this.tracks.clear();
220
- this.backpressureMonitor.clear();
221
221
  this.isReady = false;
222
+ this.videoTimestampOffset = null;
223
+ this.audioTimestampOffset = null;
222
224
  }
223
225
  }
224
226
  export {
225
- MP4Demuxer
227
+ MP4Demuxer as M
226
228
  };
227
229
  //# sourceMappingURL=MP4Demuxer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MP4Demuxer.js","sources":["../../src/stages/demux/MP4Demuxer.ts"],"sourcesContent":["import * as MP4Box from 'mp4box';\nimport type { DemuxConfig, TrackInfo } from './types';\n\n/**\n * MP4 Demuxer - Extract encoded chunks from MP4 container\n * Simplified implementation following Stream API pattern\n */\nexport class MP4Demuxer {\n private mp4boxFile: any;\n tracks = new Map<number, TrackInfo>();\n isReady = false;\n private videoController?: TransformStreamDefaultController<EncodedVideoChunk>;\n private audioController?: TransformStreamDefaultController<EncodedAudioChunk>;\n private demuxHighWaterMark: number;\n private onReadyCallback?: () => void;\n private fileOffset = 0;\n private videoTimestampOffset: number | null = null;\n private audioTimestampOffset: number | null = null;\n\n constructor(config: DemuxConfig & { onReady?: () => void } = {}) {\n this.mp4boxFile = MP4Box.createFile();\n this.onReadyCallback = config.onReady;\n\n // Use provided config with local default as fallback\n const DEFAULT_HIGH_WATER_MARK = 10; // Default for video chunks\n this.demuxHighWaterMark = config.highWaterMark ?? DEFAULT_HIGH_WATER_MARK;\n\n this.setupHandlers();\n }\n\n updateConfig(config: DemuxConfig): void {\n this.demuxHighWaterMark = config.highWaterMark ?? this.demuxHighWaterMark;\n }\n\n private setupHandlers(): void {\n this.mp4boxFile.onError = (error: string) => {\n console.error('MP4Box error:', error);\n this.videoController?.error(new Error(error));\n this.audioController?.error(new Error(error));\n };\n\n this.mp4boxFile.onReady = (info: any) => {\n this.processTracks(info.tracks);\n this.isReady = true;\n\n // Call the ready callback before starting\n if (this.onReadyCallback) {\n this.onReadyCallback();\n }\n\n // Start processing samples after callback\n // Note: start() enables extraction, actual samples will be output\n // when flush() is called (by TransformStream's flush callback)\n this.mp4boxFile.start();\n };\n\n this.mp4boxFile.onSamples = (trackId: number, _user: any, samples: any[]) => {\n this.processSamples(trackId, samples);\n };\n }\n\n private processTracks(tracks: any[]): void {\n for (const track of tracks) {\n const trackInfo: TrackInfo = {\n id: track.id,\n type: track.type === 'video' ? 'video' : 'audio',\n codec: track.codec,\n timescale: track.timescale,\n };\n\n if (track.type === 'video') {\n trackInfo.width = track.video?.width;\n trackInfo.height = track.video?.height;\n trackInfo.description = this.getVideoDescription(track);\n } else if (track.type === 'audio') {\n trackInfo.sampleRate = track.audio?.sample_rate;\n trackInfo.numberOfChannels = track.audio?.channel_count;\n trackInfo.description = this.getAudioDescription(track);\n }\n\n this.tracks.set(track.id, trackInfo);\n\n // Configure extraction\n this.mp4boxFile.setExtractionOptions(track.id, track, {\n nbSamples: 30, // Batch size per callback (balance between latency and overhead)\n });\n }\n }\n\n private processSamples(trackId: number, samples: any[]): void {\n const track = this.tracks.get(trackId);\n if (!track) return;\n\n const timescale = track.timescale || 90000;\n for (const sample of samples) {\n const rawTimestamp = (sample.cts * 1000000) / timescale;\n const duration = (sample.duration * 1000000) / timescale;\n\n if (track.type === 'video') {\n if (!this.videoController) {\n console.error('[MP4Demuxer] videoController is null when trying to output chunk!');\n // Should not happen - stream should be created before appendBuffer\n return;\n }\n\n // Normalize timestamp: first frame starts at 0\n if (this.videoTimestampOffset === null) {\n this.videoTimestampOffset = rawTimestamp;\n }\n const timestamp = rawTimestamp - this.videoTimestampOffset;\n\n const chunk = new EncodedVideoChunk({\n type: sample.is_sync ? 'key' : 'delta',\n timestamp,\n duration,\n data: sample.data,\n });\n this.videoController.enqueue(chunk);\n } else if (track.type === 'audio' && this.audioController) {\n // Normalize timestamp: first frame starts at 0\n if (this.audioTimestampOffset === null) {\n this.audioTimestampOffset = rawTimestamp;\n }\n const timestamp = rawTimestamp - this.audioTimestampOffset;\n\n const chunk = new EncodedAudioChunk({\n type: 'key',\n timestamp,\n duration,\n data: sample.data,\n });\n this.audioController.enqueue(chunk);\n }\n }\n\n const last = samples[samples.length - 1].number;\n // Release memory immediately\n this.mp4boxFile.releaseUsedSamples(trackId, last + 1);\n }\n\n private getVideoDescription(track: any): ArrayBuffer | undefined {\n try {\n const fullTrack = this.mp4boxFile.getTrackById(track.id);\n for (const entry of fullTrack.mdia.minf.stbl.stsd.entries) {\n const box = entry.avcC ?? entry.hvcC ?? entry.av1C ?? entry.vpcC;\n if (box) {\n const stream = new (MP4Box as any).DataStream(\n undefined,\n 0,\n (MP4Box as any).DataStream.BIG_ENDIAN // IMPORTANT: must be BIG_ENDIAN\n );\n box.write(stream);\n return new Uint8Array(stream.buffer.slice(8)).buffer;\n }\n }\n } catch (error) {\n console.error('Failed to get video description:', error);\n }\n return undefined;\n }\n\n // private getVideoDescription(track: any): ArrayBuffer | undefined {\n // if (!this.mp4boxFile) return undefined;\n // return getVideoDescription(this.mp4boxFile, track);\n // }\n\n private getAudioDescription(track: any): ArrayBuffer | undefined {\n try {\n const fullTrack = this.mp4boxFile.getTrackById(track.id);\n for (const entry of fullTrack.mdia.minf.stbl.stsd.entries) {\n if (entry.esds || entry.dOps) {\n const stream = new (MP4Box as any).DataStream();\n (entry.esds || entry.dOps).write(stream);\n return new Uint8Array(stream.buffer.slice(8)).buffer;\n }\n }\n } catch (error) {\n console.error('Failed to get audio description:', error);\n }\n return undefined;\n }\n\n /**\n * Create transform stream for video track\n */\n createVideoStream(): TransformStream<Uint8Array, EncodedVideoChunk> {\n // const hasVideo = Array.from(this.tracks.values()).some((t) => t.type === 'video');\n return new TransformStream<Uint8Array, EncodedVideoChunk>(\n {\n start: (controller) => {\n this.videoController = controller;\n },\n transform: (chunk, _controller) => {\n // Create a copy to avoid buffer reuse issues (required for mp4box 0.5.x)\n const chunkData = new Uint8Array(chunk);\n this.appendBuffer(chunkData);\n\n // Flush after each append to trigger sample extraction immediately\n this.mp4boxFile.flush();\n },\n flush: async () => {\n // Trigger MP4Box flush\n this.mp4boxFile.flush();\n\n // Wait for MP4Box to complete sample extraction (onSamples callbacks)\n // Give MP4Box time to process asynchronously\n await new Promise((resolve) => setTimeout(resolve, 100));\n },\n },\n // Queuing strategy: use configuration\n {\n highWaterMark: this.demuxHighWaterMark,\n size: () => 1, // Count-based\n }\n );\n }\n\n /**\n * Create transform stream for audio track\n */\n createAudioStream(): TransformStream<Uint8Array, EncodedAudioChunk> | null {\n const hasAudio = Array.from(this.tracks.values()).some((t) => t.type === 'audio');\n if (!hasAudio) return null;\n\n return new TransformStream<Uint8Array, EncodedAudioChunk>(\n {\n start: (controller) => {\n this.audioController = controller;\n },\n transform: (chunk, _controller) => {\n // Create a copy to avoid buffer reuse issues (required for mp4box 0.5.x)\n const chunkData = new Uint8Array(chunk);\n this.appendBuffer(chunkData);\n\n // Flush after each append to trigger sample extraction immediately\n this.mp4boxFile.flush();\n },\n flush: () => {\n this.mp4boxFile.flush();\n },\n },\n // Queuing strategy: use configuration\n {\n highWaterMark: this.demuxHighWaterMark,\n size: () => 1,\n }\n );\n }\n\n appendBuffer(chunk: Uint8Array): void {\n const buffer = chunk.buffer as ArrayBuffer & { fileStart: number };\n buffer.fileStart = this.fileOffset;\n this.mp4boxFile.appendBuffer(buffer);\n this.fileOffset += chunk.byteLength;\n }\n\n /**\n * Get video track info if available\n */\n get videoTrackInfo(): TrackInfo | undefined {\n return Array.from(this.tracks.values()).find((track) => track.type === 'video');\n }\n\n /**\n * Get audio track info if available\n */\n get audioTrackInfo(): TrackInfo | undefined {\n return Array.from(this.tracks.values()).find((track) => track.type === 'audio');\n }\n\n destroy(): void {\n this.mp4boxFile?.stop();\n this.mp4boxFile = null;\n this.tracks.clear();\n this.isReady = false;\n this.videoTimestampOffset = null;\n this.audioTimestampOffset = null;\n }\n}\n"],"names":["MP4Box.createFile","MP4Box.DataStream"],"mappings":"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"}