@elah/core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/dist/actions/index.d.ts +3 -0
  2. package/dist/actions/index.js +1 -0
  3. package/dist/actions/splitClipAtPlayhead.d.ts +8 -0
  4. package/dist/actions/splitClipAtPlayhead.js +34 -0
  5. package/dist/actions/types.d.ts +8 -0
  6. package/dist/actions/types.js +1 -0
  7. package/dist/assets/importFiles.d.ts +29 -0
  8. package/dist/assets/importFiles.js +351 -0
  9. package/dist/assets/index.d.ts +10 -0
  10. package/dist/assets/index.js +13 -0
  11. package/dist/assets/store.d.ts +13 -0
  12. package/dist/assets/store.js +20 -0
  13. package/dist/assets/types.d.ts +23 -0
  14. package/dist/assets/types.js +1 -0
  15. package/dist/debug/trace.d.ts +20 -0
  16. package/dist/debug/trace.js +98 -0
  17. package/dist/editor/TimelineEngine.d.ts +65 -0
  18. package/dist/editor/TimelineEngine.js +413 -0
  19. package/dist/editor-context.d.ts +10 -0
  20. package/dist/editor-context.js +10 -0
  21. package/dist/elements/audio.d.ts +13 -0
  22. package/dist/elements/audio.js +4 -0
  23. package/dist/elements/base.d.ts +40 -0
  24. package/dist/elements/base.js +39 -0
  25. package/dist/elements/image.d.ts +13 -0
  26. package/dist/elements/image.js +4 -0
  27. package/dist/elements/text.d.ts +12 -0
  28. package/dist/elements/text.js +8 -0
  29. package/dist/elements/video.d.ts +13 -0
  30. package/dist/elements/video.js +4 -0
  31. package/dist/export/ExportWorker.d.ts +1 -0
  32. package/dist/export/ExportWorker.js +371 -0
  33. package/dist/export/exportVideo.d.ts +3 -0
  34. package/dist/export/exportVideo.js +118 -0
  35. package/dist/export/index.d.ts +2 -0
  36. package/dist/export/index.js +1 -0
  37. package/dist/export/lazyExport.d.ts +4 -0
  38. package/dist/export/lazyExport.js +4 -0
  39. package/dist/export/types.d.ts +37 -0
  40. package/dist/export/types.js +1 -0
  41. package/dist/index.d.ts +48 -0
  42. package/dist/index.js +28 -0
  43. package/dist/media/audio/AudioPlaybackController.d.ts +26 -0
  44. package/dist/media/audio/AudioPlaybackController.js +125 -0
  45. package/dist/media/video/DecoderBackedVideoFrameProvider.d.ts +51 -0
  46. package/dist/media/video/DecoderBackedVideoFrameProvider.js +125 -0
  47. package/dist/media/video/FrameCache.d.ts +28 -0
  48. package/dist/media/video/FrameCache.js +88 -0
  49. package/dist/media/video/StreamingFrameProducer.d.ts +57 -0
  50. package/dist/media/video/StreamingFrameProducer.js +356 -0
  51. package/dist/media/video/VideoDecoderManager.d.ts +59 -0
  52. package/dist/media/video/VideoDecoderManager.js +342 -0
  53. package/dist/media/video/VideoFrameProvider.d.ts +101 -0
  54. package/dist/media/video/VideoFrameProvider.js +257 -0
  55. package/dist/media/video/demuxer/MediabunnyDemuxer.d.ts +23 -0
  56. package/dist/media/video/demuxer/MediabunnyDemuxer.js +88 -0
  57. package/dist/media/video/demuxer/createMediabunnyBackend.d.ts +32 -0
  58. package/dist/media/video/demuxer/createMediabunnyBackend.js +156 -0
  59. package/dist/media/video/index.d.ts +8 -0
  60. package/dist/media/video/index.js +5 -0
  61. package/dist/playback/PlaybackEngine.d.ts +50 -0
  62. package/dist/playback/PlaybackEngine.js +188 -0
  63. package/dist/renderer/gpu/GpuRenderer.d.ts +38 -0
  64. package/dist/renderer/gpu/GpuRenderer.js +208 -0
  65. package/dist/renderer/gpu/RenderGraph.d.ts +10 -0
  66. package/dist/renderer/gpu/RenderGraph.js +80 -0
  67. package/dist/renderer/gpu/ShaderProgram.d.ts +14 -0
  68. package/dist/renderer/gpu/ShaderProgram.js +76 -0
  69. package/dist/renderer/gpu/TexturePool.d.ts +25 -0
  70. package/dist/renderer/gpu/TexturePool.js +93 -0
  71. package/dist/renderer/gpu/VideoTexture.d.ts +13 -0
  72. package/dist/renderer/gpu/VideoTexture.js +54 -0
  73. package/dist/renderer/gpu/WebGLContext.d.ts +28 -0
  74. package/dist/renderer/gpu/WebGLContext.js +102 -0
  75. package/dist/renderer/gpu/debug/DebugGpuRenderer.d.ts +27 -0
  76. package/dist/renderer/gpu/debug/DebugGpuRenderer.js +108 -0
  77. package/dist/renderer/gpu/debug/DebugOverlay.d.ts +17 -0
  78. package/dist/renderer/gpu/debug/DebugOverlay.js +83 -0
  79. package/dist/renderer/gpu/debug/GpuDebugCounters.d.ts +38 -0
  80. package/dist/renderer/gpu/debug/GpuDebugCounters.js +72 -0
  81. package/dist/renderer/gpu/debug/GpuDebugGlobal.d.ts +16 -0
  82. package/dist/renderer/gpu/debug/GpuDebugGlobal.js +14 -0
  83. package/dist/renderer/gpu/debug/GpuRendererDebugPanel.d.ts +31 -0
  84. package/dist/renderer/gpu/debug/GpuRendererDebugPanel.js +128 -0
  85. package/dist/renderer/gpu/debug/RecordingGl.d.ts +88 -0
  86. package/dist/renderer/gpu/debug/RecordingGl.js +214 -0
  87. package/dist/renderer/gpu/debug/playground.d.ts +20 -0
  88. package/dist/renderer/gpu/debug/playground.js +64 -0
  89. package/dist/renderer/gpu/debug/scenarios.d.ts +7 -0
  90. package/dist/renderer/gpu/debug/scenarios.js +145 -0
  91. package/dist/renderer/gpu/debug/types.d.ts +16 -0
  92. package/dist/renderer/gpu/debug/types.js +1 -0
  93. package/dist/renderer/gpu/layers/FrameProbeLayer.d.ts +16 -0
  94. package/dist/renderer/gpu/layers/FrameProbeLayer.js +127 -0
  95. package/dist/renderer/gpu/layers/ImageLayer.d.ts +23 -0
  96. package/dist/renderer/gpu/layers/ImageLayer.js +124 -0
  97. package/dist/renderer/gpu/layers/TestLayer.d.ts +16 -0
  98. package/dist/renderer/gpu/layers/TestLayer.js +109 -0
  99. package/dist/renderer/gpu/layers/TextLayer.d.ts +19 -0
  100. package/dist/renderer/gpu/layers/TextLayer.js +166 -0
  101. package/dist/renderer/gpu/layers/VideoLayer.d.ts +38 -0
  102. package/dist/renderer/gpu/layers/VideoLayer.js +194 -0
  103. package/dist/renderer/gpu/layers/drawRect.d.ts +13 -0
  104. package/dist/renderer/gpu/layers/drawRect.js +55 -0
  105. package/dist/renderer/gpu/layers/objectFit.d.ts +7 -0
  106. package/dist/renderer/gpu/layers/objectFit.js +26 -0
  107. package/dist/renderer/gpu/layers/textLayout.d.ts +47 -0
  108. package/dist/renderer/gpu/layers/textLayout.js +82 -0
  109. package/dist/renderer/gpu/layers/types.d.ts +18 -0
  110. package/dist/renderer/gpu/layers/types.js +1 -0
  111. package/dist/renderer/gpu/shaders/quad.frag.d.ts +1 -0
  112. package/dist/renderer/gpu/shaders/quad.frag.js +14 -0
  113. package/dist/renderer/gpu/shaders/quad.vert.d.ts +1 -0
  114. package/dist/renderer/gpu/shaders/quad.vert.js +28 -0
  115. package/dist/renderer/gpu/types.d.ts +21 -0
  116. package/dist/renderer/gpu/types.js +1 -0
  117. package/dist/renderer/gpu/viewport.d.ts +7 -0
  118. package/dist/renderer/gpu/viewport.js +33 -0
  119. package/dist/renderer/types.d.ts +7 -0
  120. package/dist/renderer/types.js +1 -0
  121. package/dist/resolver/resolveTimeline.d.ts +3 -0
  122. package/dist/resolver/resolveTimeline.js +249 -0
  123. package/dist/resolver/scene.d.ts +54 -0
  124. package/dist/resolver/scene.js +1 -0
  125. package/dist/stores/playback.store.d.ts +50 -0
  126. package/dist/stores/playback.store.js +42 -0
  127. package/dist/stores/selection.store.d.ts +12 -0
  128. package/dist/stores/selection.store.js +19 -0
  129. package/dist/stores/tracks.store.d.ts +19 -0
  130. package/dist/stores/tracks.store.js +27 -0
  131. package/dist/stores/transitions.store.d.ts +9 -0
  132. package/dist/stores/transitions.store.js +7 -0
  133. package/dist/track/track.d.ts +8 -0
  134. package/dist/track/track.js +19 -0
  135. package/dist/types/index.d.ts +117 -0
  136. package/dist/types/index.js +1 -0
  137. package/dist/utils/frames.d.ts +20 -0
  138. package/dist/utils/frames.js +40 -0
  139. package/dist/utils/id.d.ts +1 -0
  140. package/dist/utils/id.js +3 -0
  141. package/dist/utils/snap.d.ts +5 -0
  142. package/dist/utils/snap.js +79 -0
  143. package/dist/visitor/add.d.ts +3 -0
  144. package/dist/visitor/add.js +16 -0
  145. package/dist/visitor/clone.d.ts +3 -0
  146. package/dist/visitor/clone.js +25 -0
  147. package/dist/visitor/remove.d.ts +5 -0
  148. package/dist/visitor/remove.js +29 -0
  149. package/dist/visitor/split.d.ts +3 -0
  150. package/dist/visitor/split.js +31 -0
  151. package/dist/visitor/update.d.ts +4 -0
  152. package/dist/visitor/update.js +31 -0
  153. package/package.json +31 -0
