Skip to content

feat: video analytics subsystem — DeepStream 9.0 + Triton (live RTSP, batch segments, tracking, semantic search) #8

Description

@davidamacey

Summary

Add a public, production-grade video analytics subsystem: NVIDIA DeepStream 9.0 pipelines (decode → detect → track → crop) fed by Triton over gRPC, with results stored durably and queryable (time/camera/class filters, text semantic search, reverse-image search) for an external UI. Runs on a single multi-GPU server via docker compose and ships a Kubernetes Helm chart with KEDA autoscaling and HA hygiene.

📄 Full implementation plan (4 documents): https://gist.github.com/davidamacey/aa2e01e46894f5437176b231caeb0645

  1. 01-overview-context-decisions.md — context, verified foundations on main, locked decisions, reconciled naming, risk register
  2. 02-core-pipeline-design.md — repo layout, DeepStream pipeline + PGIE/tracker configs, crop sampling/embedding, event schemas, track stitching, Postgres/OpenSearch/MinIO data model, query API, job orchestration, performance plan, testing
  3. 03-deployment-kubernetes-design.md — compose overlay, container images + Trivy gates, Helm chart, KEDA, GPU scheduling, HA checklist, scaling formulas, CI/CD, ops runbook
  4. 04-implementation-phases.md — validation spikes S1–S7 (riskiest-first, go/no-go), PR1–PR10 breakdown with definitions of done, end-to-end verification script

The implementation-guide comments below this issue contain ground rules, environment facts, spike details, and per-PR acceptance criteria for the implementing agent/developer.

Capabilities

  • Live RTSP feeds — 1..N third-party IP cameras (we only receive; no edge control). Runtime camera add/remove without pipeline restarts (nvmultiurisrcbin + a Postgres-backed assigner and a compacted Kafka control topic).
  • Batch video segments — 5/10/15-minute chunks recorded from live feeds but delivered late; processed faster-than-realtime (K=8 concurrent file sources per GPU, ~20×+ realtime on an A6000), queue-driven, KEDA scale-to-zero.
  • Ad-hoc uploads — arbitrary videos via POST /v1/video/jobs (priority lane).
  • Detection + tracking — existing yolov11_small_trt_end2end engine (EfficientNMS in-engine, 80 COCO classes, vehicles prioritized) as nvinferserver PGIE via Triton gRPC; NvDCF tracker (perf preset live / accuracy preset batch).
  • Search — 3–10 representative crops per track embedded with mobileclip2_s2_image_encoder (512-d); OpenSearch kNN indexes for crops/tracks/scenes; text queries via the existing mobileclip2_s2_text_encoder path; cross-segment track stitching (spatiotemporal + appearance gates) yields global_track_id.
  • Storage — PostgreSQL (source of truth: cameras, jobs, assets, tracks), OpenSearch (vectors/search), MinIO/S3 (segments, crops, keyframes, model repo), Kafka-protocol events (Redpanda locally; portable to Apache Kafka / AWS MSK incl. IAM auth).

Architecture

RTSP cams ──► video-worker-live  (DeepStream: NVDEC → PGIE yolov11 @ Triton gRPC → NvDCF → probes) ─┐
5-15 min files ► MinIO ─ S3 events ─► job topics ─► video-worker-batch (same pipeline, K=8 files)   ├─►
ad-hoc upload ► POST /v1/video/jobs ────────────────────────────────────────────────────────────────┘
        │  crop JPEGs (nvjpeg → MinIO)  +  track/segment events (Kafka JSON)
        ▼
video-writer (Kafka → Postgres upserts → MobileCLIP embeddings via AsyncTritonPool
              → OpenSearch bulk → track stitching → rollups)     video-janitor (leases, intake, GC)
        ▼
video-api (/v1/video/*: cameras, jobs, tracks, text/image search, presigned media) ─► external UI

Built on assets already on main: the hardened DeepStream 9.0 container (docker/hardened/deepstream/, CVE-gated, verified nvinferserver → Triton gRPC at ~951 FPS), the hardened Triton 26.06 image, existing TensorRT engines, AsyncTritonPool, and the OpenSearch kNN layer. Guiding rule: pixels stay on the GPU — only metadata, embeddings, and selected JPEGs leave the pipeline (NVIDIA VSS-blueprint pattern).

Scope

In: everything above + compose overlay (docker-compose.video.yml, ports 4620–4629), Helm chart (deploy/helm/openprocessor-video/) with bundled↔external switches (Redpanda↔MSK, CNPG↔RDS, MinIO↔S3, OpenSearch↔managed), CI workflows (image Trivy gates, helm lint/kind fake-mode smoke, compose validate), docs + runbook, demo profile (mediamtx fake cameras — zero-camera out-of-box demo).

Out (documented for later): VLM/summarization tiers, ReID tracker models (config-swap path documented), Avro/schema registry (JSON envelope now), DINO-style visual reranker, edge components (cameras are third-party).

Phase checklist

  • Spikes S1–S7 (S1 pyds-on-DS9 go/no-go; S2 nvmultiurisrcbin file-EOS; S3 bbox parser; S4 obj_enc; S5 SGIE tensor-meta; S6 NVDEC saturation; S7 stitch threshold)
  • PR1 — design docs, VideoSettings, compose infra (redpanda/postgres/minio/video-init), Makefile targets
  • PR2 — data layer (SQLAlchemy models, Alembic 0001_video_schema, s3.py, kafka.py)
  • PR3 — event schemas + writer skeleton (idempotent upserts, DLQ)
  • PR4 — DeepStream worker image + batch pipeline (first end-to-end)
  • PR5 — live mode + camera assigner + control topic + demo profile
  • PR6 — job orchestration (upload/S3-event intake, claim/lease, janitor)
  • PR7 — crop embeddings + track stitching + search endpoints
  • PR8 — perf bench + dashboards + activity rollups
  • PR9 — Helm chart + KEDA + kind fake-mode smoke
  • PR10 — CI/CD workflows + release + runbook

Acceptance criteria

  1. make video-up + make video-demo on a GPU box: fake RTSP cameras register, tracks accumulate, camera removal detaches cleanly.
  2. Ad-hoc job on a known clip: succeeded, track count within ±20% of golden, every track has ≥1 crop in MinIO and docs in OpenSearch.
  3. One clip split into two overlapping segments → the boundary vehicle carries a single global_track_id.
  4. POST /v1/video/search/text {"query":"red truck"} ranks the seeded truck track first; reverse-image search returns the same vehicle's other crops.
  5. Writer event replay changes no row/doc counts (idempotency).
  6. make video-bench: >400 aggregate FPS on an A6000-class GPU; a 5-minute 1080p segment processes in <60 s.
  7. Trivy 0 CRIT / 0 HIGH (with documented VEX) on all published images; helm lint + kubeconform + kind fake-mode install green.
  8. All Kafka client code runs unmodified against plain Apache Kafka (SASL/TLS) — verified by the release smoke.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions