supervision 0.1.7 → 0.2.0-next.1

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 (182) hide show
  1. package/dist/constants/media-renderer.d.ts +3 -0
  2. package/dist/constants/media-renderer.d.ts.map +1 -1
  3. package/dist/detections/chunked-detection-frame-source.d.ts.map +1 -1
  4. package/dist/index.d.ts +8 -4
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +9281 -5038
  7. package/dist/index.js.map +1 -1
  8. package/dist/mask-preparation.worker.js +409 -185
  9. package/dist/mask-preparation.worker.js.map +1 -1
  10. package/dist/media/display-pixel-ratio.d.ts +15 -0
  11. package/dist/media/display-pixel-ratio.d.ts.map +1 -0
  12. package/dist/media/engine-import-failure.d.ts +16 -0
  13. package/dist/media/engine-import-failure.d.ts.map +1 -0
  14. package/dist/media/media-errors.d.ts +6 -0
  15. package/dist/media/media-errors.d.ts.map +1 -1
  16. package/dist/media/media-normalization.d.ts.map +1 -1
  17. package/dist/media/media-probe.d.ts.map +1 -1
  18. package/dist/media/media-source-state.d.ts.map +1 -1
  19. package/dist/media/media-source.d.ts +17 -0
  20. package/dist/media/media-source.d.ts.map +1 -1
  21. package/dist/media/mediabunny-media-source.d.ts.map +1 -1
  22. package/dist/media/video-engine-media-source.d.ts +54 -0
  23. package/dist/media/video-engine-media-source.d.ts.map +1 -0
  24. package/dist/media/video-engine-media-source.js +3 -0
  25. package/dist/media/video-engine-media-source.js.map +1 -0
  26. package/dist/playback/media-playback-controller.d.ts +7 -1
  27. package/dist/playback/media-playback-controller.d.ts.map +1 -1
  28. package/dist/render-preparation/mask-frame-artifact.d.ts +48 -12
  29. package/dist/render-preparation/mask-frame-artifact.d.ts.map +1 -1
  30. package/dist/render-preparation/mask-frame-compositor.d.ts +12 -5
  31. package/dist/render-preparation/mask-frame-compositor.d.ts.map +1 -1
  32. package/dist/render-preparation/mask-frame-preparer.d.ts.map +1 -1
  33. package/dist/render-preparation/mask-preparation-worker-count.d.ts +4 -4
  34. package/dist/render-preparation/mask-preparation-worker-protocol.d.ts +13 -3
  35. package/dist/render-preparation/mask-preparation-worker-protocol.d.ts.map +1 -1
  36. package/dist/render-preparation/prepared-render-window.d.ts +44 -2
  37. package/dist/render-preparation/prepared-render-window.d.ts.map +1 -1
  38. package/dist/render-preparation/prepared-window-timeline.d.ts +2 -6
  39. package/dist/render-preparation/prepared-window-timeline.d.ts.map +1 -1
  40. package/dist/renderers/injected-pixi.d.ts +38 -0
  41. package/dist/renderers/injected-pixi.d.ts.map +1 -0
  42. package/dist/renderers/mask-palette.d.ts +14 -0
  43. package/dist/renderers/mask-palette.d.ts.map +1 -0
  44. package/dist/renderers/mask-vertex.d.ts +14 -0
  45. package/dist/renderers/mask-vertex.d.ts.map +1 -0
  46. package/dist/renderers/media-renderer-core.d.ts +9 -0
  47. package/dist/renderers/media-renderer-core.d.ts.map +1 -1
  48. package/dist/renderers/media-renderer-scene.d.ts +50 -2
  49. package/dist/renderers/media-renderer-scene.d.ts.map +1 -1
  50. package/dist/renderers/media-renderer-state.d.ts +20 -1
  51. package/dist/renderers/media-renderer-state.d.ts.map +1 -1
  52. package/dist/renderers/media-renderer-transport.d.ts +72 -0
  53. package/dist/renderers/media-renderer-transport.d.ts.map +1 -0
  54. package/dist/renderers/pixi-box-layer.d.ts +5 -0
  55. package/dist/renderers/pixi-box-layer.d.ts.map +1 -1
  56. package/dist/renderers/pixi-focus-layer.d.ts +19 -2
  57. package/dist/renderers/pixi-focus-layer.d.ts.map +1 -1
  58. package/dist/renderers/pixi-frame-present.d.ts +77 -0
  59. package/dist/renderers/pixi-frame-present.d.ts.map +1 -0
  60. package/dist/renderers/pixi-id-mask-shader.d.ts +6 -25
  61. package/dist/renderers/pixi-id-mask-shader.d.ts.map +1 -1
  62. package/dist/renderers/pixi-interaction-layer.d.ts.map +1 -1
  63. package/dist/renderers/pixi-interaction-presentation-layer.d.ts +12 -2
  64. package/dist/renderers/pixi-interaction-presentation-layer.d.ts.map +1 -1
  65. package/dist/renderers/pixi-mask-halo.d.ts +18 -23
  66. package/dist/renderers/pixi-mask-halo.d.ts.map +1 -1
  67. package/dist/renderers/pixi-mask-layer.d.ts +94 -32
  68. package/dist/renderers/pixi-mask-layer.d.ts.map +1 -1
  69. package/dist/renderers/pixi-media-scene.d.ts +67 -0
  70. package/dist/renderers/pixi-media-scene.d.ts.map +1 -1
  71. package/dist/renderers/pixi-polygon-layer.d.ts +9 -2
  72. package/dist/renderers/pixi-polygon-layer.d.ts.map +1 -1
  73. package/dist/renderers/pixi-region-coverage-mask.d.ts +62 -0
  74. package/dist/renderers/pixi-region-coverage-mask.d.ts.map +1 -0
  75. package/dist/renderers/pixi-region-effect.d.ts +42 -0
  76. package/dist/renderers/pixi-region-effect.d.ts.map +1 -0
  77. package/dist/renderers/pixi-region-layer.d.ts +43 -2
  78. package/dist/renderers/pixi-region-layer.d.ts.map +1 -1
  79. package/dist/renderers/pixi-shader-lifecycle.d.ts +14 -0
  80. package/dist/renderers/pixi-shader-lifecycle.d.ts.map +1 -0
  81. package/dist/renderers/pixi-vector-layer.d.ts.map +1 -1
  82. package/dist/renderers/prepared-annotation-window.d.ts +47 -0
  83. package/dist/renderers/prepared-annotation-window.d.ts.map +1 -0
  84. package/dist/renderers/presented-frame-channel.d.ts +138 -0
  85. package/dist/renderers/presented-frame-channel.d.ts.map +1 -0
  86. package/dist/renderers/scene-render-scheduler.d.ts +20 -0
  87. package/dist/renderers/scene-render-scheduler.d.ts.map +1 -0
  88. package/dist/sessions/media-session-defaults.d.ts +10 -6
  89. package/dist/sessions/media-session-defaults.d.ts.map +1 -1
  90. package/dist/sessions/media-session-media.d.ts.map +1 -1
  91. package/dist/sessions/media-session-state.d.ts.map +1 -1
  92. package/dist/sessions/media-session.d.ts.map +1 -1
  93. package/dist/tracking.worker.js +73 -4
  94. package/dist/tracking.worker.js.map +1 -1
  95. package/dist/types/media-normalization.d.ts +34 -0
  96. package/dist/types/media-normalization.d.ts.map +1 -1
  97. package/dist/types/media-renderer.d.ts +31 -1
  98. package/dist/types/media-renderer.d.ts.map +1 -1
  99. package/dist/types/media-session.d.ts +89 -15
  100. package/dist/types/media-session.d.ts.map +1 -1
  101. package/dist/types/render-preparation.d.ts +149 -5
  102. package/dist/types/render-preparation.d.ts.map +1 -1
  103. package/dist/video-engine-media-source-CUXnOJOV.js +450 -0
  104. package/dist/video-engine-media-source-CUXnOJOV.js.map +1 -0
  105. package/dist/web-video-engine/analysis-session.d.ts +75 -0
  106. package/dist/web-video-engine/analysis.d.ts +6 -0
  107. package/dist/web-video-engine/analysis.js +1850 -0
  108. package/dist/web-video-engine/cache-budget.d.ts +18 -0
  109. package/dist/web-video-engine/canvas-sink-scrub-cursor.d.ts +89 -0
  110. package/dist/web-video-engine/clock.d.ts +82 -0
  111. package/dist/web-video-engine/constants.d.ts +261 -0
  112. package/dist/web-video-engine/create-scrub-cursor.d.ts +65 -0
  113. package/dist/web-video-engine/decode-resolution.d.ts +114 -0
  114. package/dist/web-video-engine/decode-scheduler.d.ts +371 -0
  115. package/dist/web-video-engine/decode-session.d.ts +283 -0
  116. package/dist/web-video-engine/decode-source.d.ts +258 -0
  117. package/dist/web-video-engine/diagnostics-store.d.ts +17 -0
  118. package/dist/web-video-engine/diagnostics.d.ts +316 -0
  119. package/dist/web-video-engine/embedded-engine-worker.d.ts +1 -0
  120. package/dist/web-video-engine/engine-core.d.ts +269 -0
  121. package/dist/web-video-engine/engine.d.ts +25 -0
  122. package/dist/web-video-engine/engine.js +912 -0
  123. package/dist/web-video-engine/engine.worker.d.ts +1 -0
  124. package/dist/web-video-engine/engine.worker.js +33624 -0
  125. package/dist/web-video-engine/frame-cache.d.ts +236 -0
  126. package/dist/web-video-engine/frame-extractor.d.ts +27 -0
  127. package/dist/web-video-engine/frame-timeline-DreEwsRY.js +616 -0
  128. package/dist/web-video-engine/frame-timeline.d.ts +80 -0
  129. package/dist/web-video-engine/frame-walker.d.ts +73 -0
  130. package/dist/web-video-engine/index.d.ts +13 -0
  131. package/dist/web-video-engine/index.d.ts.map +1 -0
  132. package/dist/web-video-engine/index.js +3 -0
  133. package/dist/web-video-engine/index.js.map +1 -0
  134. package/dist/web-video-engine/key-packet.d.ts +64 -0
  135. package/dist/web-video-engine/keyframe-index.d.ts +90 -0
  136. package/dist/web-video-engine/mirror-store.d.ts +55 -0
  137. package/dist/web-video-engine/renderer.d.ts +93 -0
  138. package/dist/web-video-engine/rotation.d.ts +34 -0
  139. package/dist/web-video-engine/scrub-controller.d.ts +375 -0
  140. package/dist/web-video-engine/scrub-cursor.d.ts +347 -0
  141. package/dist/web-video-engine/scrub-trajectory.d.ts +29 -0
  142. package/dist/web-video-engine/source-residency.d.ts +91 -0
  143. package/dist/web-video-engine/trace-recorder.d.ts +163 -0
  144. package/dist/web-video-engine/types.d.ts +200 -0
  145. package/dist/web-video-engine/video-engine.d.ts +437 -0
  146. package/dist/web-video-engine/webgpu-renderer.d.ts +61 -0
  147. package/dist/web-video-engine/worker-bridge.d.ts +11 -0
  148. package/dist/web-video-engine/worker-dispatch.d.ts +16 -0
  149. package/dist/web-video-engine/worker-protocol.d.ts +282 -0
  150. package/node_modules/supervision-js-core/dist/detections/buffered-detection-timeline.d.ts.map +1 -1
  151. package/node_modules/supervision-js-core/dist/detections/composite-detection-frame-source.d.ts.map +1 -1
  152. package/node_modules/supervision-js-core/dist/index.d.ts +5 -4
  153. package/node_modules/supervision-js-core/dist/index.d.ts.map +1 -1
  154. package/node_modules/supervision-js-core/dist/index.js +1167 -280
  155. package/node_modules/supervision-js-core/dist/index.js.map +1 -1
  156. package/node_modules/supervision-js-core/dist/styles/default-annotation-presentation.d.ts.map +1 -1
  157. package/node_modules/supervision-js-core/dist/styles/interaction-style.d.ts +4 -36
  158. package/node_modules/supervision-js-core/dist/styles/interaction-style.d.ts.map +1 -1
  159. package/node_modules/supervision-js-core/dist/styles/polyline-style.d.ts +5 -0
  160. package/node_modules/supervision-js-core/dist/styles/polyline-style.d.ts.map +1 -1
  161. package/node_modules/supervision-js-core/dist/types/annotation-renderer.d.ts +92 -7
  162. package/node_modules/supervision-js-core/dist/types/annotation-renderer.d.ts.map +1 -1
  163. package/node_modules/supervision-js-core/dist/types/detection-timeline.d.ts +191 -17
  164. package/node_modules/supervision-js-core/dist/types/detection-timeline.d.ts.map +1 -1
  165. package/node_modules/supervision-js-core/dist/types/media-rendering.d.ts +83 -5
  166. package/node_modules/supervision-js-core/dist/types/media-rendering.d.ts.map +1 -1
  167. package/node_modules/supervision-js-core/dist/types/polyline-style.d.ts +2 -0
  168. package/node_modules/supervision-js-core/dist/types/polyline-style.d.ts.map +1 -1
  169. package/node_modules/supervision-js-core/dist/types/session-lifecycle.d.ts +32 -0
  170. package/node_modules/supervision-js-core/dist/types/session-lifecycle.d.ts.map +1 -1
  171. package/node_modules/supervision-js-core/dist/utils/detection-conversions.d.ts.map +1 -1
  172. package/node_modules/supervision-js-core/dist/utils/detection-frames.d.ts +5 -0
  173. package/node_modules/supervision-js-core/dist/utils/detection-frames.d.ts.map +1 -1
  174. package/node_modules/supervision-js-core/dist/utils/detection-masks.d.ts +9 -0
  175. package/node_modules/supervision-js-core/dist/utils/detection-masks.d.ts.map +1 -1
  176. package/node_modules/supervision-js-core/dist/utils/detection-ranges.d.ts +18 -0
  177. package/node_modules/supervision-js-core/dist/utils/detection-ranges.d.ts.map +1 -0
  178. package/node_modules/supervision-js-core/dist/utils/id-mask-frame.d.ts +34 -2
  179. package/node_modules/supervision-js-core/dist/utils/id-mask-frame.d.ts.map +1 -1
  180. package/node_modules/supervision-js-core/dist/utils/wait-bound.d.ts +7 -0
  181. package/node_modules/supervision-js-core/dist/utils/wait-bound.d.ts.map +1 -0
  182. package/package.json +24 -3
