supervision 0.2.0-next.2 → 0.2.0-next.3

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.
@@ -27770,12 +27770,16 @@
27770
27770
  * lands on that frame and no other. Nothing here walks, compares or skips,
27771
27771
  * so a step across a frame boundary needs no epsilon.
27772
27772
  */
27773
- async seekToFrame(frame) {
27773
+ async seekToFrame(frame, isPresentationCurrent) {
27774
27774
  if (this.closed)
27775
27775
  return null;
27776
+ this.outputGeneration += 1;
27776
27777
  const outputGeneration = this.outputGeneration;
27777
27778
  const decoded = await this.trackOutputRead(this.provider.getFrame(this.trackInfo.timeline.timeAt(frame.index)));
27778
- if (this.closed || outputGeneration !== this.outputGeneration || !decoded) {
27779
+ if (this.closed ||
27780
+ outputGeneration !== this.outputGeneration ||
27781
+ isPresentationCurrent?.() === false ||
27782
+ !decoded) {
27779
27783
  if (decoded?.kind === "sample")
27780
27784
  decoded.sample.close();
27781
27785
  return null;
@@ -29194,14 +29198,18 @@
29194
29198
  * reuses whatever decode position the session already holds, with no
29195
29199
  * iterator opened per press.
29196
29200
  */
29197
- async seekToFrame(frame) {
29201
+ async seekToFrame(frame, isPresentationCurrent) {
29198
29202
  if (this.closed)
29199
29203
  return null;
29204
+ this.outputGeneration += 1;
29200
29205
  this.enterMode(AccessMode.Stepping);
29201
29206
  this.abandonPrefetch();
29202
29207
  const outputGeneration = this.outputGeneration;
29203
29208
  const decoded = await this.withDecodeWatchdog(this.provider.getFrame(this.trackInfo.timeline.timeAt(frame.index)));
29204
- if (this.closed || outputGeneration !== this.outputGeneration || !decoded) {
29209
+ if (this.closed ||
29210
+ outputGeneration !== this.outputGeneration ||
29211
+ isPresentationCurrent?.() === false ||
29212
+ !decoded) {
29205
29213
  if (decoded?.kind === "sample")
29206
29214
  decoded.sample.close();
29207
29215
  return null;
@@ -32650,6 +32658,7 @@ ${VERTEX_STAGE}
32650
32658
  * flight and publishes itself as the playhead. */
32651
32659
  awaitedSeek = null;
32652
32660
  seekGeneration = 0;
32661
+ stepCommandGeneration = 0;
32653
32662
  /** Wall stamp of a seek being served by re-anchoring the playback walk, or
32654
32663
  * null when no such seek is waiting on its crisp frame. */
32655
32664
  playSeekStartedAtMs = null;
@@ -32947,6 +32956,7 @@ ${VERTEX_STAGE}
32947
32956
  this.playing = true;
32948
32957
  return;
32949
32958
  }
32959
+ this.stepCommandGeneration += 1;
32950
32960
  // Resume-from-end: a play after the clock crossed duration would tick
32951
32961
  // straight to Ended. Snap back to 0 first.
32952
32962
  const durS = this.durationMs / 1000;
@@ -32994,6 +33004,7 @@ ${VERTEX_STAGE}
32994
33004
  });
32995
33005
  }
32996
33006
  }
33007
+ this.stepCommandGeneration += 1;
32997
33008
  this.controller?.endPlay();
32998
33009
  if (wasPlaying && !this.displayResize)
32999
33010
  this.abandonAwaitedSeek();
@@ -33247,9 +33258,14 @@ ${VERTEX_STAGE}
33247
33258
  const target = timeline.landingAt(base.index + direction);
33248
33259
  if (target.frame.index === base.index)
33249
33260
  return null;
33250
- this.beginPresentationGeneration();
33251
- const next = await this.cursor.seekToFrame(target.frame);
33252
- if (!next)
33261
+ this.abandonAwaitedSeek();
33262
+ const commandGeneration = ++this.stepCommandGeneration;
33263
+ const generation = this.beginPresentationGeneration();
33264
+ const next = await this.cursor.seekToFrame(target.frame, () => this.isCurrentSeek(generation) &&
33265
+ commandGeneration === this.stepCommandGeneration);
33266
+ if (!next ||
33267
+ !this.isCurrentSeek(generation) ||
33268
+ commandGeneration !== this.stepCommandGeneration)
33253
33269
  return null;
33254
33270
  this.lastStepLanded = target.frame;
33255
33271
  this.clock.seek(target.mediaTimeS);
@@ -301,12 +301,10 @@ export interface ScrubCursor {
301
301
  /** Detach the forward-playback iterator. */
302
302
  detachPlay(): void;
303
303
  /**
304
- * Decode the named frame of the source and emit it through the listener
305
- * chain. Returns the emitted ScrubFrame, or null at a boundary or once
306
- * closed. Steps are index arithmetic on the frame table, so a caller names
307
- * the frame it wants and not a time near it.
304
+ * Pending output is released without listener delivery when
305
+ * isPresentationCurrent returns false after decode.
308
306
  */
309
- seekToFrame(frame: FrameId): Promise<ScrubFrame | null>;
307
+ seekToFrame(frame: FrameId, isPresentationCurrent?: () => boolean): Promise<ScrubFrame | null>;
310
308
  idle(): Promise<void>;
311
309
  /**
312
310
  * Resolves at the seek drain's next settle: whichever target it is servicing
@@ -133,6 +133,8 @@ export declare class WebVideoEngine {
133
133
  private timeline;
134
134
  private transferredCanvas;
135
135
  private presentedFrameHandler;
136
+ private navigationIntent;
137
+ private stepIntent;
136
138
  /** Deliveries counted toward the one frame-ownership check, frozen past it,
137
139
  * and the frame that check reads. Weak, so watching costs the frame no
138
140
  * lifetime: a host that closes and drops it leaves nothing to find, which is
@@ -226,6 +228,8 @@ export declare class WebVideoEngine {
226
228
  */
227
229
  step: (direction: 1 | -1) => Promise<void>;
228
230
  private runStep;
231
+ private beginNavigationIntent;
232
+ private beginStepIntent;
229
233
  /**
230
234
  * Settled iff the engine is between operations. Derived from mirror state
231
235
  * rather than the cursor (which lives in the worker): Idle/Loading read as
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "supervision",
3
- "version": "0.2.0-next.2",
3
+ "version": "0.2.0-next.3",
4
4
  "description": "Browser-native computer vision media rendering and annotation engine.",
5
5
  "repository": {
6
6
  "type": "git",