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,450 @@
1
+ import { MediaErrorKind } from 'supervision-js-core';
2
+
3
+ /**
4
+ * The kind each coded refusal already stands for. Reading the code beats
5
+ * re-deriving the kind from the message: the text of a container refusal says
6
+ * "demuxer", the text of a wedged worker says "timed out", and the patterns
7
+ * below would file both under the wrong kind. Written as a total record, so a
8
+ * code added to the vocabulary above fails the build until it has a kind.
9
+ */
10
+ const PRODUCER_CODE_KINDS = {
11
+ ABORTED: MediaErrorKind.Unknown,
12
+ BACKEND_CRASHED: MediaErrorKind.Decode,
13
+ CONTAINER_UNREADABLE: MediaErrorKind.Unreadable,
14
+ DECODER_STALLED: MediaErrorKind.Decode,
15
+ DECODE_UNSUPPORTED: MediaErrorKind.UnsupportedFormat,
16
+ NO_VIDEO_TRACK: MediaErrorKind.NoVideoTrack,
17
+ PRESENTATION_MISMATCH: MediaErrorKind.Unknown,
18
+ RATE_UNSUPPORTED: MediaErrorKind.Unknown,
19
+ SOURCE_UNREADABLE: MediaErrorKind.Unreadable,
20
+ VIDEO_TRACK_UNREADABLE: MediaErrorKind.UnsupportedFormat,
21
+ };
22
+ const UNSUPPORTED_FORMAT_PATTERN = /unsupported|not supported|no (?:matching )?(?:decoder|codec)|codec/i;
23
+ const DECODE_PATTERN = /decod|demux|corrupt|malformed|bitstream/i;
24
+ const NETWORK_PATTERN = /network|fetch|http|failed to load|load failed|timed? ?out|abort/i;
25
+ /**
26
+ * A media failure with a stable, documented kind.
27
+ *
28
+ * Branch on `kind` instead of matching decoder, demuxer, or container message
29
+ * text. `message` stays diagnostic and may name vendor internals; applications
30
+ * own their user-facing copy. The originating failure is preserved on `cause`.
31
+ */
32
+ class MediaSourceError extends Error {
33
+ kind;
34
+ constructor(kind, message, options) {
35
+ super(message, options);
36
+ this.name = "MediaSourceError";
37
+ this.kind = kind;
38
+ }
39
+ }
40
+ function isMediaSourceError(value) {
41
+ return value instanceof MediaSourceError;
42
+ }
43
+ /**
44
+ * Classifies an arbitrary media failure into a `MediaSourceError`.
45
+ *
46
+ * Already-classified errors pass through so a kind chosen at the point of
47
+ * failure is never downgraded by a broader message match. Anything the
48
+ * heuristics cannot place stays representable as `Unknown` rather than being
49
+ * forced into a wrong kind.
50
+ */
51
+ function toMediaSourceError(error, fallbackMessage = "Media source failed.") {
52
+ if (isMediaSourceError(error)) {
53
+ return error;
54
+ }
55
+ const message = error instanceof Error ? error.message : fallbackMessage;
56
+ const kind = producerCodeKind(error) ?? classifyMediaErrorMessage(message);
57
+ return new MediaSourceError(kind, message, { cause: error });
58
+ }
59
+ /**
60
+ * Failure kind of any caught media failure.
61
+ *
62
+ * A `MediaSourceError` reports the kind chosen where it failed. Anything else
63
+ * is classified from its message, and stays `Unknown` when no kind fits.
64
+ */
65
+ function getMediaErrorKind(error) {
66
+ return toMediaSourceError(error).kind;
67
+ }
68
+ function producerCodeKind(error) {
69
+ const code = error?.code;
70
+ return typeof code === "string" && code in PRODUCER_CODE_KINDS
71
+ ? PRODUCER_CODE_KINDS[code]
72
+ : null;
73
+ }
74
+ function classifyMediaErrorMessage(message) {
75
+ if (NETWORK_PATTERN.test(message)) {
76
+ return MediaErrorKind.Network;
77
+ }
78
+ if (UNSUPPORTED_FORMAT_PATTERN.test(message)) {
79
+ return MediaErrorKind.UnsupportedFormat;
80
+ }
81
+ if (DECODE_PATTERN.test(message)) {
82
+ return MediaErrorKind.Decode;
83
+ }
84
+ return MediaErrorKind.Unknown;
85
+ }
86
+
87
+ const DEFAULT_MAX_DEVICE_PIXEL_RATIO = 2;
88
+ /**
89
+ * The pixel ratio a host's display box rasterizes at, for every grid that lands
90
+ * in that box: the presentation surface, the mask rasters drawn onto it, and the
91
+ * decode under both. The ceiling is what keeps a 3x display from costing nine
92
+ * times the texels of a 1x one for sharpness nobody resolves on a moving
93
+ * picture. An id raster carries a detection per pixel and can only be sampled
94
+ * nearest, so a grid it does not share ragged its edges.
95
+ *
96
+ * A ceiling that is not a usable number states nothing, and takes the default.
97
+ */
98
+ function resolveDisplayPixelRatio(display) {
99
+ const { devicePixelRatio, maxDevicePixelRatio } = display;
100
+ if (!Number.isFinite(devicePixelRatio) || devicePixelRatio <= 0) {
101
+ return 1;
102
+ }
103
+ const ceiling = maxDevicePixelRatio !== undefined &&
104
+ Number.isFinite(maxDevicePixelRatio) &&
105
+ maxDevicePixelRatio > 0
106
+ ? maxDevicePixelRatio
107
+ : DEFAULT_MAX_DEVICE_PIXEL_RATIO;
108
+ return Math.min(devicePixelRatio, ceiling);
109
+ }
110
+
111
+ const VIDEO_ENGINE_ENTRY = "supervision/web-video-engine";
112
+ const VIDEO_ENGINE_ANALYSIS_ENTRY = `${VIDEO_ENGINE_ENTRY}/analysis`;
113
+ /**
114
+ * A bundler renames the engine chunk after the module it was split from, and a
115
+ * browser reports the failing chunk's URL rather than the specifier that asked
116
+ * for it, so the name a failure can be recognised by is the module's, not the
117
+ * entry's.
118
+ */
119
+ const VIDEO_ENGINE_MODULE = "web-video-engine";
120
+ const MISSING_MODULE_ERROR_CODES = new Set([
121
+ "ERR_MODULE_NOT_FOUND",
122
+ "MODULE_NOT_FOUND",
123
+ ]);
124
+ const MISSING_MODULE_MESSAGE = /cannot find (?:module|package)|failed to (?:resolve|fetch dynamically imported) module|could not resolve/i;
125
+ const QUOTED_SPECIFIER = /['"]([^'"]+)['"]/;
126
+ const MAX_WRAPPED_ERROR_DEPTH = 8;
127
+ /**
128
+ * The engine is a chunk of this package that the browser fetches on demand, so
129
+ * the raw failure names a URL nobody wrote and reads like a bug in the caller's
130
+ * own code.
131
+ */
132
+ function rethrowEngineImportFailure(error, entry) {
133
+ if (isEngineResolutionFailure(error)) {
134
+ throw new Error(`openWebVideoEngineMediaSource needs "${entry}", which did not load. ` +
135
+ "The web video engine is a lazily loaded chunk of supervision, so check " +
136
+ "that the deployed build still serves every chunk it emitted.", { cause: error });
137
+ }
138
+ throw error;
139
+ }
140
+ /**
141
+ * An engine that never loaded and an engine that loaded and then threw arrive
142
+ * at the same catch, and only the first is a deployment problem. Loaders that
143
+ * wrap what they caught put the load failure under the error they raise, so the
144
+ * whole cause chain is read, bounded because a chain can be cyclic.
145
+ */
146
+ function isEngineResolutionFailure(error) {
147
+ let cursor = error;
148
+ for (let depth = 0; depth <= MAX_WRAPPED_ERROR_DEPTH; depth += 1) {
149
+ if (!(cursor instanceof Error))
150
+ return false;
151
+ if (namesUnloadableEngine(cursor))
152
+ return true;
153
+ cursor = cursor.cause;
154
+ }
155
+ return false;
156
+ }
157
+ /**
158
+ * Node and bundlers quote the specifier they failed to resolve, so a dependency
159
+ * missing from an engine that did load is told apart by whose name is quoted; a
160
+ * browser reports an unquoted URL, which carries the chunk name too.
161
+ *
162
+ * Each bundler words this differently and one of them stubs the import with an
163
+ * error of its own, so the wording is matched as well as the code. A build that
164
+ * names the engine first and its importer second is the engine failing to load;
165
+ * one that names a dependency first is that dependency's problem, and reading
166
+ * only the first quoted specifier keeps the two apart.
167
+ */
168
+ function namesUnloadableEngine(error) {
169
+ const code = "code" in error ? String(error.code) : "";
170
+ if (!MISSING_MODULE_ERROR_CODES.has(code) &&
171
+ !MISSING_MODULE_MESSAGE.test(error.message)) {
172
+ return false;
173
+ }
174
+ const quoted = QUOTED_SPECIFIER.exec(error.message)?.[1];
175
+ return (quoted ?? error.message).includes(VIDEO_ENGINE_MODULE);
176
+ }
177
+
178
+ const MILLISECONDS_PER_SECOND = 1000;
179
+ const DEFAULT_FRAME_RATE = 30;
180
+ const TIMESTAMP_EPSILON_SECONDS = 1e-6;
181
+ const FRAMES_PRESENTATION_PREVIEW_MAX_WIDTH_PX = 320;
182
+ /**
183
+ * Adapts the web video engine to the decoded-media source seam.
184
+ *
185
+ * The pull path, `sampleSink`, serves one-off reads such as thumbnails and
186
+ * single frame grabs, decoding each request from scratch through the engine's
187
+ * batch analysis entry. The push path serves playback and scrub presentation:
188
+ * the engine holds no canvas, paints nothing, and announces every frame that
189
+ * earns the screen, so a compositor subscribes to `engine` and never pulls
190
+ * samples here.
191
+ */
192
+ async function openWebVideoEngineMediaSource(options) {
193
+ if ("stream" in options.source) {
194
+ throw new MediaSourceError(MediaErrorKind.Unreadable, "This media source decodes playback and one-off frame grabs from two readers of the video, so it needs one that opens twice: a URL or a Blob. A ReadableStream yields its bytes once.");
195
+ }
196
+ let engine;
197
+ let retainedFrames;
198
+ try {
199
+ const { WebVideoEngine, displayBoxResolution } = await importEngineEntry();
200
+ const { display, frameDecodeStrategy, ...engineOptions } = options;
201
+ engine = new WebVideoEngine({
202
+ decodeStrategy: display ? displayBoxResolution(display) : undefined,
203
+ previewWidth: framesPreviewWidth(display),
204
+ ...engineOptions,
205
+ presentation: "frames",
206
+ });
207
+ const openedEngine = engine;
208
+ // The engine can present its seed before open() returns and before the
209
+ // renderer can register. Retain only the newest frame across that gap.
210
+ retainedFrames = retainFramesUntilSubscribed(openedEngine);
211
+ const snapshot = await openedEngine.load();
212
+ const frames = createAnalysisFrameReader({
213
+ decodeStrategy: frameDecodeStrategy,
214
+ frameDuration: resolveFrameDuration(snapshot.nativeFps),
215
+ source: options.source,
216
+ });
217
+ return {
218
+ engine: openedEngine,
219
+ input: {
220
+ dispose() {
221
+ retainedFrames?.dispose();
222
+ void frames.close();
223
+ void openedEngine.dispose();
224
+ },
225
+ },
226
+ metadata: createMetadata(snapshot),
227
+ sampleSink: frames.sampleSink,
228
+ };
229
+ }
230
+ catch (error) {
231
+ retainedFrames?.dispose();
232
+ await engine?.dispose();
233
+ throw toWebVideoEngineMediaSourceError(error);
234
+ }
235
+ }
236
+ function retainFramesUntilSubscribed(engine) {
237
+ const registerUpstream = engine.onPresentedFrame.bind(engine);
238
+ let downstream = null;
239
+ let pending = null;
240
+ let disposed = false;
241
+ registerUpstream((presented) => {
242
+ if (disposed) {
243
+ presented.frame.close();
244
+ return;
245
+ }
246
+ if (downstream) {
247
+ downstream(presented);
248
+ return;
249
+ }
250
+ pending?.frame.close();
251
+ pending = presented;
252
+ });
253
+ engine.onPresentedFrame = (handler) => {
254
+ downstream = handler;
255
+ const retained = pending;
256
+ pending = null;
257
+ if (retained)
258
+ handler(retained);
259
+ };
260
+ return {
261
+ dispose() {
262
+ if (disposed)
263
+ return;
264
+ disposed = true;
265
+ pending?.frame.close();
266
+ pending = null;
267
+ downstream = (presented) => presented.frame.close();
268
+ },
269
+ };
270
+ }
271
+ function toWebVideoEngineMediaSourceError(error) {
272
+ if (error instanceof DOMException &&
273
+ (error.name === "SecurityError" || error.name === "NotSupportedError")) {
274
+ return new MediaSourceError(MediaErrorKind.EnvironmentUnsupported, "The browser environment could not start the web video engine worker.", { cause: error });
275
+ }
276
+ return toMediaSourceError(error, "Unable to open this video source.");
277
+ }
278
+ function createWebVideoEngineMediaRendererSource(options) {
279
+ return {
280
+ open() {
281
+ return openWebVideoEngineMediaSource(options);
282
+ },
283
+ };
284
+ }
285
+ /**
286
+ * The engine ships inside this package, and arrives through a dynamic import so
287
+ * that it lands in its own chunk: a consumer who only annotates images never
288
+ * downloads the engine's embedded decode worker. A static import would fold it
289
+ * into the main entry.
290
+ */
291
+ async function importEngineEntry() {
292
+ try {
293
+ return await import('./web-video-engine/engine.js');
294
+ }
295
+ catch (error) {
296
+ rethrowEngineImportFailure(error, VIDEO_ENGINE_ENTRY);
297
+ }
298
+ }
299
+ async function importAnalysisEntry() {
300
+ try {
301
+ return await import('./web-video-engine/analysis.js');
302
+ }
303
+ catch (error) {
304
+ rethrowEngineImportFailure(error, VIDEO_ENGINE_ANALYSIS_ENTRY);
305
+ }
306
+ }
307
+ /**
308
+ * A wider coarse frame means fewer of them resident, and residency is what a
309
+ * drag spends: a scrub position holding no coarse frame paints nothing until a
310
+ * full decode returns. A stated box only ever lowers the width, since a preview
311
+ * wider than the picture it stands in for buys no sharpness and costs resident
312
+ * frames.
313
+ */
314
+ function framesPreviewWidth(display) {
315
+ if (display === undefined || !(display.boxWidth > 0)) {
316
+ return FRAMES_PRESENTATION_PREVIEW_MAX_WIDTH_PX;
317
+ }
318
+ return Math.min(FRAMES_PRESENTATION_PREVIEW_MAX_WIDTH_PX, Math.ceil(display.boxWidth * resolveDisplayPixelRatio(display)));
319
+ }
320
+ function createAnalysisFrameReader(options) {
321
+ let sessionPromise;
322
+ let closed = false;
323
+ const openSession = () => {
324
+ sessionPromise ??= (async () => {
325
+ try {
326
+ const { AnalysisSession } = await importAnalysisEntry();
327
+ return await AnalysisSession.open({
328
+ decodeStrategy: options.decodeStrategy,
329
+ source: options.source,
330
+ });
331
+ }
332
+ catch (error) {
333
+ throw toMediaSourceError(error, "Unable to open video frame analysis.");
334
+ }
335
+ })();
336
+ return sessionPromise;
337
+ };
338
+ const extractAt = async (timestamp) => {
339
+ if (closed)
340
+ return null;
341
+ try {
342
+ const session = await openSession();
343
+ const [frame] = await session.extractFrames([timestamp]);
344
+ return frame ?? null;
345
+ }
346
+ catch (error) {
347
+ throw toMediaSourceError(error, "Unable to decode this video frame.");
348
+ }
349
+ };
350
+ const sampleSink = {
351
+ async getSample(timestamp) {
352
+ const frame = await extractAt(timestamp);
353
+ return frame ? createSample(frame, options.frameDuration) : null;
354
+ },
355
+ async *samples(startTimestamp = 0, endTimestamp = Number.POSITIVE_INFINITY) {
356
+ let cursor = startTimestamp;
357
+ let lastTimestamp = Number.NEGATIVE_INFINITY;
358
+ while (cursor <= endTimestamp) {
359
+ const frame = await extractAt(cursor);
360
+ if (!frame)
361
+ return;
362
+ // The analysis entry answers with the frame on screen at the requested
363
+ // timestamp, so a request past the last frame answers with that frame
364
+ // again. A timestamp that does not advance is the end of the track.
365
+ if (frame.timestampS <= lastTimestamp + TIMESTAMP_EPSILON_SECONDS) {
366
+ return;
367
+ }
368
+ lastTimestamp = frame.timestampS;
369
+ cursor = Math.max(cursor, frame.timestampS) + options.frameDuration;
370
+ yield createSample(frame, options.frameDuration);
371
+ }
372
+ },
373
+ async *samplesAtTimestamps(timestamps) {
374
+ if (closed)
375
+ return;
376
+ try {
377
+ const session = await openSession();
378
+ for await (const frame of session.framesAtTimestamps([...timestamps])) {
379
+ yield frame ? createSample(frame, options.frameDuration) : null;
380
+ }
381
+ }
382
+ catch (error) {
383
+ throw toMediaSourceError(error, "Unable to decode these video frames.");
384
+ }
385
+ },
386
+ };
387
+ const close = async () => {
388
+ closed = true;
389
+ const opening = sessionPromise;
390
+ sessionPromise = undefined;
391
+ if (!opening)
392
+ return;
393
+ try {
394
+ const session = await opening;
395
+ await session.close();
396
+ }
397
+ catch {
398
+ // A session that failed to open already rejected the pull that opened it.
399
+ }
400
+ };
401
+ return { close, sampleSink };
402
+ }
403
+ function createSample(frame, duration) {
404
+ let closed = false;
405
+ return {
406
+ close() {
407
+ closed = true;
408
+ },
409
+ draw(context, dx, dy, dWidth = frame.width, dHeight = frame.height) {
410
+ if (closed)
411
+ throw new Error("Cannot draw a closed web video engine frame.");
412
+ context.drawImage(frame.canvas, dx, dy, dWidth, dHeight);
413
+ },
414
+ duration,
415
+ timestamp: frame.timestampS,
416
+ };
417
+ }
418
+ function createMetadata(snapshot) {
419
+ const duration = Number.isFinite(snapshot.durationMs)
420
+ ? snapshot.durationMs / MILLISECONDS_PER_SECOND
421
+ : null;
422
+ const estimatedFrameRate = snapshot.nativeFps !== null && snapshot.nativeFps > 0
423
+ ? snapshot.nativeFps
424
+ : null;
425
+ return {
426
+ audioTrackCount: 0,
427
+ canRead: snapshot.canDecode,
428
+ duration,
429
+ estimatedFrameCount: duration !== null && estimatedFrameRate !== null
430
+ ? Math.max(1, Math.round(duration * estimatedFrameRate))
431
+ : null,
432
+ estimatedFrameRate,
433
+ firstTimestamp: snapshot.firstTimestampMs / MILLISECONDS_PER_SECOND,
434
+ formatMimeType: null,
435
+ formatName: "video-engine",
436
+ mimeType: null,
437
+ primaryVideoHeight: snapshot.naturalHeight,
438
+ primaryVideoWidth: snapshot.naturalWidth,
439
+ trackCount: 1,
440
+ videoTrackCount: 1,
441
+ };
442
+ }
443
+ function resolveFrameDuration(nativeFps) {
444
+ return nativeFps !== null && nativeFps > 0
445
+ ? 1 / nativeFps
446
+ : 1 / DEFAULT_FRAME_RATE;
447
+ }
448
+
449
+ export { MediaSourceError as M, createWebVideoEngineMediaRendererSource as c, getMediaErrorKind as g, isMediaSourceError as i, openWebVideoEngineMediaSource as o, resolveDisplayPixelRatio as r, toMediaSourceError as t };
450
+ //# sourceMappingURL=video-engine-media-source-CUXnOJOV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"video-engine-media-source-CUXnOJOV.js","sources":["../src/media/media-errors.ts","../src/media/display-pixel-ratio.ts","../src/media/engine-import-failure.ts","../src/media/video-engine-media-source.ts"],"sourcesContent":[null,null,null,null],"names":[],"mappings":"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"}
@@ -0,0 +1,75 @@
1
+ import { type DecodeSourceHandle } from "./decode-source";
2
+ import type { DecodeResolutionStrategy } from "./decode-resolution";
3
+ import type { VideoSource } from "./types";
4
+ /**
5
+ * Playback-independent analysis over a video source: metadata, keyframe
6
+ * discovery, and frame extraction at arbitrary timestamps. It rides the same
7
+ * opened decode source as the playback cursor but spins no worker, binds no
8
+ * canvas, and runs no clock, so a consumer can pull thumbnails or build a
9
+ * contact sheet without standing up a player.
10
+ *
11
+ * Extracted frames are copied into their own canvases before the next decode,
12
+ * because the underlying sink recycles a small pool round-robin; the copy is
13
+ * what makes a returned frame safe to hold.
14
+ */
15
+ export interface AnalysisOptions {
16
+ source: VideoSource;
17
+ /**
18
+ * Output frame resolution: it sizes the decode sink, so frames decode (and
19
+ * paint, and copy) at this width with height following native aspect. Native
20
+ * when omitted; a capped strategy makes a thumbnail pass cheaper end to end
21
+ * rather than decoding native and scaling down afterward.
22
+ */
23
+ decodeStrategy?: DecodeResolutionStrategy;
24
+ poolSize?: number;
25
+ }
26
+ export interface AnalysisMetadata {
27
+ readonly durationS: number;
28
+ readonly width: number;
29
+ readonly height: number;
30
+ /** Resolution extracted frames are sized to, after the decode strategy. */
31
+ readonly frameWidth: number;
32
+ readonly frameHeight: number;
33
+ readonly nativeFps: number | null;
34
+ }
35
+ export interface ExtractedFrame {
36
+ readonly timestampS: number;
37
+ readonly canvas: OffscreenCanvas;
38
+ readonly width: number;
39
+ readonly height: number;
40
+ }
41
+ export declare class AnalysisSession {
42
+ private readonly sink;
43
+ private readonly keyframeIndex;
44
+ private readonly track;
45
+ private readonly disposeSource;
46
+ private closed;
47
+ constructor(source: DecodeSourceHandle);
48
+ /** Opens a source for analysis. The returned session owns the source. */
49
+ static open(options: AnalysisOptions): Promise<AnalysisSession>;
50
+ get metadata(): AnalysisMetadata;
51
+ /**
52
+ * Keyframe timestamps (seconds) whose GOP overlaps the range, resolved
53
+ * lazily through the container. Useful for a contact sheet that lands on
54
+ * real I-frames, which decode without a GOP walk.
55
+ */
56
+ keyframeTimestamps(startS?: number, endS?: number): Promise<readonly number[]>;
57
+ /**
58
+ * Decodes a frame for each requested timestamp and returns a stable copy of
59
+ * each. Timestamps are sorted so the sink decodes each packet at most once;
60
+ * a timestamp with no frame is skipped rather than yielding a gap.
61
+ */
62
+ extractFrames(timestampsS: readonly number[]): Promise<ExtractedFrame[]>;
63
+ /**
64
+ * One frame per requested timestamp, in the order asked for, `null` where no
65
+ * frame covers it, so a caller pairing frames with its own indices keeps the
66
+ * gaps attributable. Timestamps that climb decode in a single pass over the
67
+ * track: one seek and GOP walk for the whole set.
68
+ *
69
+ * A consumer that finishes with each frame before pulling the next holds one
70
+ * frame of memory; {@link extractFrames} holds the whole set.
71
+ */
72
+ framesAtTimestamps(timestampsS: readonly number[]): AsyncGenerator<ExtractedFrame | null, void, unknown>;
73
+ close(): Promise<void>;
74
+ private copyFrame;
75
+ }
@@ -0,0 +1,6 @@
1
+ export { AnalysisSession } from "./analysis-session";
2
+ export type { AnalysisMetadata, AnalysisOptions, ExtractedFrame, } from "./analysis-session";
3
+ export { FrameExtractor } from "./frame-extractor";
4
+ export { FrameWalker, walkFrames } from "./frame-walker";
5
+ export type { FrameWalkMetadata, FrameWalkRange, WalkedFrame, } from "./frame-walker";
6
+ export type { WalkFrameSource } from "./decode-source";