@@ -0,0 +1,258 @@
1
+ import { BlobSource, ReadableStreamSource, UrlSource } from "mediabunny";
2
+ import type { CreateScrubCursorOptions } from "./create-scrub-cursor";
3
+ import { type SessionFrameSource } from "./decode-session";
4
+ import type { SourceResidency } from "./source-residency";
5
+ import type { KeyframeProbe } from "./keyframe-index";
6
+ import { type ScrubTrackInfo, type VideoSampleLike } from "./scrub-cursor";
7
+ import { type DecodePath, type UrlSourceReadConfig, type UrlVideoSource, type VideoSource } from "./types";
8
+ /**
9
+ * A decoded frame handle: the slice of mediabunny's WrappedCanvas the runtime
10
+ * paints, caches, and extracts. Only the canvas and its presentation timestamp
11
+ * matter.
12
+ */
13
+ export interface WrappedCanvasLike {
14
+ readonly canvas: OffscreenCanvas | HTMLCanvasElement;
15
+ readonly timestamp: number;
16
+ }
17
+ /**
18
+ * The slice of mediabunny's CanvasSink the runtime decodes through. getCanvas
19
+ * does the random-access keyframe walk and GOP decode internally; canvases
20
+ * streams forward for playback and stepping; canvasesAtTimestamps decodes a set
21
+ * of sorted timestamps in one pass (the prefetch window and frame extraction).
22
+ */
23
+ export interface CanvasFrameSource {
24
+ getCanvas(timestampS: number): Promise<WrappedCanvasLike | null>;
25
+ canvases(startS: number): AsyncGenerator<WrappedCanvasLike, void, unknown>;
26
+ canvasesAtTimestamps(timestamps: Iterable<number>): AsyncGenerator<WrappedCanvasLike | null, void, unknown>;
27
+ }
28
+ /**
29
+ * The opened decode primitives for one source: resolved track facts plus the
30
+ * two sinks the runtime rides. Built once by openDecodeSource, so a consumer
31
+ * never imports mediabunny and stays fake-injectable under test. This seam is
32
+ * shared by the playback cursors and the playback-independent AnalysisSession,
33
+ * so it lives here next to its producer rather than inside any one consumer.
34
+ */
35
+ export interface DecodeSourceHandle {
36
+ readonly track: ScrubTrackInfo;
37
+ readonly sink: CanvasFrameSource;
38
+ readonly keyframeProbe: KeyframeProbe;
39
+ dispose(): Promise<void>;
40
+ }
41
+ /**
42
+ * The slice of mediabunny's VideoSampleSink the runtime decodes through, mirror
43
+ * for mirror with CanvasFrameSource but yielding live VideoSamples the zero-copy
44
+ * WebGPU path imports directly. The sink yields raw samples; the cursor wraps
45
+ * each in idempotentSample before emitting so the close obligation is safe to
46
+ * discharge from every path.
47
+ */
48
+ export interface SampleFrameSource {
49
+ getSample(timestampS: number): Promise<VideoSampleLike | null>;
50
+ samples(startS: number): AsyncGenerator<VideoSampleLike, void, unknown>;
51
+ samplesAtTimestamps(timestamps: Iterable<number>): AsyncGenerator<VideoSampleLike | null, void, unknown>;
52
+ }
53
+ /**
54
+ * The opened decode primitives for the zero-copy sample path: the same resolved
55
+ * track facts and keyframe probe as DecodeSourceHandle, with the VideoSampleSink
56
+ * standing in for the CanvasSink. Built only where zeroCopyViable approves the
57
+ * path, so the rest of the runtime never reaches it by accident.
58
+ */
59
+ export interface SampleSourceHandle {
60
+ readonly track: ScrubTrackInfo;
61
+ readonly sampleSink: SampleFrameSource;
62
+ readonly keyframeProbe: KeyframeProbe;
63
+ dispose(): Promise<void>;
64
+ }
65
+ /**
66
+ * The opened decode primitives for the long-lived-decoder path: the same
67
+ * resolved track facts and keyframe probe as the sink handles, with a
68
+ * DecodeSession standing in for the sink. Built only where decodeSessionViable
69
+ * approves the path.
70
+ */
71
+ export interface SessionSourceHandle {
72
+ readonly track: ScrubTrackInfo;
73
+ readonly session: SessionFrameSource;
74
+ readonly keyframeProbe: KeyframeProbe;
75
+ dispose(): Promise<void>;
76
+ }
77
+ /**
78
+ * One decoded frame, tagged by which sink produced it. A canvas frame from the
79
+ * CanvasSink path; a sample frame from the VideoSampleSink path, carrying a live
80
+ * VideoSample the cursor owns the close of. The cursor turns each into the
81
+ * matching ScrubFrame kind, so the canvas-vs-sample branch lives in one place
82
+ * rather than forking every cursor method.
83
+ */
84
+ export type DecodedFrame = {
85
+ readonly kind: "canvas";
86
+ readonly canvas: OffscreenCanvas | HTMLCanvasElement;
87
+ readonly timestamp: number;
88
+ } | {
89
+ readonly kind: "sample";
90
+ readonly sample: VideoSampleLike;
91
+ readonly timestamp: number;
92
+ };
93
+ /**
94
+ * The decode seam both cursors ride, normalized over the two sink kinds: a
95
+ * random-access read, a forward stream, and a sorted-timestamp batch, each
96
+ * yielding a DecodedFrame. The provider also names the path it was built over,
97
+ * which the scheduler reports so a human can see which machinery is decoding.
98
+ */
99
+ export interface FrameProvider {
100
+ readonly decodePath: DecodePath;
101
+ readonly track: ScrubTrackInfo;
102
+ readonly keyframeProbe: KeyframeProbe;
103
+ getFrame(timestampS: number): Promise<DecodedFrame | null>;
104
+ frames(startS: number): AsyncGenerator<DecodedFrame, void, unknown>;
105
+ framesAt(timestamps: Iterable<number>): AsyncGenerator<DecodedFrame | null, void, unknown>;
106
+ /**
107
+ * Whether reaching `timestampS` would restart this provider from a keyframe
108
+ * and decode everything in between. Only the long-lived decode session ever
109
+ * answers true: the sink paths re-position per retrieval, so nothing they
110
+ * are asked for is dearer than anything else.
111
+ */
112
+ wouldReanchor(timestampS: number): boolean;
113
+ /**
114
+ * Decoded frames a consumer may hold ahead of the playhead. Only the
115
+ * zero-copy sample sink is constrained here: each of its frames pins a slot
116
+ * in a fixed pool, so a deep queue starves the decoder that fills it. The
117
+ * other paths hand out frames they own, and a cushion is what stops a decode
118
+ * that overruns one frame interval from starving the next paint.
119
+ */
120
+ readonly playReadAhead: number;
121
+ /**
122
+ * Frames the decode machinery has produced since open, monotonic. On the
123
+ * session path this counts every decoder output including discarded walk
124
+ * pre-roll; the sink paths can only count what mediabunny yields, so their
125
+ * figure is a floor, not the decoder's true output.
126
+ */
127
+ framesDecoded(): number;
128
+ dispose(): Promise<void>;
129
+ }
130
+ /**
131
+ * The forward-sample seam a batch range walk reads: the track's own timing
132
+ * origin and one stream of its frames in presentation order. Both sample-
133
+ * yielding paths present this shape, so the walk never branches on which decoder
134
+ * it got, and every sample it hands over carries a close obligation.
135
+ */
136
+ export interface WalkFrameSource {
137
+ readonly track: ScrubTrackInfo;
138
+ framesFrom(startS: number): AsyncGenerator<VideoSampleLike, void, unknown>;
139
+ }
140
+ /** A walk source and its disposal, held by whoever opened it. */
141
+ export interface WalkSourceHandle extends WalkFrameSource {
142
+ dispose(): Promise<void>;
143
+ }
144
+ /** Discriminates the opened-source handle shapes at the cursor boundary. */
145
+ export type AnySourceHandle = DecodeSourceHandle | SampleSourceHandle | SessionSourceHandle;
146
+ /**
147
+ * Wraps any opened-source handle in the unified FrameProvider. The two sample
148
+ * paths wrap each yielded VideoSample in idempotentSample so the cursor can
149
+ * discharge the close obligation from any path without double-free.
150
+ */
151
+ export declare function openFrameProvider(handle: AnySourceHandle): FrameProvider;
152
+ /**
153
+ * Opens a source on the CanvasSink path, the one every decodable source
154
+ * supports. Track facts are resolved here too, so the consumer receives a fully
155
+ * described handle and never touches mediabunny or the resolution math. Playback
156
+ * consumers call openScrubSource instead and take whatever path the source
157
+ * supports; this is for consumers that want canvases specifically.
158
+ */
159
+ export declare function openDecodeSource(options: CreateScrubCursorOptions): Promise<DecodeSourceHandle>;
160
+ /**
161
+ * Opens a source and routes it to the fastest decode path it supports: the
162
+ * long-lived DecodeSession, then the zero-copy VideoSampleSink, then the
163
+ * CanvasSink.
164
+ *
165
+ * The session's condition is the track's codec, which nothing can answer until
166
+ * the container has been read, so the input opens first and the path is chosen
167
+ * against what the opened track reports. The one input then serves whichever
168
+ * path won.
169
+ */
170
+ export declare function openScrubSource(options: CreateScrubCursorOptions): Promise<AnySourceHandle>;
171
+ /**
172
+ * Opens a source for a batch walk over its frames, on its own input and its own
173
+ * decoder. A walk reads thousands of frames in a row and a playback cursor is
174
+ * serving a screen, so the two never share: whatever a walk does to its read
175
+ * head, no gesture is waiting behind it.
176
+ *
177
+ * The CanvasSink path is not offered here. It yields recycled canvases with no
178
+ * duration and no close, and a walk's whole contract is real frames with the
179
+ * timing they were encoded with, so a source that cannot present samples cannot
180
+ * be walked. Frames arrive at the source's native resolution; nothing downscales
181
+ * them on the way out.
182
+ */
183
+ export declare function openWalkSource(source: VideoSource): Promise<WalkSourceHandle>;
184
+ /**
185
+ * Inputs the zero-copy gate reasons over. Held as data, not probed live, so the
186
+ * predicate is pure and unit-testable: the caller measures the realm once and
187
+ * passes the facts in.
188
+ */
189
+ export interface ZeroCopyContext {
190
+ /** True when the consumer pinned the 2D renderer. */
191
+ readonly prefer2d: boolean;
192
+ /** Whether decode runs at the source's native size (the strategy requests no
193
+ * downscale). A downscale rules the path out: the sample arrives native, so
194
+ * importing it zero-copy would paint at the wrong resolution. */
195
+ readonly decodesNative: boolean;
196
+ /** Whether the worker realm has WebGPU with importExternalTexture, the API
197
+ * the zero-copy import needs. */
198
+ readonly webgpuImportAvailable: boolean;
199
+ }
200
+ /**
201
+ * The gate. True only when every condition holds: the 2D path is not pinned, the
202
+ * strategy decodes at native (no downscale), and the realm offers WebGPU's
203
+ * importExternalTexture. False keeps the byte-identical CanvasSink path; this is
204
+ * the one place the additive path is allowed to switch on.
205
+ */
206
+ export declare function zeroCopyViable(ctx: ZeroCopyContext): boolean;
207
+ /**
208
+ * Inputs the long-lived-decoder gate reasons over, held as data for the same
209
+ * reason ZeroCopyContext is.
210
+ *
211
+ * Decode resolution is deliberately absent. The session owns its decoder and
212
+ * always decodes at the source's native size, so a requested downscale is a
213
+ * canvas and cache concern rather than a reason to refuse the path.
214
+ */
215
+ export interface DecodeSessionContext {
216
+ /** Whether this realm has WebCodecs. The session builds and drives its own
217
+ * VideoDecoder rather than decoding through a mediabunny sink. */
218
+ readonly videoDecoderAvailable: boolean;
219
+ /** The opened track's decoder config, which decides whether the session's
220
+ * anchor trick applies to this bitstream. */
221
+ readonly decoderConfig: VideoDecoderConfig;
222
+ }
223
+ /** Platform facts used to contain decoder-output ownership to Android.
224
+ * Client hints win when available so desktop UA emulation cannot accidentally
225
+ * turn the expensive path on. */
226
+ export interface DecodeSessionPixelOwnershipContext {
227
+ readonly clientPlatform?: string;
228
+ readonly userAgent?: string;
229
+ readonly offscreenCanvasAvailable: boolean;
230
+ }
231
+ export declare function shouldOwnDecodeSessionPixels(context: DecodeSessionPixelOwnershipContext): boolean;
232
+ /**
233
+ * The gate. The session reaches a non-IDR anchor by declaring it a recovery
234
+ * point, which only holds for AVCC-framed H.264 carrying its parameter sets, so
235
+ * every other source keeps the mediabunny sinks.
236
+ */
237
+ export declare function decodeSessionViable(ctx: DecodeSessionContext): boolean;
238
+ /** Whether this realm exposes the WebCodecs decoder the session constructs. */
239
+ export declare function detectVideoDecoder(): boolean;
240
+ /**
241
+ * Probes the worker realm for WebGPU with importExternalTexture. Checks for the
242
+ * method on the prototype rather than acquiring a device, so it is synchronous
243
+ * and cheap; the actual device acquisition still happens (and can still fail
244
+ * back to 2D) in the renderer.
245
+ */
246
+ export declare function detectWebgpuImport(): boolean;
247
+ export declare function urlRequestInit(crossOrigin: UrlVideoSource["crossOrigin"]): {
248
+ requestInit: RequestInit;
249
+ } | undefined;
250
+ export declare function toMediabunnySource(source: VideoSource, residency?: SourceResidency, urlSource?: UrlSourceReadConfig): UrlSource | BlobSource | ReadableStreamSource;
251
+ /**
252
+ * Whether a source can be opened a second time, which the hang-recovery path
253
+ * needs to rebuild a wedged decoder. A URL re-fetches and a Blob re-reads, so
254
+ * both re-open cleanly. A ReadableStream is consumed once and cannot be rewound,
255
+ * so a rebuild on it would open onto an exhausted stream; the watchdog falls back
256
+ * to a degraded-but-alive state instead of rebuilding for that kind.
257
+ */
258
+ export declare function isReopenableSource(source: VideoSource): boolean;
@@ -0,0 +1,17 @@
1
+ import type { DiagnosticsSnapshot } from "./diagnostics";
2
+ /**
3
+ * Sibling of MirrorStore for the diagnostics broadcast plane. A single
4
+ * channel holding the latest snapshot, shaped for useSyncExternalStore. Fed only
5
+ * by the 'diag' event; the playback mirror store and its subscribers never touch
6
+ * it, so a 10Hz diagnostics push never wakes a playback consumer.
7
+ *
8
+ * getSnapshot returns the same reference between writes, so a selector using
9
+ * Object.is short-circuits when nothing changed.
10
+ */
11
+ export declare class DiagnosticsStore {
12
+ private snapshot;
13
+ private readonly listeners;
14
+ getSnapshot(): DiagnosticsSnapshot | null;
15
+ write(snapshot: DiagnosticsSnapshot): void;
16
+ subscribe(listener: () => void): () => void;
17
+ }
@@ -0,0 +1,316 @@
1
+ import type { FrameCacheStats } from "./frame-cache";
2
+ import type { FrameId } from "./frame-timeline";
3
+ import type { GopStats } from "./keyframe-index";
4
+ import type { FrameQuality, SchedulerStats } from "./scrub-cursor";
5
+ import type { PresentationMode } from "./types";
6
+ /** Which render backend is painting the display canvas. */
7
+ export type RendererName = "2d" | "webgpu";
8
+ /** Resolved track facts worth surfacing for diagnostics. decodeWidth/Height
9
+ * explain cache slot counts: the exact tier is RAM-budgeted, so large frames
10
+ * mean few slots. */
11
+ export interface DiagnosticsTrack {
12
+ readonly decodeWidth: number;
13
+ readonly decodeHeight: number;
14
+ readonly nativeFps: number | null;
15
+ readonly durationS: number;
16
+ }
17
+ /**
18
+ * Engine-level diagnostics snapshot the worker assembles on demand. Combines the
19
+ * renderer (controller-owned), track facts, and the scheduler stats (cursor-
20
+ * owned, null on the uncached cursor). All plain data, so it crosses the worker
21
+ * boundary by structured clone.
22
+ *
23
+ * What `getStats` answers with, one round trip per call and no broadcast timer
24
+ * required. {@link DiagnosticsSnapshot} opens with these same three fields and
25
+ * carries the rest of the instrument payload, but only while the diagnostics
26
+ * broadcast is running.
27
+ */
28
+ export interface EngineDiagnostics {
29
+ readonly renderer: RendererName | null;
30
+ readonly track: DiagnosticsTrack | null;
31
+ readonly scheduler: SchedulerStats | null;
32
+ }
33
+ /** Per-paint realtime needles. effectivePaintFps is the painted rate over a
34
+ * trailing window of broadcast intervals (see PaintRateMeter), null unless
35
+ * playback was up across the whole window, so every snapshot in a series
36
+ * carries its own reading. ticks and paints reset at each play start, so they
37
+ * count the current play session rather than the source's lifetime.
38
+ * catchUpMs is how far the clock ran past the last painted frame.
39
+ * playQueueDepth is the decode-ahead buffer's current length: 0 while playing is
40
+ * the imminent-stall tell. */
41
+ export interface RealtimeDiagnostics {
42
+ readonly effectivePaintFps: number | null;
43
+ readonly catchUpMs: number;
44
+ readonly lateFrames: number;
45
+ readonly stalls: number;
46
+ readonly ticks: number;
47
+ readonly paints: number;
48
+ readonly playQueueDepth: number;
49
+ /** Decoded frames thrown away before reaching the canvas: ones that arrived
50
+ * for a position playback had left, buffered ones overtaken by the clock
51
+ * moving backwards, and the ones the present cadence declines once the rate
52
+ * asks for more frames a second than it. The first two are decode bandwidth
53
+ * spent on frames nobody ever saw; the third is the cadence doing its job,
54
+ * and at a high rate it dominates the count. */
55
+ readonly droppedFrames: number;
56
+ }
57
+ /**
58
+ * Lifetime frame ledger across the decode-to-screen pipe: what the decoder
59
+ * produced, what reached the canvas, what was discarded on the way. These three
60
+ * are only meaningful read together; the ratio between decoded and painted is
61
+ * the cost of every frame nobody saw. Monotonic from load, never reset by a
62
+ * play session. decodedFrames is null when the decode path cannot report it
63
+ * (the uncached cursor).
64
+ */
65
+ export interface PipelineDiagnostics {
66
+ readonly decodedFrames: number | null;
67
+ readonly paintedFrames: number;
68
+ readonly droppedFrames: number;
69
+ }
70
+ /** Last painted frame and its quality; see DiagnosticsSnapshot.screen. */
71
+ export interface ScreenDiagnostics {
72
+ /** Which frame of the source is up, by the engine's own frame table. */
73
+ readonly frameId: FrameId;
74
+ readonly mediaTimeMs: number;
75
+ readonly quality: FrameQuality;
76
+ }
77
+ /** Cache occupancy in bytes, derived from resident slot counts and frame dims.
78
+ * exactBytesPct is the exact tier's fill against its RAM ceiling; a high value
79
+ * with a low hit rate is the starved-cache tell. */
80
+ export interface CacheBytesDiagnostics {
81
+ readonly exactBytes: number;
82
+ readonly previewBytes: number;
83
+ readonly exactBudgetBytes: number;
84
+ readonly exactBytesPct: number;
85
+ }
86
+ /** Track geometry that explains decode cost. nativeWidth/Height come from the
87
+ * source track (omitted when the track exposes no native dims). downscaleRatio
88
+ * is decodeWidth/nativeWidth; decodeVsDisplayAreaRatio compares the decoded
89
+ * frame area to the bound canvas area (>1 means decoding larger than painted). */
90
+ export interface TrackGeometryDiagnostics {
91
+ readonly nativeWidth: number | null;
92
+ readonly nativeHeight: number | null;
93
+ readonly decodeWidth: number;
94
+ readonly decodeHeight: number;
95
+ readonly downscaleRatio: number | null;
96
+ readonly decodeVsDisplayAreaRatio: number | null;
97
+ readonly boundCanvasWidth: number | null;
98
+ readonly boundCanvasHeight: number | null;
99
+ }
100
+ /** GOP distribution plus the labelled estimates. estimatedGopWalkDepthFrames is
101
+ * an ESTIMATE: frames a worst-case off-anchor scrub would decode, derived from
102
+ * avg GOP and native fps, never measured inside the decode loop. */
103
+ export interface GopDiagnostics extends GopStats {
104
+ /** Media seconds from the playhead to the closest anchor the keyframe index
105
+ * has discovered so far. The index fills lazily, so this reads null until it
106
+ * holds one and tightens as it walks further. */
107
+ readonly distanceToNearestKeyframeS: number | null;
108
+ readonly estimatedGopWalkDepthFrames: number;
109
+ }
110
+ /** Scrub responsiveness aggregates lifted from the scheduler. cacheHitRatePct
111
+ * reads 0 when nothing has looked the cache up yet, which is indistinguishable
112
+ * from every lookup missing; cacheLookups() is the denominator that tells the
113
+ * two apart. */
114
+ export interface ScrubDiagnostics {
115
+ readonly samples: number;
116
+ readonly avgMs: number;
117
+ readonly maxMs: number;
118
+ readonly p50Ms: number;
119
+ readonly p95Ms: number;
120
+ readonly targetVsLandedMs: number;
121
+ readonly timeToCrispMs: number;
122
+ readonly cacheHitRatePct: number;
123
+ }
124
+ /**
125
+ * Seeks served by re-anchoring the running playback walk, the path a seek
126
+ * issued while playing takes, with the wall time each waited for its crisp
127
+ * frame. They never reach the cursor, so nothing in ScrubDiagnostics and no
128
+ * cache lookup counts them. samples is the denominator of avgMs and maxMs: it
129
+ * trails seeks whenever one is superseded, or the transport stopped under it,
130
+ * before its crisp frame arrived.
131
+ */
132
+ export interface PlaySeekDiagnostics {
133
+ readonly seeks: number;
134
+ readonly samples: number;
135
+ readonly avgMs: number;
136
+ readonly maxMs: number;
137
+ }
138
+ /** Decode/seek/prefetch counters lifted from the scheduler. */
139
+ export interface CounterDiagnostics {
140
+ readonly foregroundDecodes: number;
141
+ readonly prefetchExact: number;
142
+ readonly prefetchPreview: number;
143
+ readonly keyframeAnchored: number;
144
+ readonly exactSeeks: number;
145
+ readonly keySeeks: number;
146
+ readonly seekCoalesceDepth: number;
147
+ readonly probeRoundTrips: number;
148
+ readonly prefetchInFlight: boolean;
149
+ /**
150
+ * Background sweeps cancelled since the source opened, as a running total, so
151
+ * a rate is only ever the delta between two snapshots. Playback schedules no
152
+ * sweeps, so a clip that only plays never moves this.
153
+ */
154
+ readonly prefetchGeneration: number;
155
+ readonly nextPending: number;
156
+ /** How long the cursor has been draining a seek uninterrupted, in ms; 0 when
157
+ * none is in flight. Every play pull is refused for the whole of it. */
158
+ readonly seekDrainingForMs: number;
159
+ }
160
+ /**
161
+ * The page's JS heap in use. Blink exposes performance.memory on Window only,
162
+ * never in a worker scope, so the worker cannot read this at all: it leaves the
163
+ * field null and the main thread fills it on receipt, as it does
164
+ * webgpuAvailable. Null off Blink, and null in a trace, which is assembled
165
+ * inside the worker.
166
+ */
167
+ export interface MemoryDiagnostics {
168
+ readonly jsHeapUsedBytes: number | null;
169
+ }
170
+ /** Severity of a diagnosis, ordered info < warn < critical for sorting. */
171
+ export type WarningSeverity = "info" | "warn" | "critical";
172
+ /**
173
+ * One self-explaining diagnosis. id is the stable rule key; scenario names what
174
+ * the runtime is doing wrong in plain language; advice is the fix; evidence is
175
+ * the human-readable metric values that tripped the rule, so a trace explains
176
+ * itself to a human or an agent without re-deriving the thresholds.
177
+ */
178
+ export interface Warning {
179
+ readonly id: string;
180
+ readonly severity: WarningSeverity;
181
+ readonly title: string;
182
+ readonly scenario: string;
183
+ readonly advice: string;
184
+ readonly evidence: string;
185
+ }
186
+ /**
187
+ * Source bytes this process holds, for a host that wants to show a viewer how
188
+ * much of the clip is local. Null unless the engine was loaded with
189
+ * `sourceResidency`; nothing else in the runtime can answer it, because the
190
+ * demuxer's own reads and the browser cache are both opaque from here.
191
+ */
192
+ export interface SourceResidencyDiagnostics {
193
+ readonly ranges: readonly {
194
+ readonly start: number;
195
+ readonly end: number;
196
+ }[];
197
+ readonly residentBytes: number;
198
+ readonly totalBytes: number | null;
199
+ readonly prefetchedBytes: number;
200
+ readonly warming: boolean;
201
+ }
202
+ /**
203
+ * The clone-safe wire snapshot the worker broadcasts at BROADCAST_HZ. A superset
204
+ * of {@link EngineDiagnostics}: renderer, track and scheduler carry the same
205
+ * values, and it adds the realtime needles, the pipeline ledger, derived cache
206
+ * bytes, track geometry, GOP block, scrub aggregates, the play-time seek block,
207
+ * counters, memory, the clock/screen pair, and the worker-evaluated warnings.
208
+ * Only plain data crosses the boundary.
209
+ *
210
+ * webgpuAvailable and memory.jsHeapUsedBytes are the fields the worker leaves at
211
+ * their empty value for the main thread to fill after the broadcast, so a rule
212
+ * in evaluateWarnings (which runs in the worker) can never read them, and an
213
+ * exported trace, assembled worker-side, carries the unfilled value. Warnings
214
+ * are evaluated once, worker-side, so the HUD and an exported trace always show
215
+ * the same diagnoses.
216
+ */
217
+ export interface DiagnosticsSnapshot {
218
+ /**
219
+ * Which presentation the engine was loaded for. `renderer` and the geometry
220
+ * fields that need a bound canvas are null for the whole life of a "frames"
221
+ * engine, which holds none by design; without this a reader cannot tell that
222
+ * from a "canvas" engine whose renderer has not resolved yet.
223
+ */
224
+ readonly presentation: PresentationMode;
225
+ readonly renderer: RendererName | null;
226
+ readonly track: DiagnosticsTrack | null;
227
+ readonly scheduler: SchedulerStats | null;
228
+ readonly realtime: RealtimeDiagnostics;
229
+ readonly pipeline: PipelineDiagnostics;
230
+ readonly cacheBytes: CacheBytesDiagnostics;
231
+ readonly geometry: TrackGeometryDiagnostics;
232
+ readonly gop: GopDiagnostics;
233
+ readonly scrub: ScrubDiagnostics;
234
+ readonly playSeek: PlaySeekDiagnostics;
235
+ readonly counters: CounterDiagnostics;
236
+ readonly memory: MemoryDiagnostics;
237
+ readonly sourceResidency: SourceResidencyDiagnostics | null;
238
+ readonly nativeFps: number | null;
239
+ /** Media seconds per wall second the transport was told to run at. */
240
+ readonly rate: number;
241
+ /**
242
+ * The same figure measured off the canvas: media seconds of picture actually
243
+ * presented per wall second, over a trailing window; null unless playback was
244
+ * up across the whole of it. Read against `rate` it answers the one question
245
+ * a commanded rate cannot, which is whether the picture is really moving that
246
+ * fast. Falling short means frames are arriving slower than the clock wants
247
+ * them, so the picture lags further behind the playhead every second.
248
+ *
249
+ * It is a window over whole paints, so it quantises when paints are sparse: a
250
+ * slow rate on a low-fps source reads low from a healthy pipeline. Read it
251
+ * against catchUpMs before concluding anything from a shortfall.
252
+ */
253
+ readonly presentedRate: number | null;
254
+ /** The engine clock at assembly, ms; null before load. Paused, it holds the
255
+ * last commanded target; playing, it advances at rate. The one value the
256
+ * instruments draw the playhead from, so the playhead and the coverage
257
+ * lanes cannot disagree about where "now" is. */
258
+ readonly playheadMs: number | null;
259
+ /** What is actually on the canvas: last painted position and its quality;
260
+ * null before the first paint. Its distance from playheadMs is the live
261
+ * landing error (paused) or catch-up depth (playing). A sampled
262
+ * observation for instruments; frame identity for consumers still travels
263
+ * only on the paint event. */
264
+ readonly screen: ScreenDiagnostics | null;
265
+ readonly status: string;
266
+ readonly webgpuAvailable: boolean;
267
+ readonly warnings: Warning[];
268
+ }
269
+ /**
270
+ * Painted-frame rate over a trailing window of broadcast intervals, fed once
271
+ * per snapshot. A single interval can only hold whole paints, so its rate
272
+ * quantises hard; the trailing window smooths that without collapsing the
273
+ * series into a whole-capture average, which could confirm "playback is slow"
274
+ * but never locate it in time.
275
+ */
276
+ export declare class PaintRateMeter {
277
+ private readonly windowSize;
278
+ private readonly samples;
279
+ constructor(windowSize?: number);
280
+ /** Rate in paints/second, or null unless playback was up across the whole
281
+ * window. A pause or a paints reset (each play session restarts the
282
+ * counter) invalidates the window, not just the sample. */
283
+ sample(atMs: number, paints: number, playing: boolean): number | null;
284
+ }
285
+ /**
286
+ * Playback speed measured off what reached the canvas: media seconds presented
287
+ * per wall second, over the same trailing window PaintRateMeter uses. Fed the
288
+ * last painted media position once per snapshot.
289
+ *
290
+ * It reads painted positions, not paint counts: a source can paint at a healthy
291
+ * 30fps while the clock runs at 4x, and only the distance the picture travelled
292
+ * shows that the two disagree.
293
+ */
294
+ export declare class PresentedRateMeter {
295
+ private readonly windowSize;
296
+ private readonly samples;
297
+ constructor(windowSize?: number);
298
+ /** Rate in media seconds per wall second, or null unless playback was up
299
+ * across the whole window with the picture moving forward through it. */
300
+ sample(atMs: number, paintedMs: number | null, playing: boolean): number | null;
301
+ /** Drops the window, so a rate change is not measured across its own edge. */
302
+ reset(): void;
303
+ }
304
+ /**
305
+ * Cache lookups across every tier. Only an exact seek looks the cache up, so
306
+ * playback and key seeks never move this and a play-only session sits at zero.
307
+ * A rule or readout that reads the hit rate without this denominator reports a
308
+ * cold cache as a failing one.
309
+ */
310
+ export declare function cacheLookups(cache: FrameCacheStats | null | undefined): number;
311
+ /**
312
+ * Pure threshold evaluator. Reads a snapshot and returns the active diagnoses,
313
+ * critical first. Used both in the worker (so the broadcast carries warnings the
314
+ * UI and the trace share) and in tests. No I/O, no side effects.
315
+ */
316
+ export declare function evaluateWarnings(snapshot: DiagnosticsSnapshot): Warning[];
@@ -0,0 +1 @@
1
+ export declare const EMBEDDED_ENGINE_WORKER_SOURCE = "__SUPERVISION_JS_EMBEDDED_ENGINE_WORKER_SOURCE__";