# OpenTrackIO

> How OWG records camera and lens tracking for a take as a governed asset, while the live stream stays outside the graph.

**Status:** buildable on v0.92 at asset level. One gap: the schema's `timerange` field is documented for TAMS syntax only, so a take's timecode range goes in an `x-` metadata key for now.

## What OpenTrackIO is

OpenTrackIO is a free, open protocol from the SMPTE RIS-OSVP (On-Set Virtual Production) group for streaming camera tracking, lens and metadata from a producer, such as a tracker or a camera, to a consumer, such as a render engine. The published specification is [v1.0.1](https://ris-pub.smpte.org/ris-osvp-metadata-camdkit/).

- **Transport:** IPv4 UDP, with multicast recommended. Payloads are JSON or CBOR.
- **Each sample** carries identifiers (`sampleId`, `sourceId`, `sourceNumber`), timing (`timecode`, `sampleRate`, PTP timestamps, `sequenceNumber`), `transforms` (translation in meters, rotation in degrees) and `lens` data (`pinholeFocalLength`, `focusDistance`, `fStop`, `distortion`, `encoders`).
- **Static data** describes the camera, lens and tracker, including calibration history.
- **Timing** can be locked by genlock, PTP or NTP.

Vendors are adopting it. Unreal Engine has supported it since 5.6, and [trade coverage](https://www.redsharknews.com/sony-firmware-venice2-burano-fx6-fr7-2026) reports Sony's FR7 camera sending it from firmware 4.0.

## What belongs in the graph

A tracker emits tens of samples per second per stream. A graph that stored them would be a time-series database with the wrong query model. The graph holds the description of the take instead:

| OpenTrackIO | OWG |
|---|---|
| Camera, lens and tracker hardware | `infrastructure` entries |
| The multicast network the samples travel on | `infrastructure`, with the timing spec in `spec` |
| A recording of a take's samples | an `asset` (type `data.tracking`) with a storage locator |
| The producer's `sourceId` | an `identifiers[]` entry, scope `opentrackio.source` |
| Recording the stream | a task with a recorder as its executor |
| Checking the recording | a `qc` task with named `checks` |
| Rendering against the recording | a task that `used` the log and a scene asset |

```json
{
  "id": "tracking_log_t4",
  "type": "data.tracking",
  "content_type": "application/json",
  "produced_by": "record_tracking",
  "identifiers": [
    { "scope": "opentrackio.source", "id": "urn:uuid:3e8f1c52-9a47-4b0d-8c6e-2d7a5f1b9e04" }
  ],
  "storage": { "provider": "s3", "locator": "s3://stage/scene12/take4/tracking.jsonl", "zone": "us-west-2" },
  "metadata": {
    "x-opentrackio": {
      "protocol": "OpenTrackIO", "version": "1.0.1", "encoding": "json",
      "sample_rate": "24/1",
      "timecode_in": "14:32:10:00", "timecode_out": "14:33:02:12",
      "samples": 1260
    }
  }
}
```

## Reference workflow

[`opentrackio-camera-take.owg.json`](/corpus/opentrackio-camera-take.owg.json) — a stage records the tracking stream for a take, QC checks it, a supervisor approves it, and a render task uses it against a [USD](/standards-bindings#openusd-composition-arcs-become-typed-edges) stage to produce the background.

```bash
curl -O https://openworkflowgraph.org/corpus/opentrackio-camera-take.owg.json
owg-validate opentrackio-camera-take.owg.json --json
```

**What to take from it:**

- The live UDP stream never enters the graph. Only the recording does.
- The lineage runs camera move, then log, then approved log, then render. The render task can be traced to the exact recording it used.
- The approval step is what turns a raw recording into something a downstream task may consume.

## What stays in OpenTrackIO

OWG does not read samples, resolve the lens model, or convert timecode. Interpretation of the data stays with the consumer.

The specification does not address authentication or signing of the stream. A recording in a graph gets assurance from the graph's own rules: `asserted` by the recorder and the approver by default, and `attested` only where a device or signer produces a verifiable credential.

## Known gaps

- `timerange` is documented as TAMS syntax. A take is bounded by SMPTE timecode. Until the field carries a syntax marker, the range lives under `x-opentrackio`.
- The scope `opentrackio.source` is a convention documented here. Note that a `sourceId` identifies the producing device stream, not the take.
- The recorder is an implementation concern. It has to join the multicast group and write the samples to storage.

See also: [BBC TAMS](/standards-bindings#bbc-tams-growing-assets-and-opaque-timeranges), [Security model](/security-model), [Standards bindings](/standards-bindings).
