supervision 0.2.0-next.0 → 0.2.0-next.2
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/constants/media-renderer.d.ts +3 -0
- package/dist/constants/media-renderer.d.ts.map +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1722 -1395
- package/dist/index.js.map +1 -1
- package/dist/mask-preparation.worker.js +109 -31
- package/dist/mask-preparation.worker.js.map +1 -1
- package/dist/media/media-frame-clock.d.ts +4 -0
- package/dist/media/media-frame-clock.d.ts.map +1 -0
- package/dist/media/media-source-state.d.ts.map +1 -1
- package/dist/media/media-source.d.ts +6 -0
- package/dist/media/media-source.d.ts.map +1 -1
- package/dist/media/video-engine-media-source.d.ts +17 -7
- package/dist/media/video-engine-media-source.d.ts.map +1 -1
- package/dist/media/video-engine-media-source.js +3 -0
- package/dist/media/video-engine-media-source.js.map +1 -0
- package/dist/playback/media-playback-controller.d.ts +7 -1
- package/dist/playback/media-playback-controller.d.ts.map +1 -1
- package/dist/render-preparation/mask-frame-artifact.d.ts +2 -0
- package/dist/render-preparation/mask-frame-artifact.d.ts.map +1 -1
- package/dist/render-preparation/mask-frame-compositor.d.ts +7 -0
- package/dist/render-preparation/mask-frame-compositor.d.ts.map +1 -1
- package/dist/render-preparation/mask-preparation-worker-protocol.d.ts +1 -0
- package/dist/render-preparation/mask-preparation-worker-protocol.d.ts.map +1 -1
- package/dist/render-preparation/prepared-render-window.d.ts +21 -2
- package/dist/render-preparation/prepared-render-window.d.ts.map +1 -1
- package/dist/render-preparation/prepared-window-timeline.d.ts +1 -0
- package/dist/render-preparation/prepared-window-timeline.d.ts.map +1 -1
- package/dist/renderers/injected-pixi.d.ts +38 -0
- package/dist/renderers/injected-pixi.d.ts.map +1 -0
- package/dist/renderers/media-frame-navigation.d.ts +17 -0
- package/dist/renderers/media-frame-navigation.d.ts.map +1 -0
- package/dist/renderers/media-renderer-core.d.ts +9 -0
- package/dist/renderers/media-renderer-core.d.ts.map +1 -1
- package/dist/renderers/media-renderer-scene.d.ts +17 -5
- package/dist/renderers/media-renderer-scene.d.ts.map +1 -1
- package/dist/renderers/media-renderer-state.d.ts +9 -0
- package/dist/renderers/media-renderer-state.d.ts.map +1 -1
- package/dist/renderers/media-renderer-transport.d.ts +19 -3
- package/dist/renderers/media-renderer-transport.d.ts.map +1 -1
- package/dist/renderers/pixi-focus-layer.d.ts +1 -0
- package/dist/renderers/pixi-focus-layer.d.ts.map +1 -1
- package/dist/renderers/pixi-frame-present.d.ts +1 -1
- package/dist/renderers/pixi-frame-present.d.ts.map +1 -1
- package/dist/renderers/pixi-id-mask-shader.d.ts +4 -33
- package/dist/renderers/pixi-id-mask-shader.d.ts.map +1 -1
- package/dist/renderers/pixi-interaction-presentation-layer.d.ts +0 -1
- package/dist/renderers/pixi-interaction-presentation-layer.d.ts.map +1 -1
- package/dist/renderers/pixi-mask-halo.d.ts +4 -33
- package/dist/renderers/pixi-mask-halo.d.ts.map +1 -1
- package/dist/renderers/pixi-mask-layer.d.ts +28 -29
- package/dist/renderers/pixi-mask-layer.d.ts.map +1 -1
- package/dist/renderers/pixi-media-scene.d.ts.map +1 -1
- package/dist/renderers/pixi-polygon-layer.d.ts +2 -0
- package/dist/renderers/pixi-polygon-layer.d.ts.map +1 -1
- package/dist/renderers/pixi-region-coverage-mask.d.ts +4 -33
- package/dist/renderers/pixi-region-coverage-mask.d.ts.map +1 -1
- package/dist/renderers/pixi-region-layer.d.ts +6 -31
- package/dist/renderers/pixi-region-layer.d.ts.map +1 -1
- package/dist/renderers/pixi-shader-lifecycle.d.ts +14 -0
- package/dist/renderers/pixi-shader-lifecycle.d.ts.map +1 -0
- package/dist/renderers/prepared-annotation-window.d.ts.map +1 -1
- package/dist/renderers/presented-frame-channel.d.ts +34 -1
- package/dist/renderers/presented-frame-channel.d.ts.map +1 -1
- package/dist/sessions/media-session-defaults.d.ts.map +1 -1
- package/dist/sessions/media-session-detections.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 +19 -5
- package/dist/tracking.worker.js.map +1 -1
- package/dist/types/media-frame-clock.d.ts +16 -0
- package/dist/types/media-frame-clock.d.ts.map +1 -0
- package/dist/types/media-frame-navigation.d.ts +28 -0
- package/dist/types/media-frame-navigation.d.ts.map +1 -0
- package/dist/types/media-renderer-display.d.ts +12 -0
- package/dist/types/media-renderer-display.d.ts.map +1 -0
- package/dist/types/media-renderer.d.ts +13 -0
- package/dist/types/media-renderer.d.ts.map +1 -1
- package/dist/types/media-session.d.ts +35 -32
- package/dist/types/media-session.d.ts.map +1 -1
- package/dist/types/render-preparation.d.ts +78 -28
- package/dist/types/render-preparation.d.ts.map +1 -1
- package/dist/video-engine-media-source-DR-x1UfK.js +483 -0
- package/dist/video-engine-media-source-DR-x1UfK.js.map +1 -0
- package/dist/web-video-engine/analysis-session.d.ts +0 -1
- package/dist/web-video-engine/analysis.d.ts +0 -1
- package/dist/web-video-engine/analysis.js +211 -23
- package/dist/web-video-engine/cache-budget.d.ts +0 -1
- package/dist/web-video-engine/canvas-sink-scrub-cursor.d.ts +6 -2
- package/dist/web-video-engine/clock.d.ts +0 -1
- package/dist/web-video-engine/constants.d.ts +9 -1
- package/dist/web-video-engine/create-scrub-cursor.d.ts +6 -3
- package/dist/web-video-engine/decode-resolution.d.ts +0 -1
- package/dist/web-video-engine/decode-scheduler.d.ts +26 -5
- package/dist/web-video-engine/decode-session.d.ts +11 -1
- package/dist/web-video-engine/decode-source.d.ts +11 -1
- package/dist/web-video-engine/diagnostics-store.d.ts +0 -1
- package/dist/web-video-engine/diagnostics.d.ts +19 -19
- package/dist/web-video-engine/embedded-engine-worker.d.ts +0 -1
- package/dist/web-video-engine/engine-core.d.ts +31 -11
- package/dist/web-video-engine/engine.d.ts +3 -4
- package/dist/web-video-engine/engine.js +175 -44
- package/dist/web-video-engine/engine.worker.d.ts +0 -1
- package/dist/web-video-engine/engine.worker.js +5712 -2947
- package/dist/web-video-engine/frame-cache.d.ts +121 -12
- package/dist/web-video-engine/frame-extractor.d.ts +0 -1
- package/dist/web-video-engine/{frame-timeline-GINI8Gum.js → frame-timeline-DreEwsRY.js} +83 -27
- package/dist/web-video-engine/frame-timeline.d.ts +10 -1
- package/dist/web-video-engine/frame-walker.d.ts +0 -1
- package/dist/web-video-engine/index.d.ts +12 -2
- package/dist/web-video-engine/index.d.ts.map +1 -1
- package/dist/web-video-engine/index.js +2 -2
- package/dist/web-video-engine/key-packet.d.ts +0 -1
- package/dist/web-video-engine/keyframe-index.d.ts +0 -1
- package/dist/web-video-engine/mirror-store.d.ts +0 -1
- package/dist/web-video-engine/pausable-deadline.d.ts +11 -0
- package/dist/web-video-engine/renderer.d.ts +0 -1
- package/dist/web-video-engine/rotation.d.ts +0 -1
- package/dist/web-video-engine/scrub-controller.d.ts +8 -5
- package/dist/web-video-engine/scrub-cursor.d.ts +15 -7
- package/dist/web-video-engine/scrub-trajectory.d.ts +0 -1
- package/dist/web-video-engine/source-residency.d.ts +35 -1
- package/dist/web-video-engine/trace-recorder.d.ts +0 -1
- package/dist/web-video-engine/types.d.ts +18 -22
- package/dist/web-video-engine/video-engine.d.ts +39 -17
- package/dist/web-video-engine/webgpu-renderer.d.ts +0 -1
- package/dist/web-video-engine/worker-bridge.d.ts +0 -1
- package/dist/web-video-engine/worker-dispatch.d.ts +0 -1
- package/dist/web-video-engine/worker-protocol.d.ts +38 -15
- package/node_modules/supervision-js-core/dist/detections/buffered-detection-timeline.d.ts.map +1 -1
- package/node_modules/supervision-js-core/dist/index.d.ts +2 -2
- package/node_modules/supervision-js-core/dist/index.d.ts.map +1 -1
- package/node_modules/supervision-js-core/dist/index.js +182 -68
- package/node_modules/supervision-js-core/dist/index.js.map +1 -1
- package/node_modules/supervision-js-core/dist/types/detection-timeline.d.ts +20 -3
- 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 +28 -26
- package/node_modules/supervision-js-core/dist/types/media-rendering.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-masks.d.ts.map +1 -1
- package/node_modules/supervision-js-core/dist/utils/id-mask-frame.d.ts +19 -0
- package/node_modules/supervision-js-core/dist/utils/id-mask-frame.d.ts.map +1 -1
- package/package.json +3 -3
- package/dist/media/media-condition-probe.d.ts +0 -51
- package/dist/media/media-condition-probe.d.ts.map +0 -1
- package/dist/media/media-conditions.d.ts +0 -28
- package/dist/media/media-conditions.d.ts.map +0 -1
- package/dist/types/media-conditions.d.ts +0 -149
- package/dist/types/media-conditions.d.ts.map +0 -1
- package/dist/web-video-engine/analysis-session.d.ts.map +0 -1
- package/dist/web-video-engine/analysis.d.ts.map +0 -1
- package/dist/web-video-engine/analysis.js.map +0 -1
- package/dist/web-video-engine/cache-budget.d.ts.map +0 -1
- package/dist/web-video-engine/canvas-sink-scrub-cursor.d.ts.map +0 -1
- package/dist/web-video-engine/clock.d.ts.map +0 -1
- package/dist/web-video-engine/constants.d.ts.map +0 -1
- package/dist/web-video-engine/create-scrub-cursor.d.ts.map +0 -1
- package/dist/web-video-engine/decode-resolution.d.ts.map +0 -1
- package/dist/web-video-engine/decode-scheduler.d.ts.map +0 -1
- package/dist/web-video-engine/decode-session.d.ts.map +0 -1
- package/dist/web-video-engine/decode-source.d.ts.map +0 -1
- package/dist/web-video-engine/diagnostics-store.d.ts.map +0 -1
- package/dist/web-video-engine/diagnostics.d.ts.map +0 -1
- package/dist/web-video-engine/embedded-engine-worker.d.ts.map +0 -1
- package/dist/web-video-engine/engine-core.d.ts.map +0 -1
- package/dist/web-video-engine/engine.d.ts.map +0 -1
- package/dist/web-video-engine/engine.js.map +0 -1
- package/dist/web-video-engine/engine.worker.d.ts.map +0 -1
- package/dist/web-video-engine/engine.worker.js.map +0 -1
- package/dist/web-video-engine/frame-cache.d.ts.map +0 -1
- package/dist/web-video-engine/frame-extractor.d.ts.map +0 -1
- package/dist/web-video-engine/frame-timeline-GINI8Gum.js.map +0 -1
- package/dist/web-video-engine/frame-timeline.d.ts.map +0 -1
- package/dist/web-video-engine/frame-walker.d.ts.map +0 -1
- package/dist/web-video-engine/key-packet.d.ts.map +0 -1
- package/dist/web-video-engine/keyframe-index.d.ts.map +0 -1
- package/dist/web-video-engine/mirror-store.d.ts.map +0 -1
- package/dist/web-video-engine/renderer.d.ts.map +0 -1
- package/dist/web-video-engine/rotation.d.ts.map +0 -1
- package/dist/web-video-engine/scrub-controller.d.ts.map +0 -1
- package/dist/web-video-engine/scrub-cursor.d.ts.map +0 -1
- package/dist/web-video-engine/scrub-trajectory.d.ts.map +0 -1
- package/dist/web-video-engine/source-residency.d.ts.map +0 -1
- package/dist/web-video-engine/trace-recorder.d.ts.map +0 -1
- package/dist/web-video-engine/types.d.ts.map +0 -1
- package/dist/web-video-engine/video-engine.d.ts.map +0 -1
- package/dist/web-video-engine/webgpu-renderer.d.ts.map +0 -1
- package/dist/web-video-engine/worker-bridge.d.ts.map +0 -1
- package/dist/web-video-engine/worker-dispatch.d.ts.map +0 -1
- package/dist/web-video-engine/worker-protocol.d.ts.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Two-tier frame cache
|
|
2
|
+
* Two-tier frame cache.
|
|
3
3
|
*
|
|
4
4
|
* The preview tier holds many downscaled frames: a long, coarse history that
|
|
5
5
|
* answers a scrub instantly while the crisp frame decodes. The exact tier holds
|
|
@@ -10,11 +10,18 @@
|
|
|
10
10
|
* served it. Only an exact hit is full-resolution; a preview hit still owes the
|
|
11
11
|
* caller a crisp decode.
|
|
12
12
|
*
|
|
13
|
+
* The exact tier is keyed by the timeline's identity for the frame, so two
|
|
14
|
+
* source frames can never share a slot at any frame rate. The preview tier is
|
|
15
|
+
* keyed by rounded millisecond, which merges frames spaced under a millisecond;
|
|
16
|
+
* it is the tier whose answer is already declared approximate, and it never
|
|
17
|
+
* claims to be the frame at the target.
|
|
18
|
+
*
|
|
13
19
|
* Both tiers store OffscreenCanvas blits, never VideoFrames: a raw-frame cache
|
|
14
20
|
* pins decoder output, stalling the decoder and growing VRAM without bound. A
|
|
15
21
|
* frame fed as a live VideoSample is drawn into the blit and never retained, so
|
|
16
22
|
* the no-retention rule holds on the zero-copy path too.
|
|
17
23
|
*/
|
|
24
|
+
import type { FrameId } from "./frame-timeline";
|
|
18
25
|
import type { VideoSampleLike } from "./scrub-cursor";
|
|
19
26
|
/**
|
|
20
27
|
* What the cache can blit into a tier: an already-decoded canvas/image, or a
|
|
@@ -45,11 +52,12 @@ export interface FrameCacheStats {
|
|
|
45
52
|
readonly exactTimestampsMs: number[];
|
|
46
53
|
readonly previewTimestampsMs: number[];
|
|
47
54
|
/** Configured source frame interval: the visual width of each cached mark on
|
|
48
|
-
* the timeline.
|
|
49
|
-
*
|
|
55
|
+
* the timeline. Nothing is keyed by it, so this is a display width and not
|
|
56
|
+
* the grid entries land on. */
|
|
50
57
|
readonly bucketMs: number;
|
|
51
|
-
/** Frames dropped to LRU pressure per tier, and puts that
|
|
52
|
-
*
|
|
58
|
+
/** Frames dropped to LRU pressure per tier, and puts that overwrote a live
|
|
59
|
+
* key: a frame decoded again on the exact tier, and on the preview tier
|
|
60
|
+
* either that or two frames sharing one rounded millisecond. */
|
|
53
61
|
readonly exactEvictions: number;
|
|
54
62
|
readonly previewEvictions: number;
|
|
55
63
|
readonly bucketCollapses: number;
|
|
@@ -72,10 +80,7 @@ export interface FrameCacheOptions {
|
|
|
72
80
|
/** Coarse-tier slot count. */
|
|
73
81
|
readonly previewCapacity: number;
|
|
74
82
|
/** Source frame interval in ms, reported to diagnostics as the timeline mark
|
|
75
|
-
* width. It
|
|
76
|
-
* frames onto one slot wherever the rounded interval exceeds the true one
|
|
77
|
-
* (24, 60fps and their pulldown rates), so each frame is keyed by its own
|
|
78
|
-
* millisecond instead. */
|
|
83
|
+
* width. It keys nothing. */
|
|
79
84
|
readonly bucketMs: number;
|
|
80
85
|
/** Floor on exact-tier slots, applied even when the byte budget would yield
|
|
81
86
|
* fewer. Lets a caller that owns the prefetch-window width guarantee a full
|
|
@@ -84,6 +89,7 @@ export interface FrameCacheOptions {
|
|
|
84
89
|
readonly minExactSlots?: number;
|
|
85
90
|
}
|
|
86
91
|
export declare class FrameCache {
|
|
92
|
+
private readonly options;
|
|
87
93
|
private readonly exact;
|
|
88
94
|
private readonly preview;
|
|
89
95
|
private exactHits;
|
|
@@ -92,10 +98,24 @@ export declare class FrameCache {
|
|
|
92
98
|
private readonly bucketMs;
|
|
93
99
|
private readonly exactBudgetBytes;
|
|
94
100
|
constructor(options: FrameCacheOptions);
|
|
95
|
-
|
|
96
|
-
|
|
101
|
+
resized(width: number, height: number): FrameCache;
|
|
102
|
+
/**
|
|
103
|
+
* Store a crisp full-resolution frame for the exact (scrub) tier under
|
|
104
|
+
* `frame`, the timeline's name for it. `timestampMs` is the decoded
|
|
105
|
+
* timestamp, which is what lookups match on and what a hit reports back.
|
|
106
|
+
*/
|
|
107
|
+
putExact(frame: FrameId, timestampMs: number, src: CacheBlitSource, srcWidth: number, srcHeight: number): void;
|
|
97
108
|
/** Store a downscaled frame for the coarse preview tier. */
|
|
98
109
|
putPreview(timestampMs: number, src: CacheBlitSource, srcWidth: number, srcHeight: number): void;
|
|
110
|
+
/**
|
|
111
|
+
* Best cached answer for a named source frame. The exact tier is looked up
|
|
112
|
+
* only by `frame` identity; time is used solely for the approximate preview
|
|
113
|
+
* fallback. This keeps a long variable-rate frame from borrowing a crisp
|
|
114
|
+
* neighbour merely because both timestamps fit a millisecond tolerance.
|
|
115
|
+
*/
|
|
116
|
+
getForFrame(frame: FrameId, timestampMs: number, previewTolMs: number): CachedFrame | null;
|
|
117
|
+
/** Non-accounting form of {@link getForFrame}. */
|
|
118
|
+
peekForFrame(frame: FrameId, timestampMs: number, previewTolMs: number): CachedFrame | null;
|
|
99
119
|
/**
|
|
100
120
|
* Best cached frame for `timestampMs`, consulting the exact tier then the
|
|
101
121
|
* preview tier: a crisp hit within `exactTolMs`, else a coarse hit within
|
|
@@ -123,7 +143,96 @@ export declare class FrameCache {
|
|
|
123
143
|
* from being the LRU victim of its own neighbor sweep. No-op on a miss.
|
|
124
144
|
*/
|
|
125
145
|
bumpExact(timestampMs: number): void;
|
|
146
|
+
/** Promotes one exact frame by identity. */
|
|
147
|
+
bumpExactFrame(frame: FrameId): void;
|
|
126
148
|
clear(): void;
|
|
127
149
|
get stats(): FrameCacheStats;
|
|
128
150
|
}
|
|
129
|
-
|
|
151
|
+
interface TierHit {
|
|
152
|
+
readonly canvas: OffscreenCanvas;
|
|
153
|
+
readonly timestampMs: number;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* One cache tier: a fixed-capacity, MRU-ordered set of OffscreenCanvas copies
|
|
157
|
+
* under keys its owner assigns. A put onto a live key overwrites that slot in
|
|
158
|
+
* place, so an owner that lets two frames share a key loses one of them
|
|
159
|
+
* silently; overflow past capacity evicts the least-recently-used entry
|
|
160
|
+
* instead. Lookups match on the stored frame's true timestamp and never on the
|
|
161
|
+
* key, so a cache-served frame carries the same timestamp a fresh decode would.
|
|
162
|
+
*/
|
|
163
|
+
export declare class TierStore {
|
|
164
|
+
readonly capacity: number;
|
|
165
|
+
readonly width: number;
|
|
166
|
+
readonly height: number;
|
|
167
|
+
/** Width of the grid the owner's keys round onto, or 0 when a key names a
|
|
168
|
+
* frame outright. Two entries closer together than this are one frame
|
|
169
|
+
* whose two decodes rounded onto either side of a key boundary. */
|
|
170
|
+
private readonly keyGridMs;
|
|
171
|
+
/** MRU-ordered keys. Index 0 is the LRU, the last index is the MRU. */
|
|
172
|
+
private readonly keys;
|
|
173
|
+
private readonly entries;
|
|
174
|
+
/** Canvases released by eviction, held for the next put to fill. */
|
|
175
|
+
private readonly spare;
|
|
176
|
+
private evictionCount;
|
|
177
|
+
private bucketCollapseCount;
|
|
178
|
+
/** Smallest gap between two stored frames, which is the source frame interval
|
|
179
|
+
* once neighbours are resident. Learned from the timestamps the tier is
|
|
180
|
+
* handed, so it is what the source really did rather than a declared rate.
|
|
181
|
+
* Null until two frames have landed. */
|
|
182
|
+
private observedIntervalMs;
|
|
183
|
+
constructor(capacity: number, width: number, height: number,
|
|
184
|
+
/** Width of the grid the owner's keys round onto, or 0 when a key names a
|
|
185
|
+
* frame outright. Two entries closer together than this are one frame
|
|
186
|
+
* whose two decodes rounded onto either side of a key boundary. */
|
|
187
|
+
keyGridMs: number);
|
|
188
|
+
/** Frames dropped to the LRU policy; a cache-pressure signal for diagnostics. */
|
|
189
|
+
get evictions(): number;
|
|
190
|
+
/** Puts that landed on a key already live, collapsing both onto one slot. */
|
|
191
|
+
get bucketCollapses(): number;
|
|
192
|
+
put(key: number, timestampMs: number, src: CacheBlitSource, srcWidth: number, srcHeight: number): void;
|
|
193
|
+
/**
|
|
194
|
+
* Nearest resident frame to `timestampMs` within `tolMs`, or null.
|
|
195
|
+
*
|
|
196
|
+
* `atOrBefore` restricts it to frames at or before the target, which is the
|
|
197
|
+
* contract a decode answers a seek with. Without it the tier can answer with
|
|
198
|
+
* the frame AFTER the target, one no decode would ever return, so the same
|
|
199
|
+
* pointer position paints a different frame depending on whether the cache or
|
|
200
|
+
* the decoder served it, and the picture steps forward and back as the two
|
|
201
|
+
* alternate.
|
|
202
|
+
*/
|
|
203
|
+
get(timestampMs: number, tolMs: number, atOrBefore?: boolean): TierHit | null;
|
|
204
|
+
/** Retrieves exactly one owner-assigned key and promotes it to MRU. */
|
|
205
|
+
getByKey(key: number): TierHit | null;
|
|
206
|
+
/** Promotes the entry nearest `timestampMs` to most-recently-used. Scans
|
|
207
|
+
* rather than keys off the timestamp: callers pass a gesture position, which
|
|
208
|
+
* is not a frame timestamp, so a keyed lookup would miss the very frame on
|
|
209
|
+
* screen. No accounting; it is not a lookup. */
|
|
210
|
+
touch(timestampMs: number): void;
|
|
211
|
+
/** Promotes an owner-assigned key without a timestamp scan. */
|
|
212
|
+
touchKey(key: number): void;
|
|
213
|
+
clear(): void;
|
|
214
|
+
get size(): number;
|
|
215
|
+
/** True timestamps (ms) of resident frames, for diagnostics. Bounded by capacity. */
|
|
216
|
+
timestampsSnapshot(): number[];
|
|
217
|
+
private bump;
|
|
218
|
+
/**
|
|
219
|
+
* Best candidate for `timestampMs`, or null when nothing qualifies.
|
|
220
|
+
*
|
|
221
|
+
* Under `atOrBefore` a stored frame stands for the span from its own
|
|
222
|
+
* timestamp up to the next source frame; a target past that span belongs to
|
|
223
|
+
* the next frame, which is what a decode for it returns. Answering it from
|
|
224
|
+
* this tier would paint a frame no decode for that time ever produces, so a
|
|
225
|
+
* candidate outside its own frame's span is not eligible however generous the
|
|
226
|
+
* caller's tolerance is. Until the tier has learned a frame gap it has no
|
|
227
|
+
* spacing to bound with and the caller's tolerance stands alone.
|
|
228
|
+
*/
|
|
229
|
+
private nearest;
|
|
230
|
+
/** Narrows the learned frame interval to the smallest gap seen so far. A gap
|
|
231
|
+
* at or below the key grid is one frame that rounded onto two keys rather
|
|
232
|
+
* than two frames, so it is no interval at all; what survives is a gap
|
|
233
|
+
* between two frames, and never zero. It only ever tightens, so a tier that
|
|
234
|
+
* has watched an unrepresentative stretch of a variable-rate source bounds
|
|
235
|
+
* lookups too tightly (a decode) rather than too loosely (the wrong frame). */
|
|
236
|
+
private observeSpacing;
|
|
237
|
+
}
|
|
238
|
+
export {};
|
|
@@ -157,6 +157,7 @@ const DIAGNOSTICS = {
|
|
|
157
157
|
TRACE_EVENT_CAP: 2000,
|
|
158
158
|
TRACE_SNAPSHOT_CAP: 600,
|
|
159
159
|
SCRUB_LATENCY_RING: 64,
|
|
160
|
+
KEYFRAME_TIMESTAMPS_CAP: 512,
|
|
160
161
|
};
|
|
161
162
|
/**
|
|
162
163
|
* What an armed capture actually keeps. The snapshot ring is fed at the fixed
|
|
@@ -205,8 +206,9 @@ const TRACE_RING_BOUNDS = {
|
|
|
205
206
|
* reply before the facade gives up on it.
|
|
206
207
|
*/
|
|
207
208
|
const DECODE_HANG_TIMEOUT_MS = 30_000;
|
|
209
|
+
const WORKER_COMMAND_TIMEOUT_MS = DECODE_HANG_TIMEOUT_MS + 15_000;
|
|
208
210
|
const HANG_RECOVERY = {
|
|
209
|
-
WORKER_COMMAND_TIMEOUT_MS
|
|
211
|
+
WORKER_COMMAND_TIMEOUT_MS,
|
|
210
212
|
};
|
|
211
213
|
|
|
212
214
|
const asSec = (n) => n;
|
|
@@ -234,49 +236,48 @@ var PlaybackStatus;
|
|
|
234
236
|
PlaybackStatus["Ended"] = "ENDED";
|
|
235
237
|
PlaybackStatus["Errored"] = "ERRORED";
|
|
236
238
|
})(PlaybackStatus || (PlaybackStatus = {}));
|
|
237
|
-
var
|
|
238
|
-
(function (
|
|
239
|
-
|
|
240
|
-
|
|
239
|
+
var WebVideoEngineErrorCode;
|
|
240
|
+
(function (WebVideoEngineErrorCode) {
|
|
241
|
+
WebVideoEngineErrorCode["DecodeUnsupported"] = "DECODE_UNSUPPORTED";
|
|
242
|
+
WebVideoEngineErrorCode["SourceUnreadable"] = "SOURCE_UNREADABLE";
|
|
241
243
|
/**
|
|
242
244
|
* The demuxer refused the file outright: its container is not one this build
|
|
243
245
|
* reads, so no track was ever listed and no decoder was ever asked.
|
|
244
246
|
*/
|
|
245
|
-
|
|
247
|
+
WebVideoEngineErrorCode["ContainerUnreadable"] = "CONTAINER_UNREADABLE";
|
|
246
248
|
/**
|
|
247
249
|
* The container opened and the demuxer parsed no track at all out of it. The
|
|
248
250
|
* file's streams are in formats it does not carry, so their video cannot be
|
|
249
251
|
* reached even though it is there.
|
|
250
252
|
*/
|
|
251
|
-
|
|
253
|
+
WebVideoEngineErrorCode["VideoTrackUnreadable"] = "VIDEO_TRACK_UNREADABLE";
|
|
252
254
|
/**
|
|
253
255
|
* The container opened, its tracks listed, and none of them is video. This
|
|
254
256
|
* is the only case where the file itself is what lacks video.
|
|
255
257
|
*/
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
258
|
+
WebVideoEngineErrorCode["NoVideoTrack"] = "NO_VIDEO_TRACK";
|
|
259
|
+
WebVideoEngineErrorCode["BackendCrashed"] = "BACKEND_CRASHED";
|
|
260
|
+
WebVideoEngineErrorCode["Aborted"] = "ABORTED";
|
|
259
261
|
/** A canvas was offered to an engine loaded in "frames" presentation mode,
|
|
260
262
|
* where the host owns the only canvas. */
|
|
261
|
-
|
|
263
|
+
WebVideoEngineErrorCode["PresentationMismatch"] = "PRESENTATION_MISMATCH";
|
|
262
264
|
/**
|
|
263
265
|
* The decoder cannot decode this source at all: it refused to configure, it
|
|
264
266
|
* errored, or it acknowledged decode requests and never produced a frame.
|
|
265
|
-
* Distinct from BackendCrashed
|
|
266
|
-
*
|
|
267
|
-
*
|
|
268
|
-
* decoder session the machine has.
|
|
267
|
+
* Distinct from BackendCrashed; this one survives every rebuild, so the
|
|
268
|
+
* runtime stops rebuilding and says so. The usual cause is outside the page:
|
|
269
|
+
* another tab holding every hardware decoder session the machine has.
|
|
269
270
|
*/
|
|
270
|
-
|
|
271
|
+
WebVideoEngineErrorCode["DecoderStalled"] = "DECODER_STALLED";
|
|
271
272
|
/** A playback rate outside the forward range the engine supports. */
|
|
272
|
-
|
|
273
|
-
})(
|
|
273
|
+
WebVideoEngineErrorCode["RateUnsupported"] = "RATE_UNSUPPORTED";
|
|
274
|
+
})(WebVideoEngineErrorCode || (WebVideoEngineErrorCode = {}));
|
|
274
275
|
/**
|
|
275
|
-
* Thrown by createScrubCursor /
|
|
276
|
-
* or the source is unreadable. Branch on `error.code` (
|
|
276
|
+
* Thrown by createScrubCursor / WebVideoEngine.load when decode is unsupported
|
|
277
|
+
* or the source is unreadable. Branch on `error.code` (WebVideoEngineErrorCode)
|
|
277
278
|
* to differentiate decode failures from network failures.
|
|
278
279
|
*/
|
|
279
|
-
class
|
|
280
|
+
class WebVideoEngineError extends Error {
|
|
280
281
|
code;
|
|
281
282
|
cause;
|
|
282
283
|
constructor(code, message, cause) {
|
|
@@ -288,7 +289,7 @@ class VideoEngineError extends Error {
|
|
|
288
289
|
/** Shared by the facade and the core so a host gets the same refusal wherever
|
|
289
290
|
* its canvas is caught. */
|
|
290
291
|
function canvasBindingRefused() {
|
|
291
|
-
return new
|
|
292
|
+
return new WebVideoEngineError(WebVideoEngineErrorCode.PresentationMismatch, 'presentation "frames" leaves the canvas to the host: this engine paints nothing and hands out VideoFrames instead');
|
|
292
293
|
}
|
|
293
294
|
/**
|
|
294
295
|
* Validates a requested playback rate and returns it. The facade and the core
|
|
@@ -304,7 +305,7 @@ function resolvePlaybackRate(rate) {
|
|
|
304
305
|
if (!Number.isFinite(rate) ||
|
|
305
306
|
rate < PLAYBACK_RATE.MIN ||
|
|
306
307
|
rate > PLAYBACK_RATE.MAX) {
|
|
307
|
-
throw new
|
|
308
|
+
throw new WebVideoEngineError(WebVideoEngineErrorCode.RateUnsupported, `playback rate ${rate} is outside the supported forward range ${PLAYBACK_RATE.MIN}-${PLAYBACK_RATE.MAX}; reverse playback is not supported`);
|
|
308
309
|
}
|
|
309
310
|
return rate;
|
|
310
311
|
}
|
|
@@ -435,15 +436,55 @@ function oneEntryPerInstant(data) {
|
|
|
435
436
|
if (at === ticks.length)
|
|
436
437
|
return data;
|
|
437
438
|
const distinct = new Float64Array(ticks.length);
|
|
439
|
+
const distinctSource = data.sourceTicks
|
|
440
|
+
? new Float64Array(ticks.length)
|
|
441
|
+
: undefined;
|
|
438
442
|
distinct.set(ticks.subarray(0, at));
|
|
443
|
+
if (distinctSource)
|
|
444
|
+
distinctSource.set(data.sourceTicks.subarray(0, at));
|
|
439
445
|
let size = at;
|
|
440
446
|
for (let i = at + 1; i < ticks.length; i += 1) {
|
|
441
447
|
if (ticks[i] === distinct[size - 1])
|
|
442
448
|
continue;
|
|
443
449
|
distinct[size] = ticks[i];
|
|
450
|
+
if (distinctSource)
|
|
451
|
+
distinctSource[size] = data.sourceTicks[i];
|
|
444
452
|
size += 1;
|
|
445
453
|
}
|
|
446
|
-
return {
|
|
454
|
+
return {
|
|
455
|
+
...data,
|
|
456
|
+
ticks: distinct.slice(0, size),
|
|
457
|
+
...(distinctSource ? { sourceTicks: distinctSource.slice(0, size) } : {}),
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
function normalizePresentationOrigin(data) {
|
|
461
|
+
if (data.sourceTicks !== undefined || !(data.ticks[0] < 0))
|
|
462
|
+
return data;
|
|
463
|
+
let firstVisible = 0;
|
|
464
|
+
while (firstVisible < data.ticks.length) {
|
|
465
|
+
const end = firstVisible + 1 < data.ticks.length
|
|
466
|
+
? data.ticks[firstVisible + 1]
|
|
467
|
+
: data.ticks[firstVisible] + data.lastDurationTicks;
|
|
468
|
+
if (end > 0)
|
|
469
|
+
break;
|
|
470
|
+
firstVisible += 1;
|
|
471
|
+
}
|
|
472
|
+
if (firstVisible === data.ticks.length) {
|
|
473
|
+
throw new RangeError("FrameTimeline: a track containing only pre-roll has no presentation timeline");
|
|
474
|
+
}
|
|
475
|
+
const sourceTicks = data.ticks.slice(firstVisible);
|
|
476
|
+
const ticks = sourceTicks.slice();
|
|
477
|
+
if (ticks[0] < 0)
|
|
478
|
+
ticks[0] = 0;
|
|
479
|
+
const lastDurationTicks = ticks.length === 1 && sourceTicks[0] < 0
|
|
480
|
+
? data.lastDurationTicks + sourceTicks[0]
|
|
481
|
+
: data.lastDurationTicks;
|
|
482
|
+
return {
|
|
483
|
+
...data,
|
|
484
|
+
lastDurationTicks,
|
|
485
|
+
sourceTicks,
|
|
486
|
+
ticks,
|
|
487
|
+
};
|
|
447
488
|
}
|
|
448
489
|
/**
|
|
449
490
|
* Every real frame of one track, in presentation order, by its container tick
|
|
@@ -469,7 +510,7 @@ class FrameTimeline {
|
|
|
469
510
|
if (!(data.tickRate > 0)) {
|
|
470
511
|
throw new RangeError(`FrameTimeline: tick rate ${data.tickRate} is not positive`);
|
|
471
512
|
}
|
|
472
|
-
return new FrameTimeline(oneEntryPerInstant(data));
|
|
513
|
+
return new FrameTimeline(oneEntryPerInstant(normalizePresentationOrigin(data)));
|
|
473
514
|
}
|
|
474
515
|
/** A synthetic constant-rate table. Tests and fakes only. The default tick
|
|
475
516
|
* rate is a whole multiple of `fps`, so no test table needs rounding. */
|
|
@@ -493,6 +534,22 @@ class FrameTimeline {
|
|
|
493
534
|
timeAt(index) {
|
|
494
535
|
return asSec(this.ticksAt(index) / this.data.tickRate);
|
|
495
536
|
}
|
|
537
|
+
/** Timestamp passed to the decoder for the named presentation frame. */
|
|
538
|
+
sourceTimeAt(index) {
|
|
539
|
+
const at = this.clampIndex(index);
|
|
540
|
+
return asSec((this.data.sourceTicks?.[at] ?? this.ticksArray[at]) / this.data.tickRate);
|
|
541
|
+
}
|
|
542
|
+
/** Maps a public presentation time onto the container's source clock. */
|
|
543
|
+
toSourceTime(timeS) {
|
|
544
|
+
if (this.data.sourceTicks && timeS <= this.timeAt(0)) {
|
|
545
|
+
return this.sourceTimeAt(0);
|
|
546
|
+
}
|
|
547
|
+
return asSec(timeS);
|
|
548
|
+
}
|
|
549
|
+
/** Maps a decoded/container timestamp onto the public presentation clock. */
|
|
550
|
+
fromSourceTime(timeS) {
|
|
551
|
+
return asSec(this.data.sourceTicks ? Math.max(0, timeS) : timeS);
|
|
552
|
+
}
|
|
496
553
|
idAt(index) {
|
|
497
554
|
const at = this.clampIndex(index);
|
|
498
555
|
return { index: at, ticks: this.ticksArray[at] };
|
|
@@ -556,5 +613,4 @@ class FrameTimeline {
|
|
|
556
613
|
}
|
|
557
614
|
}
|
|
558
615
|
|
|
559
|
-
export { DIAGNOSTICS as D, FRAME_TIMELINE as F, HANG_RECOVERY as H, PlaybackStatus as P, SCRUB as S, TRACE_RING_BOUNDS as T,
|
|
560
|
-
//# sourceMappingURL=frame-timeline-GINI8Gum.js.map
|
|
616
|
+
export { DIAGNOSTICS as D, FRAME_TIMELINE as F, HANG_RECOVERY as H, PlaybackStatus as P, SCRUB as S, TRACE_RING_BOUNDS as T, WebVideoEngineError as W, WebVideoEngineErrorCode as a, asSec as b, SourceKind as c, FrameTimeline as d, asPaintSeq as e, canvasBindingRefused as f, resolvePlaybackRate as g, PLAYBACK_RATE as h, asFps as i, cappedResolution as j, displayBoxResolution as k, nativeResolution as n, resolveDecodeDimensions as r, viewportResolution as v };
|
|
@@ -22,6 +22,10 @@ export interface FrameTimelineData {
|
|
|
22
22
|
readonly tickRate: TickRate;
|
|
23
23
|
readonly ticks: Float64Array;
|
|
24
24
|
readonly lastDurationTicks: number;
|
|
25
|
+
/** Original source timestamps when presentation pre-roll was removed. The
|
|
26
|
+
* public `ticks` stay zero-based while decode requests retain the addresses
|
|
27
|
+
* needed to reach a frame straddling presentation time zero. */
|
|
28
|
+
readonly sourceTicks?: Float64Array;
|
|
25
29
|
}
|
|
26
30
|
/**
|
|
27
31
|
* Every real frame of one track, in presentation order, by its container tick
|
|
@@ -46,6 +50,12 @@ export declare class FrameTimeline {
|
|
|
46
50
|
toData(): FrameTimelineData;
|
|
47
51
|
ticksAt(index: number): number;
|
|
48
52
|
timeAt(index: number): Sec;
|
|
53
|
+
/** Timestamp passed to the decoder for the named presentation frame. */
|
|
54
|
+
sourceTimeAt(index: number): Sec;
|
|
55
|
+
/** Maps a public presentation time onto the container's source clock. */
|
|
56
|
+
toSourceTime(timeS: number): Sec;
|
|
57
|
+
/** Maps a decoded/container timestamp onto the public presentation clock. */
|
|
58
|
+
fromSourceTime(timeS: number): Sec;
|
|
49
59
|
idAt(index: number): FrameId;
|
|
50
60
|
landingAt(index: number): FrameLanding;
|
|
51
61
|
/** Ticks the frame at `index` ends at, which is where the next one starts. */
|
|
@@ -68,4 +78,3 @@ export declare class FrameTimeline {
|
|
|
68
78
|
indexOfDecoded(timeS: number): number;
|
|
69
79
|
private clampIndex;
|
|
70
80
|
}
|
|
71
|
-
//# sourceMappingURL=frame-timeline.d.ts.map
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* The web video engine, and the two adapters that hand what it decodes to a
|
|
3
|
+
* media renderer.
|
|
4
|
+
*
|
|
5
|
+
* The engine's own barrel is wider than this, because its modules export for
|
|
6
|
+
* one another. A name reaches an application only by being listed here, so
|
|
7
|
+
* listing one is a decision to support it. Worker message shapes, mediabunny
|
|
8
|
+
* pass-through configuration, and the React imperative handle stay inside.
|
|
9
|
+
*/
|
|
10
|
+
export { createWebVideoEngineMediaRendererSource, openWebVideoEngineMediaSource, type WebVideoEngineMediaSource, type WebVideoEngineMediaSourceOptions, } from "#media/video-engine-media-source";
|
|
11
|
+
export { DIAGNOSTICS, FrameTimeline, PLAYBACK_RATE, PlaybackStatus, SourceKind, TRACE_RING_BOUNDS, WebVideoEngine, WebVideoEngineError, WebVideoEngineErrorCode, cappedResolution, displayBoxResolution, nativeResolution, viewportResolution, } from "#web-video-engine";
|
|
12
|
+
export type { BlobVideoSource, DecodeResolutionStrategy, DiagnosticsSnapshot, DisplayBoxResolutionOptions, EngineChannel, EngineReadySnapshot, Fps, FrameId, FrameLanding, FrameQuality, FrameTimelineData, PaintSeq, PlaybackState, PresentationMode, PresentedFrame, PresentedFrameHandler, Rotation, Sec, SeekIntent, SeekTarget, SourceResidencyConfig, SourceResidencyDiagnostics, StreamVideoSource, TickRate, UrlVideoSource, VideoMetadata, VideoSource, ViewportResolutionOptions, Warning, WarningSeverity, WebVideoEngineOptions, } from "#web-video-engine";
|
|
3
13
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/web-video-engine/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/web-video-engine/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EACL,uCAAuC,EACvC,6BAA6B,EAC7B,KAAK,yBAAyB,EAC9B,KAAK,gCAAgC,GACtC,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EACL,WAAW,EACX,aAAa,EACb,aAAa,EACb,cAAc,EACd,UAAU,EACV,iBAAiB,EACjB,cAAc,EACd,mBAAmB,EACnB,uBAAuB,EACvB,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,eAAe,EACf,wBAAwB,EACxB,mBAAmB,EACnB,2BAA2B,EAC3B,aAAa,EACb,mBAAmB,EACnB,GAAG,EACH,OAAO,EACP,YAAY,EACZ,YAAY,EACZ,iBAAiB,EACjB,QAAQ,EACR,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,qBAAqB,EACrB,QAAQ,EACR,GAAG,EACH,UAAU,EACV,UAAU,EACV,qBAAqB,EACrB,0BAA0B,EAC1B,iBAAiB,EACjB,QAAQ,EACR,cAAc,EACd,aAAa,EACb,WAAW,EACX,yBAAyB,EACzB,OAAO,EACP,eAAe,EACf,qBAAqB,GACtB,MAAM,mBAAmB,CAAC"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export
|
|
2
|
-
export {
|
|
1
|
+
export { createWebVideoEngineMediaRendererSource, openWebVideoEngineMediaSource } from '../media/video-engine-media-source.js';
|
|
2
|
+
export { DIAGNOSTICS, FrameTimeline, PLAYBACK_RATE, PlaybackStatus, SourceKind, TRACE_RING_BOUNDS, WebVideoEngine, WebVideoEngineError, WebVideoEngineErrorCode, cappedResolution, displayBoxResolution, nativeResolution, viewportResolution } from './engine.js';
|
|
3
3
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A timeout whose budget advances only while its owner is visible. The owner
|
|
3
|
+
* still decides which work is eligible: this helper never pauses the work
|
|
4
|
+
* itself, nor any unrelated watchdog.
|
|
5
|
+
*/
|
|
6
|
+
export interface PausableDeadline {
|
|
7
|
+
cancel(): void;
|
|
8
|
+
pause(): void;
|
|
9
|
+
resume(): void;
|
|
10
|
+
}
|
|
11
|
+
export declare function createPausableDeadline(timeoutMs: number, onExpire: () => void): PausableDeadline;
|
|
@@ -32,4 +32,3 @@ export declare function drawRotated(context: CanvasRenderingContext2D | Offscree
|
|
|
32
32
|
* stretch-to-fill absorbs the aspect change for free.
|
|
33
33
|
*/
|
|
34
34
|
export declare function uvRotationMatrix(rotation: Rotation): readonly [number, number, number, number];
|
|
35
|
-
//# sourceMappingURL=rotation.d.ts.map
|
|
@@ -349,6 +349,8 @@ export declare class ScrubController {
|
|
|
349
349
|
* walk. Detaches the iterator and drops the read-ahead so paused ticks
|
|
350
350
|
* never paint a stale play frame. */
|
|
351
351
|
endPlay(): void;
|
|
352
|
+
holdOutput(): void;
|
|
353
|
+
releaseOutput(): void;
|
|
352
354
|
/**
|
|
353
355
|
* Cache lookup helper used by the engine on scrub. Asks the cursor for a
|
|
354
356
|
* cached frame near the target and, if it is far enough from what the canvas
|
|
@@ -356,12 +358,14 @@ export declare class ScrubController {
|
|
|
356
358
|
* calls cursor.seekTo to land the full-res frame; the cursor's emit listener
|
|
357
359
|
* stashes it for the next tick.
|
|
358
360
|
*
|
|
359
|
-
*
|
|
360
|
-
*
|
|
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.
|
|
361
|
+
* Nearby approximate hits respect cacheSkipNearMs. An exact hit for the
|
|
362
|
+
* requested frame can advance immediately, without waiting for a decode.
|
|
363
363
|
*/
|
|
364
364
|
tryPaintFromCache(timestampMs: number): boolean;
|
|
365
|
+
/** A new commit needs its own presentation even when its exact pixels were
|
|
366
|
+
* already shown by the preceding scrub. Approximate neighbors cannot answer it. */
|
|
367
|
+
presentExactFromCache(timestampMs: number): boolean;
|
|
368
|
+
private paintCached;
|
|
365
369
|
private start;
|
|
366
370
|
private runTick;
|
|
367
371
|
private paint;
|
|
@@ -373,4 +377,3 @@ export declare class ScrubController {
|
|
|
373
377
|
getRealtimeStats(): RealtimeStats;
|
|
374
378
|
private stop;
|
|
375
379
|
}
|
|
376
|
-
//# sourceMappingURL=scrub-controller.d.ts.map
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CreateScrubCursorOptions } from "./create-scrub-cursor";
|
|
2
|
+
import type { DecodeDimensions } from "./decode-resolution";
|
|
2
3
|
import type { FrameCacheStats } from "./frame-cache";
|
|
3
4
|
import type { FrameId, FrameTimeline } from "./frame-timeline";
|
|
4
5
|
import type { GopStats } from "./keyframe-index";
|
|
@@ -27,8 +28,9 @@ export interface ScrubFrameBase {
|
|
|
27
28
|
}
|
|
28
29
|
/**
|
|
29
30
|
* The structural slice of mediabunny's VideoSample the runtime touches: enough
|
|
30
|
-
* to draw it into a 2D canvas, hand its pixels to WebGPU
|
|
31
|
-
*
|
|
31
|
+
* to draw it into a 2D canvas, hand its pixels to WebGPU without an intermediate
|
|
32
|
+
* transfer copy where the selected path supports that, and release it. Kept as
|
|
33
|
+
* a slice rather than the concrete class so the runtime never
|
|
32
34
|
* imports mediabunny and stays fake-injectable under test.
|
|
33
35
|
*
|
|
34
36
|
* close() is the caller's obligation and is made idempotent at the cursor
|
|
@@ -44,6 +46,9 @@ export interface VideoSampleLike {
|
|
|
44
46
|
* whoever takes one owes it the turn named by `rotation` below.
|
|
45
47
|
*/
|
|
46
48
|
toVideoFrame(): VideoFrame;
|
|
49
|
+
/** The sample owns storage independent of a decoder output pool, so a host
|
|
50
|
+
* transfer may rewrap it without copying its pixels again. */
|
|
51
|
+
readonly independentPixels?: true;
|
|
47
52
|
/** The turn the pixels still need, already applied by draw() and dropped by
|
|
48
53
|
* toVideoFrame(). */
|
|
49
54
|
readonly rotation: Rotation;
|
|
@@ -58,9 +63,11 @@ export interface VideoSampleLike {
|
|
|
58
63
|
*
|
|
59
64
|
* A canvas frame carries a canvas and no close obligation: it is a cache blit
|
|
60
65
|
* or a CanvasSink decode. WebGPU uploads it with copyExternalImageToTexture,
|
|
61
|
-
* which accepts neither an SVG image nor a video element. A sample frame carries
|
|
62
|
-
*
|
|
63
|
-
*
|
|
66
|
+
* which accepts neither an SVG image nor a video element. A sample frame carries
|
|
67
|
+
* a live VideoSample that an eligible VideoSampleSink route can import directly
|
|
68
|
+
* into WebGPU. A DecodeSession route may first materialize independently owned
|
|
69
|
+
* pixels. Whoever stashes the sample owns its close, so only fresh decodes on
|
|
70
|
+
* the sample source produce one.
|
|
64
71
|
*/
|
|
65
72
|
export interface CanvasScrubFrame extends ScrubFrameBase {
|
|
66
73
|
readonly kind: "canvas";
|
|
@@ -270,13 +277,15 @@ export interface ScrubTrackInfo {
|
|
|
270
277
|
* frame as a keyframe result.
|
|
271
278
|
* - next is VFR-correct and a no-op while paused (no iterator attached),
|
|
272
279
|
* so it never advances media time across a paused canvas. The 1/fps step
|
|
273
|
-
* approximation lives in
|
|
280
|
+
* approximation lives in WebVideoEngine.step, not here.
|
|
274
281
|
* - isIdle is true only when no seek is draining and no pull is in flight.
|
|
275
282
|
* - subscribe replays the most recent frame to a new listener so the seed
|
|
276
283
|
* frame from open() is never dropped.
|
|
277
284
|
* - close is final; reusing a closed cursor is a programming error.
|
|
278
285
|
*/
|
|
279
286
|
export interface ScrubCursor {
|
|
287
|
+
/** Drains old output and changes frame/cache size without reopening decode. */
|
|
288
|
+
resizeOutput?(dimensions: DecodeDimensions): Promise<boolean>;
|
|
280
289
|
readonly state: ScrubCursorState;
|
|
281
290
|
readonly track: ScrubTrackInfo;
|
|
282
291
|
readonly isIdle: boolean;
|
|
@@ -339,4 +348,3 @@ export interface ScrubCursor {
|
|
|
339
348
|
close(): Promise<void>;
|
|
340
349
|
}
|
|
341
350
|
export type ScrubCursorFactory = (options: CreateScrubCursorOptions) => Promise<ScrubCursor>;
|
|
342
|
-
//# sourceMappingURL=scrub-cursor.d.ts.map
|
|
@@ -53,5 +53,39 @@ export interface SourceResidency {
|
|
|
53
53
|
* the network for less than half a mebibyte, so every read it makes banks
|
|
54
54
|
* at least one block. */
|
|
55
55
|
export declare const READ_BLOCK_BYTES: number;
|
|
56
|
+
/** How long a delivered chunk may sit unclaimed before the walk stops deferring
|
|
57
|
+
* to the read that produced it. It measures the gap between a chunk and the
|
|
58
|
+
* consumer's next pull, not the wait for the server, so a slow link reads as
|
|
59
|
+
* a live read while a reader that walked away frees the link. */
|
|
60
|
+
export declare const FOREGROUND_STALL_MS = 250;
|
|
61
|
+
/**
|
|
62
|
+
* Bytes held in one buffer per contiguous run, so a lookup is a single scan and
|
|
63
|
+
* a served range is a subarray with nothing copied. Insert is where copying
|
|
64
|
+
* happens: a run keeps spare capacity so an append that extends it writes into
|
|
65
|
+
* that room, and only a backward or overlapping insert re-materializes the run.
|
|
66
|
+
*/
|
|
67
|
+
export declare class ByteStore {
|
|
68
|
+
#private;
|
|
69
|
+
get residentBytes(): number;
|
|
70
|
+
/** Bytes retained by backing arrays, including append headroom. */
|
|
71
|
+
get allocatedBytes(): number;
|
|
72
|
+
ranges(): ResidentRange[];
|
|
73
|
+
/** The held run from `offset` to the end of its run, or null. */
|
|
74
|
+
runAt(offset: number): Uint8Array | null;
|
|
75
|
+
/** Where the gap containing `offset` ends, or null when nothing is held past it. */
|
|
76
|
+
nextHeldStart(offset: number): number | null;
|
|
77
|
+
insert(start: number, bytes: Uint8Array): void;
|
|
78
|
+
/**
|
|
79
|
+
* Brings held bytes under the budget: whole runs go first, furthest from
|
|
80
|
+
* `focus`, and a lone run that has outgrown the budget is narrowed to a
|
|
81
|
+
* `budgetBytes` window at `focus`.
|
|
82
|
+
*/
|
|
83
|
+
evictTo(budgetBytes: number, focus: number): void;
|
|
84
|
+
clear(): void;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Outstanding claims on the link, for this module's own tests: they drive every
|
|
88
|
+
* way a read can end and assert the count comes back to zero.
|
|
89
|
+
*/
|
|
90
|
+
export declare function outstandingForegroundHolds(residency: SourceResidency): number;
|
|
56
91
|
export declare function createSourceResidency(options: SourceResidencyOptions): SourceResidency;
|
|
57
|
-
//# sourceMappingURL=source-residency.d.ts.map
|