supervision 0.1.7 → 0.2.0-next.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.
- package/dist/detections/chunked-detection-frame-source.d.ts.map +1 -1
- package/dist/index.d.ts +11 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8856 -4559
- package/dist/index.js.map +1 -1
- package/dist/mask-preparation.worker.js +310 -164
- package/dist/mask-preparation.worker.js.map +1 -1
- package/dist/media/display-pixel-ratio.d.ts +15 -0
- package/dist/media/display-pixel-ratio.d.ts.map +1 -0
- package/dist/media/engine-import-failure.d.ts +16 -0
- package/dist/media/engine-import-failure.d.ts.map +1 -0
- package/dist/media/media-condition-probe.d.ts +51 -0
- package/dist/media/media-condition-probe.d.ts.map +1 -0
- package/dist/media/media-conditions.d.ts +28 -0
- package/dist/media/media-conditions.d.ts.map +1 -0
- package/dist/media/media-errors.d.ts +6 -0
- package/dist/media/media-errors.d.ts.map +1 -1
- package/dist/media/media-normalization.d.ts.map +1 -1
- package/dist/media/media-probe.d.ts.map +1 -1
- package/dist/media/media-source.d.ts +17 -0
- package/dist/media/media-source.d.ts.map +1 -1
- package/dist/media/mediabunny-media-source.d.ts.map +1 -1
- package/dist/media/video-engine-media-source.d.ts +44 -0
- package/dist/media/video-engine-media-source.d.ts.map +1 -0
- package/dist/render-preparation/mask-frame-artifact.d.ts +46 -12
- package/dist/render-preparation/mask-frame-artifact.d.ts.map +1 -1
- package/dist/render-preparation/mask-frame-compositor.d.ts +5 -5
- package/dist/render-preparation/mask-frame-compositor.d.ts.map +1 -1
- package/dist/render-preparation/mask-frame-preparer.d.ts.map +1 -1
- package/dist/render-preparation/mask-preparation-worker-count.d.ts +4 -4
- package/dist/render-preparation/mask-preparation-worker-protocol.d.ts +12 -3
- package/dist/render-preparation/mask-preparation-worker-protocol.d.ts.map +1 -1
- package/dist/render-preparation/prepared-render-window.d.ts +23 -0
- package/dist/render-preparation/prepared-render-window.d.ts.map +1 -1
- package/dist/render-preparation/prepared-window-timeline.d.ts +2 -6
- package/dist/render-preparation/prepared-window-timeline.d.ts.map +1 -1
- package/dist/renderers/mask-palette.d.ts +14 -0
- package/dist/renderers/mask-palette.d.ts.map +1 -0
- package/dist/renderers/mask-vertex.d.ts +14 -0
- package/dist/renderers/mask-vertex.d.ts.map +1 -0
- package/dist/renderers/media-renderer-core.d.ts.map +1 -1
- package/dist/renderers/media-renderer-scene.d.ts +37 -0
- package/dist/renderers/media-renderer-scene.d.ts.map +1 -1
- package/dist/renderers/media-renderer-state.d.ts +11 -1
- package/dist/renderers/media-renderer-state.d.ts.map +1 -1
- package/dist/renderers/media-renderer-transport.d.ts +59 -0
- package/dist/renderers/media-renderer-transport.d.ts.map +1 -0
- package/dist/renderers/pixi-box-layer.d.ts +5 -0
- package/dist/renderers/pixi-box-layer.d.ts.map +1 -1
- package/dist/renderers/pixi-focus-layer.d.ts +18 -2
- package/dist/renderers/pixi-focus-layer.d.ts.map +1 -1
- package/dist/renderers/pixi-frame-present.d.ts +77 -0
- package/dist/renderers/pixi-frame-present.d.ts.map +1 -0
- package/dist/renderers/pixi-id-mask-shader.d.ts +12 -2
- package/dist/renderers/pixi-id-mask-shader.d.ts.map +1 -1
- package/dist/renderers/pixi-interaction-layer.d.ts.map +1 -1
- package/dist/renderers/pixi-interaction-presentation-layer.d.ts +13 -2
- package/dist/renderers/pixi-interaction-presentation-layer.d.ts.map +1 -1
- package/dist/renderers/pixi-mask-halo.d.ts +24 -0
- package/dist/renderers/pixi-mask-halo.d.ts.map +1 -1
- package/dist/renderers/pixi-mask-layer.d.ts +71 -8
- package/dist/renderers/pixi-mask-layer.d.ts.map +1 -1
- package/dist/renderers/pixi-media-scene.d.ts +67 -0
- package/dist/renderers/pixi-media-scene.d.ts.map +1 -1
- package/dist/renderers/pixi-polygon-layer.d.ts +7 -2
- package/dist/renderers/pixi-polygon-layer.d.ts.map +1 -1
- package/dist/renderers/pixi-region-coverage-mask.d.ts +91 -0
- package/dist/renderers/pixi-region-coverage-mask.d.ts.map +1 -0
- package/dist/renderers/pixi-region-effect.d.ts +42 -0
- package/dist/renderers/pixi-region-effect.d.ts.map +1 -0
- package/dist/renderers/pixi-region-layer.d.ts +68 -2
- package/dist/renderers/pixi-region-layer.d.ts.map +1 -1
- package/dist/renderers/pixi-vector-layer.d.ts.map +1 -1
- package/dist/renderers/prepared-annotation-window.d.ts +47 -0
- package/dist/renderers/prepared-annotation-window.d.ts.map +1 -0
- package/dist/renderers/presented-frame-channel.d.ts +107 -0
- package/dist/renderers/presented-frame-channel.d.ts.map +1 -0
- package/dist/renderers/scene-render-scheduler.d.ts +20 -0
- package/dist/renderers/scene-render-scheduler.d.ts.map +1 -0
- package/dist/sessions/media-session-defaults.d.ts +10 -6
- package/dist/sessions/media-session-defaults.d.ts.map +1 -1
- package/dist/sessions/media-session-media.d.ts.map +1 -1
- package/dist/sessions/media-session-state.d.ts.map +1 -1
- package/dist/sessions/media-session.d.ts.map +1 -1
- package/dist/tracking.worker.js +58 -3
- package/dist/tracking.worker.js.map +1 -1
- package/dist/types/media-conditions.d.ts +149 -0
- package/dist/types/media-conditions.d.ts.map +1 -0
- package/dist/types/media-normalization.d.ts +34 -0
- package/dist/types/media-normalization.d.ts.map +1 -1
- package/dist/types/media-renderer.d.ts +31 -1
- package/dist/types/media-renderer.d.ts.map +1 -1
- package/dist/types/media-session.d.ts +89 -8
- package/dist/types/media-session.d.ts.map +1 -1
- package/dist/types/render-preparation.d.ts +101 -4
- package/dist/types/render-preparation.d.ts.map +1 -1
- package/dist/web-video-engine/analysis-session.d.ts +76 -0
- package/dist/web-video-engine/analysis-session.d.ts.map +1 -0
- package/dist/web-video-engine/analysis.d.ts +7 -0
- package/dist/web-video-engine/analysis.d.ts.map +1 -0
- package/dist/web-video-engine/analysis.js +1678 -0
- package/dist/web-video-engine/analysis.js.map +1 -0
- package/dist/web-video-engine/cache-budget.d.ts +19 -0
- package/dist/web-video-engine/cache-budget.d.ts.map +1 -0
- package/dist/web-video-engine/canvas-sink-scrub-cursor.d.ts +90 -0
- package/dist/web-video-engine/canvas-sink-scrub-cursor.d.ts.map +1 -0
- package/dist/web-video-engine/clock.d.ts +83 -0
- package/dist/web-video-engine/clock.d.ts.map +1 -0
- package/dist/web-video-engine/constants.d.ts +253 -0
- package/dist/web-video-engine/constants.d.ts.map +1 -0
- package/dist/web-video-engine/create-scrub-cursor.d.ts +62 -0
- package/dist/web-video-engine/create-scrub-cursor.d.ts.map +1 -0
- package/dist/web-video-engine/decode-resolution.d.ts +115 -0
- package/dist/web-video-engine/decode-resolution.d.ts.map +1 -0
- package/dist/web-video-engine/decode-scheduler.d.ts +356 -0
- package/dist/web-video-engine/decode-scheduler.d.ts.map +1 -0
- package/dist/web-video-engine/decode-session.d.ts +276 -0
- package/dist/web-video-engine/decode-session.d.ts.map +1 -0
- package/dist/web-video-engine/decode-source.d.ts +250 -0
- package/dist/web-video-engine/decode-source.d.ts.map +1 -0
- package/dist/web-video-engine/diagnostics-store.d.ts +18 -0
- package/dist/web-video-engine/diagnostics-store.d.ts.map +1 -0
- package/dist/web-video-engine/diagnostics.d.ts +316 -0
- package/dist/web-video-engine/diagnostics.d.ts.map +1 -0
- package/dist/web-video-engine/embedded-engine-worker.d.ts +2 -0
- package/dist/web-video-engine/embedded-engine-worker.d.ts.map +1 -0
- package/dist/web-video-engine/engine-core.d.ts +258 -0
- package/dist/web-video-engine/engine-core.d.ts.map +1 -0
- package/dist/web-video-engine/engine.d.ts +26 -0
- package/dist/web-video-engine/engine.d.ts.map +1 -0
- package/dist/web-video-engine/engine.js +873 -0
- package/dist/web-video-engine/engine.js.map +1 -0
- package/dist/web-video-engine/engine.worker.d.ts +2 -0
- package/dist/web-video-engine/engine.worker.d.ts.map +1 -0
- package/dist/web-video-engine/engine.worker.js +31320 -0
- package/dist/web-video-engine/engine.worker.js.map +1 -0
- package/dist/web-video-engine/frame-cache.d.ts +129 -0
- package/dist/web-video-engine/frame-cache.d.ts.map +1 -0
- package/dist/web-video-engine/frame-extractor.d.ts +28 -0
- package/dist/web-video-engine/frame-extractor.d.ts.map +1 -0
- package/dist/web-video-engine/frame-timeline-GINI8Gum.js +560 -0
- package/dist/web-video-engine/frame-timeline-GINI8Gum.js.map +1 -0
- package/dist/web-video-engine/frame-timeline.d.ts +71 -0
- package/dist/web-video-engine/frame-timeline.d.ts.map +1 -0
- package/dist/web-video-engine/frame-walker.d.ts +74 -0
- package/dist/web-video-engine/frame-walker.d.ts.map +1 -0
- package/dist/web-video-engine/index.d.ts +3 -0
- package/dist/web-video-engine/index.d.ts.map +1 -0
- package/dist/web-video-engine/index.js +3 -0
- package/dist/web-video-engine/index.js.map +1 -0
- package/dist/web-video-engine/key-packet.d.ts +65 -0
- package/dist/web-video-engine/key-packet.d.ts.map +1 -0
- package/dist/web-video-engine/keyframe-index.d.ts +91 -0
- package/dist/web-video-engine/keyframe-index.d.ts.map +1 -0
- package/dist/web-video-engine/mirror-store.d.ts +56 -0
- package/dist/web-video-engine/mirror-store.d.ts.map +1 -0
- package/dist/web-video-engine/renderer.d.ts +94 -0
- package/dist/web-video-engine/renderer.d.ts.map +1 -0
- package/dist/web-video-engine/rotation.d.ts +35 -0
- package/dist/web-video-engine/rotation.d.ts.map +1 -0
- package/dist/web-video-engine/scrub-controller.d.ts +376 -0
- package/dist/web-video-engine/scrub-controller.d.ts.map +1 -0
- package/dist/web-video-engine/scrub-cursor.d.ts +342 -0
- package/dist/web-video-engine/scrub-cursor.d.ts.map +1 -0
- package/dist/web-video-engine/scrub-trajectory.d.ts +30 -0
- package/dist/web-video-engine/scrub-trajectory.d.ts.map +1 -0
- package/dist/web-video-engine/source-residency.d.ts +57 -0
- package/dist/web-video-engine/source-residency.d.ts.map +1 -0
- package/dist/web-video-engine/trace-recorder.d.ts +164 -0
- package/dist/web-video-engine/trace-recorder.d.ts.map +1 -0
- package/dist/web-video-engine/types.d.ts +204 -0
- package/dist/web-video-engine/types.d.ts.map +1 -0
- package/dist/web-video-engine/video-engine.d.ts +426 -0
- package/dist/web-video-engine/video-engine.d.ts.map +1 -0
- package/dist/web-video-engine/webgpu-renderer.d.ts +62 -0
- package/dist/web-video-engine/webgpu-renderer.d.ts.map +1 -0
- package/dist/web-video-engine/worker-bridge.d.ts +12 -0
- package/dist/web-video-engine/worker-bridge.d.ts.map +1 -0
- package/dist/web-video-engine/worker-dispatch.d.ts +17 -0
- package/dist/web-video-engine/worker-dispatch.d.ts.map +1 -0
- package/dist/web-video-engine/worker-protocol.d.ts +267 -0
- package/dist/web-video-engine/worker-protocol.d.ts.map +1 -0
- package/node_modules/supervision-js-core/dist/detections/buffered-detection-timeline.d.ts.map +1 -1
- package/node_modules/supervision-js-core/dist/detections/composite-detection-frame-source.d.ts.map +1 -1
- package/node_modules/supervision-js-core/dist/index.d.ts +4 -3
- package/node_modules/supervision-js-core/dist/index.d.ts.map +1 -1
- package/node_modules/supervision-js-core/dist/index.js +1075 -266
- package/node_modules/supervision-js-core/dist/index.js.map +1 -1
- package/node_modules/supervision-js-core/dist/styles/default-annotation-presentation.d.ts.map +1 -1
- package/node_modules/supervision-js-core/dist/styles/interaction-style.d.ts +4 -36
- package/node_modules/supervision-js-core/dist/styles/interaction-style.d.ts.map +1 -1
- package/node_modules/supervision-js-core/dist/styles/polyline-style.d.ts +5 -0
- package/node_modules/supervision-js-core/dist/styles/polyline-style.d.ts.map +1 -1
- package/node_modules/supervision-js-core/dist/types/annotation-renderer.d.ts +92 -7
- package/node_modules/supervision-js-core/dist/types/annotation-renderer.d.ts.map +1 -1
- package/node_modules/supervision-js-core/dist/types/detection-timeline.d.ts +179 -17
- package/node_modules/supervision-js-core/dist/types/detection-timeline.d.ts.map +1 -1
- package/node_modules/supervision-js-core/dist/types/media-rendering.d.ts +78 -2
- package/node_modules/supervision-js-core/dist/types/media-rendering.d.ts.map +1 -1
- package/node_modules/supervision-js-core/dist/types/polyline-style.d.ts +2 -0
- package/node_modules/supervision-js-core/dist/types/polyline-style.d.ts.map +1 -1
- package/node_modules/supervision-js-core/dist/types/session-lifecycle.d.ts +16 -0
- package/node_modules/supervision-js-core/dist/types/session-lifecycle.d.ts.map +1 -1
- package/node_modules/supervision-js-core/dist/utils/detection-conversions.d.ts.map +1 -1
- package/node_modules/supervision-js-core/dist/utils/detection-frames.d.ts +5 -0
- package/node_modules/supervision-js-core/dist/utils/detection-frames.d.ts.map +1 -1
- package/node_modules/supervision-js-core/dist/utils/detection-masks.d.ts +9 -0
- package/node_modules/supervision-js-core/dist/utils/detection-masks.d.ts.map +1 -1
- package/node_modules/supervision-js-core/dist/utils/detection-ranges.d.ts +18 -0
- package/node_modules/supervision-js-core/dist/utils/detection-ranges.d.ts.map +1 -0
- package/node_modules/supervision-js-core/dist/utils/id-mask-frame.d.ts +15 -2
- package/node_modules/supervision-js-core/dist/utils/id-mask-frame.d.ts.map +1 -1
- package/node_modules/supervision-js-core/dist/utils/wait-bound.d.ts +7 -0
- package/node_modules/supervision-js-core/dist/utils/wait-bound.d.ts.map +1 -0
- package/package.json +22 -1
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
import type { MediaClock } from "./clock";
|
|
2
|
+
import type { RendererName } from "./diagnostics";
|
|
3
|
+
import { type FrameQuality, type ScrubCursor, type ScrubFrame } from "./scrub-cursor";
|
|
4
|
+
import type { PresentationMode } from "./types";
|
|
5
|
+
export declare function setDiagnosticsEnabled(enabled: boolean): void;
|
|
6
|
+
/** Per-rAF realtime needles, collected only while diagnostics are enabled. ticks
|
|
7
|
+
* is every loop turn; paints is every frame drawn; lateFrames is a playing frame
|
|
8
|
+
* more than one interval behind the clock; stalls is a playing tick with no frame
|
|
9
|
+
* to paint; catchUpMs is how far the clock has run past the last painted frame.
|
|
10
|
+
* playQueueDepth is the decode-ahead buffer's current length: a live read, not a
|
|
11
|
+
* per-tick accumulator, so 0 while playing means the pipeline ran dry. */
|
|
12
|
+
export interface RealtimeStats {
|
|
13
|
+
readonly ticks: number;
|
|
14
|
+
readonly paints: number;
|
|
15
|
+
readonly lateFrames: number;
|
|
16
|
+
readonly stalls: number;
|
|
17
|
+
readonly catchUpMs: number;
|
|
18
|
+
readonly playQueueDepth: number;
|
|
19
|
+
readonly endedFired: boolean;
|
|
20
|
+
/** Decoded frames thrown away before reaching the canvas: ones that arrived
|
|
21
|
+
* for a position playback had left, buffered ones overtaken by the clock
|
|
22
|
+
* moving backwards, and the ones the present cadence declines once the rate
|
|
23
|
+
* asks for more frames a second than it. All three cost a full decode. The
|
|
24
|
+
* first two are decode bandwidth spent on nothing; the third is the cadence
|
|
25
|
+
* doing its job, and at a high rate it dominates the count. */
|
|
26
|
+
readonly droppedFrames: number;
|
|
27
|
+
/** Same fact accumulated over the source's lifetime for the pipeline
|
|
28
|
+
* ledger, so it can sit beside the other monotonic counters. */
|
|
29
|
+
readonly droppedFramesTotal: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Render loop. One rAF tick. Mode-aware:
|
|
33
|
+
*
|
|
34
|
+
* - Playing: the catch-up loop from the mediabunny media-player example.
|
|
35
|
+
* On each tick read clock.now(); if the stashed nextFrame's timestamp
|
|
36
|
+
* has arrived, paint it, then pull forward from the cursor in a
|
|
37
|
+
* while-loop. Late frames paint immediately; the first future-timestamped
|
|
38
|
+
* frame is stashed for the next tick. This matches Vanilagy's reference
|
|
39
|
+
* pattern and prevents visible skips when the decoder lags behind the clock.
|
|
40
|
+
*
|
|
41
|
+
* - Paused: the cursor's most recent emission is whatever the latest
|
|
42
|
+
* seek landed on. Tick paints it once, nulls nextFrame, and never
|
|
43
|
+
* touches the iterator. Subsequent user input that calls seekTo
|
|
44
|
+
* emits a fresh frame, the listener stashes it, and the next tick
|
|
45
|
+
* paints it.
|
|
46
|
+
*
|
|
47
|
+
* No backup setInterval. rAF is enough: tab backgrounding will pause the
|
|
48
|
+
* loop, but pause is the right behavior because nothing should advance
|
|
49
|
+
* media time while the surface is not visible.
|
|
50
|
+
*
|
|
51
|
+
* Runs worker-side. It renders frames through a Renderer (the 2D canvas path
|
|
52
|
+
* today, swappable for WebGPU behind the same seam); the cursor owns the frame
|
|
53
|
+
* cache and fills it as it decodes, so this loop only reads it through
|
|
54
|
+
* peekCached. The only way out is the onPaint callback, which EngineCore turns
|
|
55
|
+
* into serializable state emits. No DOM, no React, no main-thread reference
|
|
56
|
+
* ever reaches this loop.
|
|
57
|
+
*/
|
|
58
|
+
export interface ScrubControllerDeps {
|
|
59
|
+
cursor: ScrubCursor;
|
|
60
|
+
clock: MediaClock;
|
|
61
|
+
/** catchUpMs is supplied only while diagnostics are enabled and playing, so
|
|
62
|
+
* the engine can fold it onto the broadcast frame event; undefined otherwise.
|
|
63
|
+
* presented carries the pixels when the sink handed them out instead of
|
|
64
|
+
* painting them, and transfers ownership of that frame with the call. */
|
|
65
|
+
onPaint: (frame: ScrubFrame, catchUpMs?: number, presented?: VideoFrame | null) => void;
|
|
66
|
+
/** Fired when playback runs past the source duration so the engine can
|
|
67
|
+
* transition to Ended status. Without this the iterator yields done
|
|
68
|
+
* forever and the play UI stays stuck on Playing while the canvas freezes. */
|
|
69
|
+
onEnded: () => void;
|
|
70
|
+
/** Cache lookups whose resolved entry is closer than this to whatever
|
|
71
|
+
* the visible canvas already shows are rejected. Forces a fresh decode
|
|
72
|
+
* on small movements (frame-step gestures) so the user sees the actual
|
|
73
|
+
* next/prev frame, not the cached neighbor. */
|
|
74
|
+
cacheSkipNearMs: number;
|
|
75
|
+
/** Pin the 2D renderer; unset prefers WebGPU, falling back to 2D when unavailable. */
|
|
76
|
+
prefer2d?: boolean;
|
|
77
|
+
/** Defaults to "canvas". Under "frames" the loop binds no canvas and every
|
|
78
|
+
* paint yields its pixels to onPaint instead. */
|
|
79
|
+
presentation?: PresentationMode;
|
|
80
|
+
}
|
|
81
|
+
export declare class ScrubController {
|
|
82
|
+
private readonly deps;
|
|
83
|
+
private rafHandle;
|
|
84
|
+
/** Paused/seek path: the single most-recent landed frame. */
|
|
85
|
+
private nextFrame;
|
|
86
|
+
/** Playing path: a bounded decode-ahead buffer so a decode that overruns a
|
|
87
|
+
* frame interval does not starve the next tick. Drained one frame per tick,
|
|
88
|
+
* refilled toward the read-ahead depth. */
|
|
89
|
+
private playQueue;
|
|
90
|
+
private sink;
|
|
91
|
+
/** The canvas the latest bind targeted; guards the async renderer race. */
|
|
92
|
+
private boundCanvas;
|
|
93
|
+
private disposed;
|
|
94
|
+
private unsub;
|
|
95
|
+
/** Milliseconds-rounded timestamp of whatever the visible canvas
|
|
96
|
+
* currently shows. Updated on every paint (cursor emit OR cache hit).
|
|
97
|
+
* Drives the skip-near-current check in tryPaintFromCache. */
|
|
98
|
+
private lastPaintedMs;
|
|
99
|
+
/** Quality of what the canvas shows, so a repaint can be judged on sharpness
|
|
100
|
+
* as well as position. */
|
|
101
|
+
private lastPaintedQuality;
|
|
102
|
+
/** Set true when runTick detects clock past duration so we only emit
|
|
103
|
+
* the onEnded transition once per playback session. */
|
|
104
|
+
private endedFired;
|
|
105
|
+
private ticks;
|
|
106
|
+
private paints;
|
|
107
|
+
private lateFrames;
|
|
108
|
+
private stalls;
|
|
109
|
+
private catchUpMs;
|
|
110
|
+
private droppedFrames;
|
|
111
|
+
/** Lifetime companion to droppedFrames for the pipeline ledger: never reset
|
|
112
|
+
* by a play session and not gated on diagnostics, so the ledger is honest
|
|
113
|
+
* even about what happened before the HUD opened. */
|
|
114
|
+
private droppedFramesTotal;
|
|
115
|
+
/** False from every attach of the play walk until its first frame paints.
|
|
116
|
+
* The bootstrap pull is async, so the opening ticks find nextFrame null
|
|
117
|
+
* and would each book a stall the user never saw. */
|
|
118
|
+
private paintedSincePlay;
|
|
119
|
+
/** Whether a play session the user started is still running. A seek while
|
|
120
|
+
* playing re-attaches the walk through endPlay and beginPlay without ever
|
|
121
|
+
* stopping the transport, and a drag stops the transport for the length of
|
|
122
|
+
* the gesture and walks the playhead across the source under it. Neither is
|
|
123
|
+
* the user putting the picture down, and the per-session needles count the
|
|
124
|
+
* session the user is watching, not the walk. */
|
|
125
|
+
private playSessionLive;
|
|
126
|
+
/** Clock reading the transport stopped at, or null while it runs. A stopped
|
|
127
|
+
* clock moves only by being seeked, so a stopped tick reading anything else
|
|
128
|
+
* is a seek, which is why the comparison against it is exact. */
|
|
129
|
+
private stoppedAtS;
|
|
130
|
+
/** Media time the current play session was attached at, which is what makes
|
|
131
|
+
* a frame produced for a position the session has left recognisable. */
|
|
132
|
+
private playAnchorS;
|
|
133
|
+
/** Media time the previous playing tick read, so a tick can price its own
|
|
134
|
+
* span in source frames. Null until the session's second tick. */
|
|
135
|
+
private lastTickS;
|
|
136
|
+
/** Clock reading at the play walk's last delivery, or null when no walk is
|
|
137
|
+
* attached. Set at the attach too, so the walk's opening frame is priced
|
|
138
|
+
* against the wait for it. */
|
|
139
|
+
private lastDeliveryS;
|
|
140
|
+
/** Source frames this tick may pull past the one it paints, refreshed per
|
|
141
|
+
* tick from the span the clock covered. Sourced from ticks so a loop that
|
|
142
|
+
* stops (a hidden tab parks rAF) takes the pull chain down with it. */
|
|
143
|
+
private catchUpBudget;
|
|
144
|
+
/** Clock reading at the last paint this play session put on screen, which is
|
|
145
|
+
* what the wall-time gap between presents is measured from. Null until the
|
|
146
|
+
* session's first paint, so an opening frame is never held for cadence. */
|
|
147
|
+
private lastPresentTickS;
|
|
148
|
+
/** The share of the rate's demand the pump allows itself to present. Held as
|
|
149
|
+
* a share rather than a frames-a-second figure so it survives a rate change
|
|
150
|
+
* as the same statement about the machine: a pipeline that was keeping up
|
|
151
|
+
* at 1x opens 4x at everything 4x asks for, with no ramp to climb. */
|
|
152
|
+
private presentShare;
|
|
153
|
+
/** Frames the running play walk has delivered into the queue, and the two
|
|
154
|
+
* readings the cadence loop last took: the clock, and that same count.
|
|
155
|
+
* Between them a tick knows what it asked the pipeline for and what it got. */
|
|
156
|
+
private walkDelivered;
|
|
157
|
+
private cadenceTickS;
|
|
158
|
+
private cadenceDeliveredAt;
|
|
159
|
+
/** Frames the pipeline owes the playhead since the cadence last moved: what
|
|
160
|
+
* the clock has asked for, less what the walk delivered. Zeroed on every
|
|
161
|
+
* move, so it holds the evidence for the next one rather than the ground
|
|
162
|
+
* lost over the session. */
|
|
163
|
+
private cadenceBacklog;
|
|
164
|
+
/** Wall seconds the walk has held a frame the clock has not run past, without
|
|
165
|
+
* a break, which is the only evidence a pipeline can offer that it has room
|
|
166
|
+
* to spare. */
|
|
167
|
+
private cadenceCushionS;
|
|
168
|
+
constructor(deps: ScrubControllerDeps);
|
|
169
|
+
/**
|
|
170
|
+
* Routes an arriving frame. While playing it appends to the decode-ahead
|
|
171
|
+
* queue and chains another pull until the read-ahead depth is reached (the
|
|
172
|
+
* cursor's one-in-flight latch makes the extra pulls free no-ops). While
|
|
173
|
+
* paused it replaces the single stashed frame, closing the superseded one
|
|
174
|
+
* when it is an unpainted sample so a fast drag does not leak VideoSamples.
|
|
175
|
+
*/
|
|
176
|
+
private stash;
|
|
177
|
+
/**
|
|
178
|
+
* Decoded frames to keep queued ahead of the playhead. The decode path
|
|
179
|
+
* decides it, not the shape of the frame: reading it off the frame treated
|
|
180
|
+
* every sample-carrying path as pool-bound, which the long-lived decode
|
|
181
|
+
* session is not, so the default path ran with a queue of one and no cushion
|
|
182
|
+
* at all. A cushion is the whole point, it is what stops a decode that
|
|
183
|
+
* overruns one frame interval from starving the next paint.
|
|
184
|
+
*/
|
|
185
|
+
private readAhead;
|
|
186
|
+
/**
|
|
187
|
+
* Whether a frame arriving while the clock runs belongs to the running play
|
|
188
|
+
* session. The controller receives every frame the cursor emits, not only
|
|
189
|
+
* the ones its own pulls asked for, so a seek still landing when playback
|
|
190
|
+
* resumes delivers a frame for a position the session has already left.
|
|
191
|
+
* Queued, that frame sits at the head never due, which blocks the paint and
|
|
192
|
+
* the refill alike, and playback resumes only once the clock has run all the
|
|
193
|
+
* way to it: exactly as long as the jump the user just made.
|
|
194
|
+
*/
|
|
195
|
+
private belongsToPlaySession;
|
|
196
|
+
/**
|
|
197
|
+
* Whether a queued frame is further ahead of the clock than playback can
|
|
198
|
+
* legitimately buffer. Play frames come from an iterator anchored at the
|
|
199
|
+
* playhead, so the buffer leads the clock by its own depth and no more. A
|
|
200
|
+
* frame past that either arrived for a position the session has left, or was
|
|
201
|
+
* overtaken when the clock moved backwards under the queue, which a step or
|
|
202
|
+
* a seek during playback both do.
|
|
203
|
+
*/
|
|
204
|
+
private beyondPlayHorizon;
|
|
205
|
+
/**
|
|
206
|
+
* Discards every queued frame the clock has already run past except the last
|
|
207
|
+
* one, which is the frame that belongs on screen now.
|
|
208
|
+
*
|
|
209
|
+
* A tick can only present one frame, so whenever more than one falls due in
|
|
210
|
+
* the same tick the surplus has nowhere to go. Serving them one a tick
|
|
211
|
+
* instead makes the picture drift further behind the playhead every tick,
|
|
212
|
+
* which is what a rate past display-refresh over source-fps produces on a
|
|
213
|
+
* pipeline that is otherwise keeping up perfectly. Skipping keeps the picture
|
|
214
|
+
* on the playhead and charges the difference to the dropped-frame ledger,
|
|
215
|
+
* where a consumer can see what the rate cost.
|
|
216
|
+
*/
|
|
217
|
+
private dropFramesTheClockHasPassed;
|
|
218
|
+
/**
|
|
219
|
+
* Source frames this tick may pull past the one it paints, measured as the
|
|
220
|
+
* span the clock covered. One of them covers that span, which is what a rate
|
|
221
|
+
* demanding more than a frame per tick needs and cannot get from a queue
|
|
222
|
+
* bounded by read-ahead depth; the rest work off a backlog, so a pipeline a
|
|
223
|
+
* slow stretch knocked behind can return to the playhead.
|
|
224
|
+
*/
|
|
225
|
+
private catchUpAllowance;
|
|
226
|
+
/**
|
|
227
|
+
* Presents a wall second the pump allows itself right now: the rate's demand
|
|
228
|
+
* cut to the share the machine has been paying for, and never under the
|
|
229
|
+
* source's own frame rate. Rate 1 asks for exactly the source rate, so its
|
|
230
|
+
* floor and its demand are the same figure and no share can come between
|
|
231
|
+
* them, which is what leaves 1x painting every frame of every source.
|
|
232
|
+
*/
|
|
233
|
+
private presentCadence;
|
|
234
|
+
/** Forgets what the cadence loop had gathered. The walk is about to be
|
|
235
|
+
* attached somewhere else, and a span across that move charges the pipeline
|
|
236
|
+
* for frames it was never asked to have ready. */
|
|
237
|
+
private resetCadenceTracking;
|
|
238
|
+
/**
|
|
239
|
+
* Prices this tick against the pipeline and moves the share one step once
|
|
240
|
+
* either reading has gathered the evidence a step takes.
|
|
241
|
+
*
|
|
242
|
+
* What takes the share down is a running bill, in frames, between what the
|
|
243
|
+
* clock passed and what the play walk delivered over the same span.
|
|
244
|
+
* Accumulating rather than thresholding each tick is what tells a shortfall
|
|
245
|
+
* from noise: counting whole frames against a fractional demand leaves every
|
|
246
|
+
* tick out by up to one either way and those cancel, while a machine that
|
|
247
|
+
* cannot sustain the rate falls short every tick and adds up. A machine that
|
|
248
|
+
* can sustain it has no way to run the bill up, since the queue only takes a
|
|
249
|
+
* frame as the clock passes one and catch-up pulls repay any span the walk
|
|
250
|
+
* came up short on, which bounds the bill by the depth being held.
|
|
251
|
+
*
|
|
252
|
+
* What puts the share back is the walk holding a frame the clock has not run
|
|
253
|
+
* past, unbroken for the wall time the source takes to produce that many.
|
|
254
|
+
* Nothing else would do, since a machine at equilibrium delivers exactly what
|
|
255
|
+
* the clock asks for however much headroom it has, so a surplus never appears
|
|
256
|
+
* in the bill to be read.
|
|
257
|
+
*
|
|
258
|
+
* Neither reading is the depth of the decode-ahead queue, which belongs to
|
|
259
|
+
* the decode path and not to the machine: on the zero-copy path, which
|
|
260
|
+
* buffers one frame, a single frame in hand is full depth and one tick from
|
|
261
|
+
* empty alike.
|
|
262
|
+
*
|
|
263
|
+
* Nothing either reading is made of knows what the panel refreshes at, so one
|
|
264
|
+
* machine lands on one cadence on any panel; a present the share declines
|
|
265
|
+
* hands its time back to decode, so the loop this closes is a negative one;
|
|
266
|
+
* and zeroing both on each step makes the next one gather its own evidence,
|
|
267
|
+
* which is what a share sitting at the machine's limit needs to stop it
|
|
268
|
+
* pulsing.
|
|
269
|
+
*/
|
|
270
|
+
private observePresentCadence;
|
|
271
|
+
/**
|
|
272
|
+
* Whether the frame that is due arrives too soon after the last painted one
|
|
273
|
+
* to earn the screen. Wall time, read as the media span over the clock's
|
|
274
|
+
* slope, so the same gap decides at every rate. The pump paints at most one
|
|
275
|
+
* frame per display tick, so it can only decline one on a panel whose ticks
|
|
276
|
+
* fall closer together than the interval it compares against.
|
|
277
|
+
*
|
|
278
|
+
* A cadence sitting at its ceiling never reaches the wall-time test, so a
|
|
279
|
+
* machine keeping up declines nothing at any rate, and the ceiling equals the
|
|
280
|
+
* demand at rate 1, which paints every frame of every source. A clock that
|
|
281
|
+
* moved backwards under the pump reads as a non-positive span and paints,
|
|
282
|
+
* which is what stops a step or a seek during playback from holding the
|
|
283
|
+
* picture for the length of the jump it made.
|
|
284
|
+
*/
|
|
285
|
+
private skipsForPresentCadence;
|
|
286
|
+
/**
|
|
287
|
+
* Re-anchors the playback walk when the clock ran further past the previous
|
|
288
|
+
* tick than a loop that was actually running could have let it, and reports
|
|
289
|
+
* whether it did.
|
|
290
|
+
*
|
|
291
|
+
* A hidden tab parks rAF while the clock keeps wall time, so the tick that
|
|
292
|
+
* resumes finds a backlog as deep as the whole absence. Walked, it costs one
|
|
293
|
+
* decode per frame nobody was there to see, and the picture replays the
|
|
294
|
+
* absence at decode rate on its way to the playhead: 30 seconds hidden
|
|
295
|
+
* measured 4961ms of 8x fast-forward. Anchoring at the playhead lands the
|
|
296
|
+
* frame that walk was travelling toward for one keyframe seek, flat in how
|
|
297
|
+
* far the clock went.
|
|
298
|
+
*
|
|
299
|
+
* Dividing the span by the clock's slope is what makes the reading wall time,
|
|
300
|
+
* so a high rate legitimately moving the clock several frames per tick is not
|
|
301
|
+
* read as a loop nobody was driving.
|
|
302
|
+
*/
|
|
303
|
+
private reanchorParkedWalk;
|
|
304
|
+
/**
|
|
305
|
+
* Puts the clock back onto the frame a starved walk has just delivered.
|
|
306
|
+
*
|
|
307
|
+
* A seek onto unbuffered ground leaves the render loop ticking with nothing
|
|
308
|
+
* to paint, so no tick gap ever opens and reanchorParkedWalk never sees it;
|
|
309
|
+
* what stopped is the walk. The clock runs through the whole wait, so the
|
|
310
|
+
* frame the viewer asked for arrives that far behind it, and a walk left to
|
|
311
|
+
* catch up spends the wait replaying it at decode speed: the position they
|
|
312
|
+
* asked to see, flashed past on the way to one they did not.
|
|
313
|
+
*/
|
|
314
|
+
private reanchorStarvedWalk;
|
|
315
|
+
/**
|
|
316
|
+
* Whether the newest decoded frame is already older than the clock, which
|
|
317
|
+
* makes the queue a backlog and the next pull catch-up. Read-ahead depth
|
|
318
|
+
* cannot bound catch-up as well: a path that holds one frame consumes one
|
|
319
|
+
* source frame per tick, which pins the picture to tick rate over source fps
|
|
320
|
+
* whatever rate was commanded.
|
|
321
|
+
*/
|
|
322
|
+
private trailsTheClock;
|
|
323
|
+
/** Drops every queued play frame, closing any that are unpainted samples. */
|
|
324
|
+
private clearPlayQueue;
|
|
325
|
+
bindCanvas(el: OffscreenCanvas | null): void;
|
|
326
|
+
/** The active render backend, for diagnostics; null until it resolves. */
|
|
327
|
+
rendererName(): RendererName | null;
|
|
328
|
+
private attachRenderer;
|
|
329
|
+
dispose(): void;
|
|
330
|
+
/** Drops the stashed frame, closing it if it is an unpainted sample. */
|
|
331
|
+
private clearStash;
|
|
332
|
+
/**
|
|
333
|
+
* Millisecond timestamp of whatever the visible canvas currently shows.
|
|
334
|
+
* Engine.step uses this as the base for "next frame after current" so
|
|
335
|
+
* step lands on the actual neighbor frame, not on a 1/fps arithmetic
|
|
336
|
+
* guess from store.timeMs (which holds user intent during scrub).
|
|
337
|
+
*/
|
|
338
|
+
getLastPaintedMs(): number | null;
|
|
339
|
+
getLastPaintedQuality(): FrameQuality;
|
|
340
|
+
/**
|
|
341
|
+
* Called by the engine on play(), and again by a seek that re-anchors a walk
|
|
342
|
+
* already running. Attaches the cursor's forward iterator at the current
|
|
343
|
+
* media time and kicks the bootstrap pull. Also clears the EOF latch so a
|
|
344
|
+
* play-restart from past-end can fire onEnded again the next time the clock
|
|
345
|
+
* crosses the duration.
|
|
346
|
+
*/
|
|
347
|
+
beginPlay(startS: number): void;
|
|
348
|
+
/** Called by the engine on pause(), and by a seek re-anchoring a running
|
|
349
|
+
* walk. Detaches the iterator and drops the read-ahead so paused ticks
|
|
350
|
+
* never paint a stale play frame. */
|
|
351
|
+
endPlay(): void;
|
|
352
|
+
/**
|
|
353
|
+
* Cache lookup helper used by the engine on scrub. Asks the cursor for a
|
|
354
|
+
* cached frame near the target and, if it is far enough from what the canvas
|
|
355
|
+
* already shows, paints it and returns true. Either way the engine still
|
|
356
|
+
* calls cursor.seekTo to land the full-res frame; the cursor's emit listener
|
|
357
|
+
* stashes it for the next tick.
|
|
358
|
+
*
|
|
359
|
+
* The skip-near-current check rejects hits whose timestamp falls within
|
|
360
|
+
* cacheSkipNearMs of the currently-displayed frame. This is the knob
|
|
361
|
+
* consumers tune to control single-frame-step UX: a higher value forces a
|
|
362
|
+
* fresh decode on tighter movements, a value of 0 always serves the cache.
|
|
363
|
+
*/
|
|
364
|
+
tryPaintFromCache(timestampMs: number): boolean;
|
|
365
|
+
private start;
|
|
366
|
+
private runTick;
|
|
367
|
+
private paint;
|
|
368
|
+
/** Frame interval in seconds; the source rate when known, else a 30fps
|
|
369
|
+
* fallback. Used to decide whether a playing frame painted late. */
|
|
370
|
+
private frameIntervalS;
|
|
371
|
+
/** Realtime needles for the diagnostics snapshot. Plain reads; the worker
|
|
372
|
+
* broadcaster calls this synchronously. */
|
|
373
|
+
getRealtimeStats(): RealtimeStats;
|
|
374
|
+
private stop;
|
|
375
|
+
}
|
|
376
|
+
//# sourceMappingURL=scrub-controller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scrub-controller.d.ts","sourceRoot":"","sources":["../src/scrub-controller.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAOlD,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,UAAU,EAChB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAWhD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAE5D;AAED;;;;;2EAK2E;AAC3E,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B;;;;;oEAKgE;IAChE,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B;qEACiE;IACjE,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;CACrC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,WAAW,CAAC;IACpB,KAAK,EAAE,UAAU,CAAC;IAClB;;;8EAG0E;IAC1E,OAAO,EAAE,CACP,KAAK,EAAE,UAAU,EACjB,SAAS,CAAC,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,UAAU,GAAG,IAAI,KAC1B,IAAI,CAAC;IACV;;mFAE+E;IAC/E,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB;;;oDAGgD;IAChD,eAAe,EAAE,MAAM,CAAC;IACxB,sFAAsF;IACtF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;sDACkD;IAClD,YAAY,CAAC,EAAE,gBAAgB,CAAC;CACjC;AAED,qBAAa,eAAe;IAyFd,OAAO,CAAC,QAAQ,CAAC,IAAI;IAxFjC,OAAO,CAAC,SAAS,CAAK;IACtB,6DAA6D;IAC7D,OAAO,CAAC,SAAS,CAA2B;IAC5C;;gDAE4C;IAC5C,OAAO,CAAC,SAAS,CAAoB;IACrC,OAAO,CAAC,IAAI,CAA0B;IACtC,2EAA2E;IAC3E,OAAO,CAAC,WAAW,CAAgC;IACnD,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,KAAK,CAA6B;IAC1C;;mEAE+D;IAC/D,OAAO,CAAC,aAAa,CAAuB;IAC5C;+BAC2B;IAC3B,OAAO,CAAC,kBAAkB,CAA2B;IACrD;4DACwD;IACxD,OAAO,CAAC,UAAU,CAAS;IAG3B,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,aAAa,CAAK;IAC1B;;0DAEsD;IACtD,OAAO,CAAC,kBAAkB,CAAK;IAC/B;;0DAEsD;IACtD,OAAO,CAAC,gBAAgB,CAAS;IACjC;;;;;sDAKkD;IAClD,OAAO,CAAC,eAAe,CAAS;IAChC;;sEAEkE;IAClE,OAAO,CAAC,UAAU,CAAuB;IACzC;6EACyE;IACzE,OAAO,CAAC,WAAW,CAAK;IACxB;uEACmE;IACnE,OAAO,CAAC,SAAS,CAAuB;IACxC;;mCAE+B;IAC/B,OAAO,CAAC,aAAa,CAAuB;IAC5C;;4EAEwE;IACxE,OAAO,CAAC,aAAa,CAAK;IAC1B;;gFAE4E;IAC5E,OAAO,CAAC,gBAAgB,CAAuB;IAC/C;;;2EAGuE;IACvE,OAAO,CAAC,YAAY,CAAK;IACzB;;oFAEgF;IAChF,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,kBAAkB,CAAK;IAC/B;;;iCAG6B;IAC7B,OAAO,CAAC,cAAc,CAAK;IAC3B;;oBAEgB;IAChB,OAAO,CAAC,eAAe,CAAK;gBAEC,IAAI,EAAE,mBAAmB;IAWtD;;;;;;OAMG;IACH,OAAO,CAAC,KAAK;IA6Bb;;;;;;;OAOG;IACH,OAAO,CAAC,SAAS;IAIjB;;;;;;;;OAQG;IACH,OAAO,CAAC,oBAAoB;IAQ5B;;;;;;;OAOG;IACH,OAAO,CAAC,iBAAiB;IAOzB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,2BAA2B;IAkBnC;;;;;;OAMG;IACH,OAAO,CAAC,gBAAgB;IAOxB;;;;;;OAMG;IACH,OAAO,CAAC,cAAc;IAKtB;;uDAEmD;IACnD,OAAO,CAAC,oBAAoB;IAQ5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+BG;IACH,OAAO,CAAC,qBAAqB;IAmC7B;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,sBAAsB;IAW9B;;;;;;;;;;;;;;;;OAgBG;IACH,OAAO,CAAC,kBAAkB;IAmB1B;;;;;;;;;OASG;IACH,OAAO,CAAC,mBAAmB;IAa3B;;;;;;OAMG;IACH,OAAO,CAAC,cAAc;IAOtB,6EAA6E;IAC7E,OAAO,CAAC,cAAc;IAOtB,UAAU,CAAC,EAAE,EAAE,eAAe,GAAG,IAAI,GAAG,IAAI;IA0B5C,0EAA0E;IAC1E,YAAY,IAAI,YAAY,GAAG,IAAI;YAIrB,cAAc;IAU5B,OAAO,IAAI,IAAI;IAWf,wEAAwE;IACxE,OAAO,CAAC,UAAU;IAMlB;;;;;OAKG;IACH,gBAAgB,IAAI,MAAM,GAAG,IAAI;IAIjC,qBAAqB,IAAI,YAAY;IAIrC;;;;;;OAMG;IACH,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAiC/B;;0CAEsC;IACtC,OAAO,IAAI,IAAI;IAcf;;;;;;;;;;;OAWG;IACH,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO;IAyC/C,OAAO,CAAC,KAAK;IAWb,OAAO,CAAC,OAAO;IAoFf,OAAO,CAAC,KAAK;IAgCb;yEACqE;IACrE,OAAO,CAAC,cAAc;IAKtB;gDAC4C;IAC5C,gBAAgB,IAAI,aAAa;IAcjC,OAAO,CAAC,IAAI;CAIb"}
|