Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
158 commits
Select commit Hold shift + click to select a range
bbd67ac
Video sources POC: connector agent, warm processor, local media plane
hansent Jul 6, 2026
8db0b9d
processor: batch results recording + scrubbable playback, completed s…
hansent Jul 6, 2026
0f4ec67
HANDOFF: document heartbeat/orphan-reaping job state management
hansent Jul 6, 2026
d34a2fd
HANDOFF: link draft PRs and strategy deck
hansent Jul 6, 2026
43d7246
video_poc: interactive architecture diagram for demo walkthroughs
hansent Jul 6, 2026
a0164be
processor: download batch sources to local disk; HANDOFF: media plane…
hansent Jul 6, 2026
70222bd
staging deployment plan: Crusoe via roboflow-infra helm chart
hansent Jul 7, 2026
83ef035
deploy plan: add poll-to-queue migration design (dispatch-only queue,…
hansent Jul 7, 2026
645c322
deploy plan: Pub/Sub over RabbitMQ for dispatch; warm-floor scaling s…
hansent Jul 7, 2026
a46382c
deploy plan: WebRTC media path — ICE TCP mux through the ingest LB (s…
hansent Jul 7, 2026
8b4b31c
processor: cloud-ready — per-job identity, GCS results upload, Pub/Su…
hansent Jul 7, 2026
f071d2e
docs: sync HANDOFF + deploy plan with post-review understanding
hansent Jul 7, 2026
bde8be0
processor: ready-pool self-management (label-detach on claim, self-de…
hansent Jul 7, 2026
65376e6
HANDOFF: orphan handling sections updated to implemented requeue beha…
hansent Jul 7, 2026
6458623
processor: fix review findings — key leak, lifecycle races, stream de…
hansent Jul 7, 2026
fc4e137
processor: report localhost (not 127.0.0.1) as the local public URL
hansent Jul 7, 2026
22a1b1f
processor: publish annotated output to the relay while someone is wat…
hansent Jul 7, 2026
2ec2fad
HANDOFF: relay-published live output closed (watch TTL -> WHEP, verif…
hansent Jul 7, 2026
46f4101
video-proc rename: VIDEO_PROC_* env vars, video-proc namespace/infra …
hansent Jul 7, 2026
9d6af9c
publisher: event-driven frames, wallclock timestamps, 1s keyframes
hansent Jul 7, 2026
7a3e945
processor: fleet auth — send the service-secret header when configured
hansent Jul 7, 2026
8af619e
HANDOFF: fleet service-secret auth closes the managed-pool credential…
hansent Jul 7, 2026
8c160a5
processor: in-process aiortc WHIP publisher behind pluggable transpor…
hansent Jul 7, 2026
8ff24ec
HANDOFF: document pod-deletion-cost as the ready-pool's successor, wi…
hansent Jul 7, 2026
d9fcc1c
processor: trim OpenCV RTSP ingest buffering
hansent Jul 7, 2026
c9b032c
processor: kill the decoder's standing 16-frame delay; own serializat…
hansent Jul 7, 2026
e9281a1
HANDOFF: connector camera identity by enumeration index is fragile (o…
hansent Jul 7, 2026
c46fb41
Fix ~550ms standing ingest latency: PyAV producer with codec-level lo…
hansent Jul 7, 2026
1ecbabc
Connector: identify cameras by device name, not avfoundation index
hansent Jul 7, 2026
0b7f18e
Processor: skip per-frame JPEG encodes when nothing consumes them
hansent Jul 7, 2026
dc7b31e
HANDOFF: latency root cause closed (decoder reorder buffer), camera i…
hansent Jul 7, 2026
1d23f9e
Dockerfile: ship low_latency_producer.py (silent cv2 fallback without…
hansent Jul 7, 2026
8d3a579
whip publisher: retry the WHIP POST over the same-path teardown race
hansent Jul 7, 2026
fe14a35
whip publisher: switch outputs in-session instead of restarting
hansent Jul 7, 2026
1fe71bb
processor: legal framing for SSE/MJPEG streams (Traefik withheld them)
hansent Jul 8, 2026
a0d90d6
connector: graceful goodbye, stall watchdog, per-leg visibility
hansent Jul 8, 2026
3d0e356
connector: camera-sharing mode - keep streaming through device conten…
hansent Jul 8, 2026
0517900
processor: cursor-based /events/poll for buffering ingresses
hansent Jul 8, 2026
698946b
HANDOFF: Traefik response-buffering finding + chosen fix (streaming l…
hansent Jul 8, 2026
6e185c3
connector: default --api-url to https://api.roboflow.com
hansent Jul 8, 2026
28ca867
processor: report job failures with error + log tail before retiring
hansent Jul 13, 2026
d1157e0
Remove the connector — it moved to roboflow/rf-video-connector
hansent Jul 13, 2026
0eb9c83
Merge remote-tracking branch 'origin/main' into hansent/video-poc
hansent Jul 13, 2026
6e8cbbf
Merge branch 'main' into hansent/video-poc
hansent Jul 23, 2026
13b62b2
processor: run multiple jobs per worker + gpu/cpu tier claiming
hansent Jul 23, 2026
f059621
Merge remote-tracking branch 'origin/hansent/video-poc' into hansent/…
hansent Jul 23, 2026
00fcdee
processor: fresh pool workers yield claims so streams bin-pack
hansent Jul 23, 2026
bda5ab6
processor: cap ONNX Runtime CPU threads via ONNX_INTRA_OP_THREADS
hansent Jul 24, 2026
a4157ee
Merge branch 'main' into hansent/video-poc
hansent Aug 5, 2026
e59b5ee
Harden video processor job isolation
hansent Aug 5, 2026
d715883
Avoid regex in bearer token parsing
hansent Aug 5, 2026
5b99b45
Merge branch 'main' into hansent/video-poc
hansent Aug 6, 2026
898f152
Expose workflow processor errors
hansent Aug 7, 2026
e2b7702
Merge remote-tracking branch 'origin/main' into hansent/video-poc-har…
hansent Aug 7, 2026
d2df031
Document multi-cell video scaling plan
hansent Aug 10, 2026
d369ef7
Use portable RFC document links
hansent Aug 10, 2026
f481fd4
Add video capacity benchmark tooling
hansent Aug 10, 2026
881ea8e
Merge remote-tracking branch 'origin/main' into hansent/video-poc-har…
hansent Aug 10, 2026
b92ab20
Package video processor metrics module
hansent Aug 11, 2026
ff0eee0
Allow deterministic relay benchmark run ids
hansent Aug 11, 2026
35224b9
Build video processor images for staging
hansent Aug 11, 2026
0d14c43
Use public bases for staging processor builds
hansent Aug 11, 2026
65e9cad
Push staging processor images from runner
hansent Aug 11, 2026
735758c
Remove unavailable staging image workflow
hansent Aug 11, 2026
2e4a97e
Preserve terminal processor metrics before retirement
hansent Aug 11, 2026
c080509
Add staging video workflow corpus runner
hansent Aug 12, 2026
fba0a35
Document staging video benchmark baseline
hansent Aug 12, 2026
647c087
Use accessible staging models in video corpus
hansent Aug 12, 2026
c111d5b
Add video benchmark report analysis
hansent Aug 12, 2026
3626240
Add staged video benchmark experiment matrix
hansent Aug 12, 2026
6ee4b12
Track staging video benchmark experiments
hansent Aug 12, 2026
5c8ebd4
Prototype isolated video processor execution
hansent Aug 12, 2026
0432548
Record staged GPU packing experiment
hansent Aug 12, 2026
0a5dab6
Record live GPU benchmark cap
hansent Aug 12, 2026
4db351b
Fix staging benchmark source listing
hansent Aug 12, 2026
ae2806b
Add bounded video job benchmark telemetry
hansent Aug 12, 2026
4bbbe9f
Plan staging video network benchmarks
hansent Aug 12, 2026
8e684c5
Document staging GPU packing knee
hansent Aug 12, 2026
4760cae
Analyze bounded video job telemetry
hansent Aug 12, 2026
f430d94
Add controlled processor overlay image
hansent Aug 12, 2026
e4cb6d7
Add processor overlay Cloud Build
hansent Aug 12, 2026
fb6cd86
Record current GPU worker capacity boundary
hansent Aug 12, 2026
c846511
Add distributed relay benchmark harness
hansent Aug 12, 2026
b42873a
Add model-for-model CPU benchmark profile
hansent Aug 12, 2026
7feb081
Record CPU processor packing boundary
hansent Aug 12, 2026
d3774c4
Document staging YOLO benchmark model
hansent Aug 12, 2026
0f8e3d4
Add crash-safe video benchmark recovery
hansent Aug 12, 2026
72d76d6
Add multi-workspace benchmark recovery
hansent Aug 12, 2026
c63f972
Add staging workspace execution-domain probe
hansent Aug 12, 2026
829f1bc
Separate controlled FPS capacity curves
hansent Aug 12, 2026
f5d4337
Add staging video benchmark matrices
hansent Aug 12, 2026
95052ba
Add staging video fault injection harness
hansent Aug 12, 2026
d584d67
Harden staging video benchmark recovery
hansent Aug 12, 2026
47213f8
Add provisional video worker recommendations
hansent Aug 12, 2026
f83d3e3
Bind video faults to Crusoe staging
hansent Aug 12, 2026
1a6c640
Document staged video benchmark campaign
hansent Aug 12, 2026
0c54f21
Record staging L40S MPS capabilities
hansent Aug 12, 2026
8339764
Merge remote-tracking branch 'origin/main' into hansent/video-poc-har…
hansent Aug 12, 2026
cb8846d
Clean up process isolation test formatting
hansent Aug 12, 2026
0e4c8d0
Add reproducible staging overlay builder
hansent Aug 12, 2026
f840532
Harden benchmark credential and host validation
hansent Aug 12, 2026
460d34c
Record staging benchmark deployment artifacts
hansent Aug 13, 2026
fba3577
Add reproducible staging video connector
hansent Aug 13, 2026
30f4b16
Record controlled GPU stream capacity
hansent Aug 13, 2026
51338d5
Update video benchmark handoff
hansent Aug 13, 2026
ba3c82e
Record staging model manager smoke
hansent Aug 13, 2026
22b1a16
Record staging model manager A/B
hansent Aug 13, 2026
d25e70f
Confirm MMP frame transport bottleneck
hansent Aug 13, 2026
79dd427
Merge remote-tracking branch 'origin/main' into hansent/video-poc
hansent Aug 13, 2026
c007a81
Add selectable NVDEC video ingest
hansent Aug 13, 2026
64c2ef5
Add reproducible NVDEC staging build
hansent Aug 13, 2026
29f0105
Preserve tensor frames until output sinks
hansent Aug 13, 2026
8ecb821
Restore pip for video worker dependencies
hansent Aug 13, 2026
1cafea3
Gate capacity runs on ingest validation
hansent Aug 13, 2026
7572176
Document v1.4 ingest benchmark gate
hansent Aug 13, 2026
f912aaa
Merge remote-tracking branch 'origin/main' into hansent/video-poc
hansent Aug 13, 2026
6b07b30
Record staging tensor baseline rollout
hansent Aug 13, 2026
6ca3819
Retry fresh RTSP publishers before ingest
hansent Aug 13, 2026
9457b62
Record rejected PyAV tensor baseline
hansent Aug 13, 2026
5da2a3a
Defer PyAV frame materialization
hansent Aug 13, 2026
072c7d4
Record source FPS limiter experiment
hansent Aug 13, 2026
0ca5be3
Keep PyAV unit test isolated
hansent Aug 13, 2026
cc3d0e6
Normalize uploaded file stream replays
hansent Aug 13, 2026
244ec97
Merge remote-tracking branch 'origin/hansent/video-poc' into hansent/…
hansent Aug 13, 2026
53ec804
Report delivered video job throughput
hansent Aug 13, 2026
a21a5bb
Record source FPS limiter results
hansent Aug 13, 2026
4569946
Add L40S runtime capacity campaign
hansent Aug 13, 2026
e320bcb
Open L40S runtime capacity campaign
hansent Aug 13, 2026
58e2798
Run video jobs in isolated processes
hansent Aug 13, 2026
ba0a10f
Merge remote-tracking branch 'origin/main' into hansent/video-poc
hansent Aug 13, 2026
9d97777
Add process image smoke check
hansent Aug 13, 2026
ad55dff
Restrict process image smoke to staging
hansent Aug 13, 2026
2cd1807
Pull process image before smoke inspection
hansent Aug 13, 2026
9d8ca09
Support process jobs on legacy runtime
hansent Aug 13, 2026
0803370
Add staging process overlay build
hansent Aug 13, 2026
aa368b5
Record process experiment images
hansent Aug 13, 2026
008d5e6
Bound video job cancellation cleanup
hansent Aug 13, 2026
0d3d865
Prepare capacity campaign for dedicated video API
hansent Aug 13, 2026
8cbec45
Route video benchmarks through staging hosting
hansent Aug 13, 2026
8b6709e
Record process overlay smoke results
hansent Aug 13, 2026
eed4d0b
Record B c8 backpressure failure
hansent Aug 13, 2026
854eee5
Record confirmed B capacity boundary
hansent Aug 13, 2026
8646ed2
Clarify NVDEC backpressure comparison
hansent Aug 13, 2026
182d7fc
Record staging fairness fixtures
hansent Aug 13, 2026
71244db
Certify multi-workspace benchmark fairness
hansent Aug 13, 2026
8912806
Add staging process variant rollout manifests
hansent Aug 13, 2026
8b07ae9
Record NVDEC capacity boundary
hansent Aug 13, 2026
94071d3
Bind staging benchmark fixture identities
hansent Aug 13, 2026
f344a00
Bind staging workload mix fixture
hansent Aug 13, 2026
0119466
Record D E F L40S image smokes
hansent Aug 13, 2026
ba5e4fc
Prepare staging CPU capacity campaign
hansent Aug 14, 2026
25a0a6a
Add video benchmark decision framework
hansent Aug 14, 2026
5e451ed
Prepare staging multi-cell network campaign
hansent Aug 14, 2026
4b4f9b3
Harden video soak and recovery certification
hansent Aug 14, 2026
699c780
Contain per-job child crashes
hansent Aug 14, 2026
40e963b
Record rebuilt process experiment images
hansent Aug 14, 2026
7aa1b75
Record process-isolated L40S capacity
hansent Aug 14, 2026
e58cd8f
Restore process job JSON events
hansent Aug 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/unit_tests_inference_x86.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,6 @@ jobs:
- name: 🧪 Development Profiling Tests
timeout-minutes: 5
run: python -m pytest tests/development/profiling
- name: 🧪 Video Processor Security Tests
timeout-minutes: 1
run: python -m pytest tests/development/video_poc
7 changes: 7 additions & 0 deletions development/video_poc/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
bin/
__pycache__/
.venv/
videos/
auto.key
auto.crt
connector.json
330 changes: 330 additions & 0 deletions development/video_poc/DEPLOY_PLAN_STAGING.md

Large diffs are not rendered by default.

733 changes: 733 additions & 0 deletions development/video_poc/HANDOFF.md

Large diffs are not rendered by default.

664 changes: 664 additions & 0 deletions development/video_poc/MULTI_CELL_SCALING_RFC.md

Large diffs are not rendered by default.

150 changes: 150 additions & 0 deletions development/video_poc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
# Video Sources POC

End-to-end proof of concept for video sources as a platform primitive. This file is the
**runbook**; for the full context — what we're proving, architecture, flows, data model,
known gaps — read [HANDOFF.md](HANDOFF.md) first. For the next phase — relay capacity,
multi-cell placement, dedicated cells, remote execution, and workload-aware GPU
admission — read [MULTI_CELL_SCALING_RFC.md](MULTI_CELL_SCALING_RFC.md).

```
connector (Go, laptop/LAN) --RTSP push--> mediamtx --RTSP--> processor (Python, warm worker)
| | |
| outbound HTTP poll (commands+ack) | WHEP (browser | MJPEG + SSE events
v | live preview) v (browser, via job.processorUrl)
Roboflow app (Video Sources page; functions: token.js + deviceApi.js; Firestore)
```

Components in this folder (branch `hansent/video-poc`):

- connector — Go agent, now in its own repo: [roboflow/rf-video-connector](https://github.com/roboflow/rf-video-connector)
(single binary + bundled ffmpeg, released via goreleaser; install script in that repo).
Discovers USB cameras (avfoundation/v4l2), RTSP URLs (flags), and
video files (a folder); polls the platform for commands; pushes streams via ffmpeg. Stdlib only.
- `processor/processor.py` — warm worker. Polls the platform for jobs, runs
`InferencePipeline.init_with_workflow` on the assigned source in one of two modes
(`batch` = every frame as fast as possible; `stream` = real-time with drops, files
replayed via `ffmpeg -re` through mediamtx), splits outputs into an SSE events stream
(images redacted to refs) and per-output MJPEG previews (`/preview.mjpeg?output=`,
available outputs advertised in `/status`). Managed-pool claims carry a
platform-minted `processorAccessToken`; job endpoints require it as a Bearer
token (or `access_token` query parameter for native browser media elements).
Bare `/status` and `/metrics` expose only aggregate health/metrics without auth.
- `mediamtx.yml`, `fetch-deps.sh`, `bin/` — local media plane (RTSP ingest :8554, WHEP :8889).
- [`benchmarks/`](benchmarks/) — relay fan-out load harness, provisional workflow
corpus, standalone processor job generator, and aggregate-metric runbook. Active
load is for local, staging, or a dedicated performance cell—not production.

The platform half lives in the `roboflow` repo (branch `hansent/video-sources-poc`):
Video Sources page + `/query/video-sources*` routes (token.js) + connector/processor
endpoints (deviceApi.js) + Firestore collections `video_sources`, `video_connectors`, `video_jobs`.

Staging and the first feature-flagged production cell (`crusoe-use1`) are live as of
2026-08-10. This runbook remains intentionally local; current cluster deployment
mechanics live in the roboflow-infra `helm/roboflow-video-proc/` chart and
`crusoe/video-proc` Terraform stack.

## Running the demo (everything local)

Terminal 0 — deps (once):
```bash
cd development/video_poc && ./fetch-deps.sh
cd ../.. && uv venv development/video_poc/.venv --python 3.11
uv pip install --python development/video_poc/.venv/bin/python -e . onnxruntime requests
# connector lives in roboflow/rf-video-connector now — install a release:
gh api repos/roboflow/rf-video-connector/contents/install.sh -H "Accept: application/vnd.github.raw" | sh
```

Terminal 1 — the app (roboflow worktree). Environment quirks discovered on 2026-07-06:
node 24 required (`n exec 24.11.0`), firebase-tools 15 comes from the repo-root node_modules,
the API-key auth path needs a local Redis on :6379 (`brew install redis`; avoids the docker
compose stack, which also wants nginx), and `build:dev:once` skips docker entirely.

```bash
redis-server --port 6379 &
cd ~/code/wt/roboflow-video-poc/app
n exec 24.11.0 npm run build:dev:once # one-shot webpack build
source ../secrets.sh staging gac && \
PATH="/usr/local/n/versions/node/24.11.0/bin:$PATH" NODE_OPTIONS=--preserve-symlinks \
../node_modules/.bin/firebase emulators:start --only hosting,functions
# app: http://localhost:5000 · functions: http://localhost:5001
```

Terminal 2 — media plane:
```bash
cd development/video_poc && ./bin/mediamtx mediamtx.yml
```

Terminal 3 — warm processor. Two env vars point model downloads at staging (matching the
staging API key): `PROJECT=roboflow-staging` for the classic inference paths, and
`ROBOFLOW_ENVIRONMENT=staging` for the new `inference_models` weights provider (it has its
own config and defaults to prod — without it model loads fail with UnauthorizedModelAccessError):
```bash
cd development/video_poc/processor && \
PROJECT=roboflow-staging ROBOFLOW_ENVIRONMENT=staging ../.venv/bin/python processor.py \
--api-url http://localhost:5001/roboflow-staging/us-central1/light-v2-device \
--api-key $ROBOFLOW_API_KEY
```

Terminal 4 — connector (the thing a customer runs):
```bash
rfv-connector \
--api-url http://localhost:5001/roboflow-staging/us-central1/light-v2-device \
--api-key $ROBOFLOW_API_KEY \
--files-dir ./videos # plus e.g. --rtsp cam1=rtsp://... ; USB cams auto-discovered
```

The connector serves a local status/config UI at **http://127.0.0.1:8070** (`--ui-addr` to
change, empty to disable): platform connection status, per-source enable/disable toggles,
add-RTSP-camera form, and API-key entry — the key can be omitted from the CLI entirely and
set in the UI instead. Runtime changes persist to `connector.json` (`--config`).

Then open the app → **Video Sources** in the sidebar:
1. Connector's cameras/files appear as sources within ~2s of it starting.
2. Click a source → live preview (WHEP) or file playback.
3. "Start processing with workflow" → pick a workflow → annotated MJPEG + JSON event stream.
4. Stop processing → the platform reconciles and tells the connector to stop pushing.

## Standalone processor test (no platform)

```bash
cd development/video_poc
./bin/mediamtx mediamtx.yml &
./bin/ffmpeg -re -f lavfi -i "testsrc2=size=1280x720:rate=30" -c:v libx264 -preset veryfast \
-tune zerolatency -pix_fmt yuv420p -g 30 -f rtsp rtsp://127.0.0.1:8554/test &
cd processor && ../.venv/bin/python processor.py --job-file test-job-blur.json
# http://127.0.0.1:8890/status | /events | /preview.mjpeg
```

Measured on M-series laptop (720p30, blur workflow, CPU): 30 fps sustained,
~40 ms decode→result latency, ~12 s job→first-result (engine init dominates — a
warm processor amortizes imports; model load is the remaining per-job cost).

## Design notes

- **Control channel**: outbound-only polling with commands in the healthcheck response and
ack-by-id — the same pattern as `device-healthcheck-v2` / device-manager.
- **Stream lifecycle**: the platform reconciles desired state (active jobs + preview TTLs)
against connector-reported streams on every healthcheck — start/stop commands are emitted
from the diff. Registered ≠ streaming: video flows only while something needs it.
- **Events vs pixels**: the processor redacts image outputs from the JSON events (SSE) and
serves any image output as MJPEG on demand (`?output=`); `/status` advertises what exists
so viewers can attach to a job after it started.
- **Benchmark telemetry**: an authorized job `/status` response and the platform heartbeat
retain the original `stats.frames`, `stats.fps`, and startup fields, and add a versioned,
fixed-size `stats.counters`/`stats.decodeToResultLatency` report. It distinguishes source
frames captured, decoded/selected, and dropped from inferred, rendered, and actually
published output frames. The latency histogram has fixed bounds so runs can be merged
without retaining per-frame samples. `stats.runtime` reports only an explicit non-secret
allowlist (process/host/GPU visibility plus `VIDEO_PROC_IMAGE` and
`VIDEO_PROC_GIT_SHA` when deployment injects them). Job identity remains out of
Prometheus labels.
- **Two processing modes**: `batch` (files as they are: every frame, in order, faster than
real time is the goal) vs `stream` (real-time pacing, drops under load — cameras, or files
standing in for cameras). Details and the `is_file` gotcha that motivated it: HANDOFF.md §5.
- **Media plane**: mediamtx is one static binary doing RTSP ingest + WHEP browser preview;
the processor consumes plain RTSP from it. This is the seam where the real relay/cell
architecture slots in. The first production cell implements that seam; the next
scaling contract is [MULTI_CELL_SCALING_RFC.md](MULTI_CELL_SCALING_RFC.md).

An interactive architecture diagram with scenario walkthroughs (for demos) lives at
[architecture.html](architecture.html) — open it directly in a browser.
Loading
Loading