Skip to content

Frame timeseries

Per-frame trajectory data — the position, size, and confidence of every tracked object in every frame of a video — lives in two places, with one designated as the source of truth.

The msgpack source of truth

Classification.frames_msgpack is a zstd-compressed msgpack file on disk, served to clients via ClassificationFramesView (GET /api/media-classifications/classifications/<id>/frames/). It is written directly by the AI pipeline's post-processing step and is never derived from anything else — if it disagrees with the hypertable, the msgpack wins.

See Msgpack detection-blob contract for the wire format.

The hypertable queryable index

ObjectFrameObservation is a TimescaleDB hypertable built from the msgpack — a queryable index, populated per project via populate_project_hypertable. It exists purely for query performance (fast per-frame queries across millions of objects); it holds no information the msgpack doesn't already have.

The TimescaleDB extension itself is mandatory — ObjectFrameObservation is created unconditionally by migration, there's no setting to skip it. What is on-demand is each project's snapshot: it starts empty and has to be explicitly populated (and re-populated after any msgpack change) rather than staying automatically in sync — see Frame hypertable for the population command.

Why this split

Keeping the msgpack as the single source of truth means:

  • The hypertable can be (re)built at any time from the msgpack files, without re-running the AI pipeline.
  • Clients that only need "give me the trajectory for this classification" (export, playback) don't need a database round-trip at all — they read the msgpack directly.