@@ -0,0 +1,356 @@
1
+ import { FrameCache } from './FrameCache';
2
+ import { GpuDebugCounters } from '../../renderer/gpu/debug/GpuDebugCounters';
3
+ import { VideoDecoderManager } from './VideoDecoderManager';
4
+ const DEFAULT_FPS = 30;
5
+ const DEFAULT_LOOKAHEAD_FRAMES = 16;
6
+ const DEFAULT_MAX_FRAMES = 30;
7
+ function makeFallbackBitmap(frame) {
8
+ return {
9
+ width: frame.displayWidth,
10
+ height: frame.displayHeight,
11
+ close() { },
12
+ };
13
+ }
14
+ const defaultFrameConverter = typeof createImageBitmap !== 'undefined'
15
+ ? (frame) => createImageBitmap(frame, { imageOrientation: 'flipY' })
16
+ : (frame) => Promise.resolve(makeFallbackBitmap(frame));
17
+ const DEFAULT_IDLE_TIMEOUT_MS = 5000;
18
+ const STALL_TICKS_BEFORE_RESET = 45;
19
+ function _sfpTrace(msg, data) {
20
+ if (typeof globalThis !== 'undefined' && globalThis.__SFP_DEBUG__) {
21
+ if (data) {
22
+ console.log(`[SFP-TRACE] ${msg}`, data);
23
+ }
24
+ else {
25
+ console.log(`[SFP-TRACE] ${msg}`);
26
+ }
27
+ }
28
+ }
29
+ export class StreamingFrameProducer {
30
+ constructor(opts) {
31
+ this._state = 'active';
32
+ this._lastPlayhead = null;
33
+ this._latestPlayhead = null;
34
+ this._feedWatermark = -1;
35
+ this._highestDecodedFrame = -1;
36
+ this._ticksSinceDecodeAdvance = 0;
37
+ this._resetInProgress = false;
38
+ this._lastLoggedPlayhead = null;
39
+ this._idleTimer = null;
40
+ this._idleCallback = null;
41
+ this._openPromise = null;
42
+ this._openError = null;
43
+ this._reopening = false;
44
+ this._src = opts.src;
45
+ this._fps = opts.fps ?? DEFAULT_FPS;
46
+ this._lookaheadFrames = opts.lookaheadFrames ?? DEFAULT_LOOKAHEAD_FRAMES;
47
+ this._usPerFrame = 1000000 / this._fps;
48
+ this._convert = opts.frameConverter ?? defaultFrameConverter;
49
+ this._cache = new FrameCache({
50
+ maxFrames: opts.maxFrames ?? DEFAULT_MAX_FRAMES,
51
+ hooks: opts.cacheHooks,
52
+ });
53
+ this._manager = new VideoDecoderManager({
54
+ fps: this._fps,
55
+ demuxerFactory: opts.demuxerFactory,
56
+ decoderFactory: opts.decoderFactory,
57
+ onDroppedFrame: () => {
58
+ GpuDebugCounters.incDropped();
59
+ },
60
+ onError: (err) => {
61
+ if (this._state === 'disposed' || this._reopening)
62
+ return;
63
+ console.warn('[StreamingFrameProducer] decoder errored — reopening manager:', err);
64
+ this._reopening = true;
65
+ this._lastPlayhead = null;
66
+ this._feedWatermark = -1;
67
+ this._highestDecodedFrame = -1;
68
+ this._ticksSinceDecodeAdvance = 0;
69
+ this._cache.clear();
70
+ GpuDebugCounters.cacheSize = 0;
71
+ _sfpTrace('manager error → reopen + bookkeeping reset', {
72
+ error: err instanceof Error ? err.message : String(err),
73
+ });
74
+ this._openPromise = this._manager
75
+ .reopen(this._src)
76
+ .catch((reopenErr) => {
77
+ this._openError = reopenErr;
78
+ })
79
+ .finally(() => {
80
+ this._reopening = false;
81
+ });
82
+ },
83
+ });
84
+ this._manager.onFrame = (frame, sourceFrameIdx) => {
85
+ if (this._state === 'disposed') {
86
+ frame.close();
87
+ return;
88
+ }
89
+ const prevHighest = this._highestDecodedFrame;
90
+ if (prevHighest >= 0 && sourceFrameIdx > prevHighest + 1) {
91
+ _sfpTrace('onFrame INDEX GAP', {
92
+ expected: prevHighest + 1,
93
+ got: sourceFrameIdx,
94
+ skipped: sourceFrameIdx - prevHighest - 1,
95
+ rawTimestampUs: frame.timestamp,
96
+ rawIndex: frame.timestamp / this._usPerFrame,
97
+ });
98
+ }
99
+ const timestampUs = frame.timestamp;
100
+ void this._copyAndCache(frame, sourceFrameIdx, timestampUs);
101
+ };
102
+ this._openPromise = this._manager.open(this._src).catch((err) => {
103
+ this._openError = err;
104
+ });
105
+ if (typeof globalThis !== 'undefined') {
106
+ ;
107
+ globalThis.__elahDrain = () => {
108
+ _sfpTrace('__elahDrain invoked — forcing decoder flush', {
109
+ highestDecoded: this._highestDecodedFrame,
110
+ cacheSize: this._cache.size,
111
+ });
112
+ return this._manager.debugFlush();
113
+ };
114
+ }
115
+ _sfpTrace('init', {
116
+ fps: this._fps,
117
+ usPerFrame: this._usPerFrame,
118
+ lookaheadFrames: this._lookaheadFrames,
119
+ });
120
+ }
121
+ getCurrent(sourceFrame) {
122
+ if (this._state === 'disposed')
123
+ return null;
124
+ this._cache.setPivot(sourceFrame);
125
+ const frame = this._cache.get(sourceFrame, 2);
126
+ if (frame !== null) {
127
+ GpuDebugCounters.cacheHits++;
128
+ }
129
+ else {
130
+ GpuDebugCounters.cacheMisses++;
131
+ _sfpTrace('getCurrent MISS', {
132
+ sourceFrame,
133
+ cacheSize: this._cache.size,
134
+ watermark: this._feedWatermark,
135
+ managerState: this._manager.state,
136
+ cacheKeys: this._cacheKeysSnapshot(),
137
+ });
138
+ }
139
+ GpuDebugCounters.cacheSize = this._cache.size;
140
+ return frame;
141
+ }
142
+ _cacheKeysSnapshot() {
143
+ const keys = [];
144
+ const cacheWithKeys = this._cache;
145
+ const frames = cacheWithKeys._frames;
146
+ if (frames) {
147
+ for (const k of frames.keys())
148
+ keys.push(k);
149
+ }
150
+ return keys.sort((a, b) => a - b);
151
+ }
152
+ setPlayhead(sourceFrame, opts) {
153
+ if (this._state === 'disposed')
154
+ return;
155
+ this._cache.setPivot(sourceFrame);
156
+ this._latestPlayhead = sourceFrame;
157
+ if (this._resetInProgress) {
158
+ _sfpTrace('setPlayhead while reset in-progress', {
159
+ sourceFrame,
160
+ latestPlayhead: this._latestPlayhead,
161
+ });
162
+ return;
163
+ }
164
+ if (sourceFrame > this._highestDecodedFrame) {
165
+ this._ticksSinceDecodeAdvance++;
166
+ }
167
+ else {
168
+ this._ticksSinceDecodeAdvance = 0;
169
+ }
170
+ const lookahead = opts?.lookaheadFrames ?? this._lookaheadFrames;
171
+ const watchdogDisabled = typeof globalThis !== 'undefined' &&
172
+ globalThis.__SFP_NO_WATCHDOG__ === true;
173
+ const stalled = !watchdogDisabled &&
174
+ this._lastPlayhead !== null &&
175
+ this._manager.state === 'Ready' &&
176
+ this._feedWatermark >= sourceFrame &&
177
+ this._ticksSinceDecodeAdvance > STALL_TICKS_BEFORE_RESET;
178
+ const goingBackward = this._lastPlayhead !== null && sourceFrame < this._lastPlayhead;
179
+ const backwardMiss = goingBackward && !this._cache.has(sourceFrame);
180
+ const isDiscontinuity = this._lastPlayhead === null ||
181
+ Math.abs(sourceFrame - this._lastPlayhead) > lookahead ||
182
+ stalled ||
183
+ backwardMiss;
184
+ if (isDiscontinuity || stalled || sourceFrame !== this._lastLoggedPlayhead) {
185
+ _sfpTrace('setPlayhead', {
186
+ sourceFrame,
187
+ lastPlayhead: this._lastPlayhead,
188
+ watermark: this._feedWatermark,
189
+ highestDecoded: this._highestDecodedFrame,
190
+ managerState: this._manager.state,
191
+ cacheSize: this._cache.size,
192
+ stalled,
193
+ backwardMiss,
194
+ isDiscontinuity,
195
+ });
196
+ this._lastLoggedPlayhead = sourceFrame;
197
+ }
198
+ if (isDiscontinuity) {
199
+ this._resetInProgress = true;
200
+ void this._handleDiscontinuity(sourceFrame, lookahead);
201
+ return;
202
+ }
203
+ this._lastPlayhead = sourceFrame;
204
+ this._feedWindow(sourceFrame, lookahead);
205
+ }
206
+ markIdle() {
207
+ if (this._state === 'disposed')
208
+ return;
209
+ this._state = 'idle';
210
+ this._clearIdleTimer();
211
+ this._idleTimer = setTimeout(() => {
212
+ this._idleCallback?.();
213
+ }, DEFAULT_IDLE_TIMEOUT_MS);
214
+ this._manager.markIdle();
215
+ }
216
+ markActive() {
217
+ if (this._state === 'disposed')
218
+ return;
219
+ this._clearIdleTimer();
220
+ this._state = 'active';
221
+ this._manager.markActive();
222
+ }
223
+ dispose() {
224
+ if (this._state === 'disposed')
225
+ return;
226
+ this._state = 'disposed';
227
+ this._clearIdleTimer();
228
+ this._manager.dispose();
229
+ this._cache.dispose();
230
+ GpuDebugCounters.cacheSize = 0;
231
+ }
232
+ get state() {
233
+ return this._state;
234
+ }
235
+ get decoderState() {
236
+ return this._manager.state;
237
+ }
238
+ get cacheSize() {
239
+ return this._cache.size;
240
+ }
241
+ get openError() {
242
+ return this._openError;
243
+ }
244
+ get openPromise() {
245
+ return this._openPromise;
246
+ }
247
+ setIdleCallback(cb) {
248
+ this._idleCallback = cb;
249
+ }
250
+ async _handleDiscontinuity(sourceFrame, lookahead) {
251
+ if (this._openPromise) {
252
+ await this._openPromise;
253
+ this._openPromise = null;
254
+ }
255
+ if (this._state === 'disposed') {
256
+ this._resetInProgress = false;
257
+ return;
258
+ }
259
+ if (this._manager.state !== 'Ready') {
260
+ this._resetInProgress = false;
261
+ return;
262
+ }
263
+ this._feedWatermark = -1;
264
+ let seekAnchorFrame = sourceFrame;
265
+ try {
266
+ const toKeyframeUs = Math.round(sourceFrame * this._usPerFrame);
267
+ await this._manager.reset(toKeyframeUs);
268
+ this._lastPlayhead = this._latestPlayhead ?? sourceFrame;
269
+ this._highestDecodedFrame = -1;
270
+ this._ticksSinceDecodeAdvance = 0;
271
+ seekAnchorFrame = sourceFrame;
272
+ }
273
+ catch {
274
+ }
275
+ finally {
276
+ this._resetInProgress = false;
277
+ if (this._latestPlayhead !== null) {
278
+ const targetPlayhead = this._latestPlayhead;
279
+ const totalLookahead = Math.max(targetPlayhead - seekAnchorFrame, 0) + lookahead;
280
+ _sfpTrace('_handleDiscontinuity complete → _feedWindow', {
281
+ seekAnchorFrame,
282
+ targetPlayhead,
283
+ totalLookahead,
284
+ watermark: this._feedWatermark,
285
+ });
286
+ this._feedWindow(seekAnchorFrame, totalLookahead);
287
+ }
288
+ }
289
+ }
290
+ _feedWindow(N, lookahead) {
291
+ if (this._state === 'disposed')
292
+ return;
293
+ if (this._manager.state !== 'Ready')
294
+ return;
295
+ const highWater = N + lookahead;
296
+ const lowWater = N + Math.floor(lookahead / 2);
297
+ if (this._feedWatermark >= lowWater)
298
+ return;
299
+ const feedStart = Math.max(this._feedWatermark + 1, N);
300
+ if (feedStart > highWater)
301
+ return;
302
+ const startUs = Math.round(feedStart * this._usPerFrame);
303
+ const endUs = Math.round((highWater + 1) * this._usPerFrame);
304
+ _sfpTrace('_feedWindow → manager.feed (burst)', {
305
+ N,
306
+ feedStart,
307
+ lowWater,
308
+ highWater,
309
+ burstFrames: highWater - feedStart + 1,
310
+ startUs,
311
+ endUs,
312
+ previousWatermark: this._feedWatermark,
313
+ });
314
+ this._manager.feed([startUs, endUs]);
315
+ this._feedWatermark = highWater;
316
+ }
317
+ async _copyAndCache(frame, sourceFrameIdx, timestampUs) {
318
+ let bitmap = null;
319
+ try {
320
+ bitmap = await this._convert(frame);
321
+ }
322
+ catch (err) {
323
+ _sfpTrace('onFrame convert FAILED', {
324
+ sourceFrameIdx,
325
+ error: err instanceof Error ? err.message : String(err),
326
+ });
327
+ }
328
+ finally {
329
+ frame.close();
330
+ }
331
+ if (bitmap === null)
332
+ return;
333
+ if (this._state === 'disposed') {
334
+ bitmap.close();
335
+ return;
336
+ }
337
+ this._cache.put(sourceFrameIdx, bitmap);
338
+ if (sourceFrameIdx > this._highestDecodedFrame) {
339
+ this._highestDecodedFrame = sourceFrameIdx;
340
+ this._ticksSinceDecodeAdvance = 0;
341
+ }
342
+ GpuDebugCounters.cacheSize = this._cache.size;
343
+ _sfpTrace('onFrame → cache.put', {
344
+ sourceFrameIdx,
345
+ timestampUs,
346
+ cacheSize: this._cache.size,
347
+ lastPlayhead: this._lastPlayhead,
348
+ });
349
+ }
350
+ _clearIdleTimer() {
351
+ if (this._idleTimer !== null) {
352
+ clearTimeout(this._idleTimer);
353
+ this._idleTimer = null;
354
+ }
355
+ }
356
+ }
@@ -0,0 +1,59 @@
1
+ import { type DemuxerFactory } from './demuxer/MediabunnyDemuxer';
2
+ export type DecoderState = 'Idle' | 'Opening' | 'Ready' | 'Resetting' | 'Draining' | 'Disposed' | 'Errored';
3
+ export interface VideoDecoderLike {
4
+ state: string;
5
+ configure(config: VideoDecoderConfig): void;
6
+ decode(chunk: EncodedVideoChunk): void;
7
+ flush(): Promise<void>;
8
+ close(): void;
9
+ reset(): void;
10
+ }
11
+ export type VideoDecoderFactory = (output: (frame: VideoFrame) => void, error: (e: DOMException) => void) => VideoDecoderLike;
12
+ export interface VideoDecoderManagerOptions {
13
+ demuxerFactory?: DemuxerFactory;
14
+ decoderFactory?: VideoDecoderFactory;
15
+ idleTimeoutMs?: number;
16
+ fps?: number;
17
+ onStateChange?: (state: DecoderState) => void;
18
+ onDroppedFrame?: (sourceFrameIdx: number) => void;
19
+ onError?: (error: Error) => void;
20
+ }
21
+ export declare class VideoDecoderManager {
22
+ onFrame: ((frame: VideoFrame, sourceFrameIdx: number) => void) | null;
23
+ private readonly _demuxerFactory;
24
+ private readonly _decoderFactory;
25
+ private readonly _idleTimeoutMs;
26
+ private readonly _fps;
27
+ private readonly _onStateChange;
28
+ private readonly _onDroppedFrame;
29
+ private readonly _onError;
30
+ private _state;
31
+ private _src;
32
+ private _demuxer;
33
+ private _decoder;
34
+ private _idleTimer;
35
+ private _idleCallback;
36
+ private _feedGeneration;
37
+ private _feedActive;
38
+ private _feedPendingRange;
39
+ constructor(options?: VideoDecoderManagerOptions);
40
+ get fps(): number;
41
+ get state(): DecoderState;
42
+ get src(): string | null;
43
+ setIdleCallback(cb: (() => void) | null): void;
44
+ open(src: string): Promise<void>;
45
+ reopen(src: string): Promise<void>;
46
+ feed(timeRangeUs: [number, number]): void;
47
+ reset(toKeyframeUs: number): Promise<void>;
48
+ debugFlush(): Promise<void>;
49
+ drain(): Promise<void>;
50
+ markIdle(): void;
51
+ markActive(): void;
52
+ dispose(): void;
53
+ private _feedAsync;
54
+ private _assertTransition;
55
+ private _transition;
56
+ private _handleError;
57
+ private _cleanupResources;
58
+ private _clearIdleTimer;
59
+ }