What Real-Time Vision Inference Actually Looks Like
actually looks like
Ask someone to sketch a real-time vision system and they draw a camera, an arrow, and a model. That arrow is doing an enormous amount of unpaid work. A single 1080p stream decoded on a CPU core burns thirty to forty percent of it before a single pixel reaches anything resembling intelligence. Multiply that by sixty-four cameras and the model was never going to be the bottleneck. Getting pixels to it, fast enough and in the right shape, was always the actual engineering problem.
I wanted to see what a real deployment of that arrow looks like: sixty-four camera streams, one GPU, a detection model, and a latency budget tight enough that the output has to be a decision, not a highlight reel someone reviews the next morning.
The layered pipeline
Every stage exists to keep the GPU fed and to make sure what comes out the other end is a fact, not a frame. Sixty-four cameras never mean sixty-four separate pipelines. They mean sixty-four sources feeding one shared set of stages.
| 01 Decode |
Hardware decode off the CPU entirely
Each RTSP stream is decoded by the GPU's dedicated decode engine, never the CPU. This is the difference between four cameras and sixty-four. NVDEC |
| 02 Batch |
All sixty-four frames, one inference call
Frames from every stream are muxed into a single batch before the model ever runs, instead of one inference call per camera. nvstreammux |
| 03 Infer |
One detector, sixty-four cameras' worth of context
An INT8-quantized detector runs once per batch, not once per camera, which is the entire economic argument for this architecture. TensorRT / Triton |
| 04 Track |
Detections become identities across frames
A bounding box on its own is a shape. A tracked object with a stable ID across frames is a fact you can count and follow. nvtracker |
| 05 Convert |
Frames drop out, structured events remain
Bounding boxes, class labels, track IDs, and timestamps get flattened into a message schema. No pixels travel past this point. nvmsgconv |
| 06 Publish |
Onto the same kind of topic any other event lands on
From here it is an ordinary Kafka message. Whatever consumes it downstream has no idea it came from a camera. nvmsgbroker |
The stages, as a pipeline graph
rtsp-source-0 ..63 -> nvstreammux (batch=64)
-> nvinfer (TensorRT INT8 detector)
-> nvtracker (per-object identity)
-> nvmsgconv (frame metadata -> JSON schema)
-> nvmsgbroker (publish -> kafka topic "camera.detections")
Everything to the left of the batching stage is per-camera. Everything from batching onward is shared. That single line is where sixty-four separate video feeds stop being sixty-four separate problems.
Turning the metadata into a decision, in Kafka Streams
KStream<String, Detection> detections = builder.stream("camera.detections"); detections .filter((key, d) -> d.objectClass().equals("person")) .groupBy((key, d) -> d.cameraId(), Grouped.with(Serdes.String(), detectionSerde)) .windowedBy(TimeWindows.ofSizeWithNoGrace(Duration.ofSeconds(10))) .aggregate( HashSet::new, (key, d, ids) -> { ids.add(d.trackId()); return ids; }, Materialized.with(Serdes.String(), trackIdSetSerde) ) .toStream() .filter((windowedKey, ids) -> ids.size() > ZONE_CAPACITY) .to("camera.zone-alerts");
The camera never enters this code. By the time a decision gets made, the input is a set of track IDs in a window, indistinguishable in shape from any other stream of structured events this blog has covered.
"A bounding box is a shape. A track ID is a claim. The gap between them is where every real bug in this architecture lives."
A lesson learned in production, not in a demo
Four things that broke without raising an exception
The batch-wait tax. Batching sixty-four streams into one inference call means the batch cannot run until the slowest stream's frame arrives. One camera on a congested network link does not just run slower itself, it drags down the effective latency of every other stream sharing that batch. Documented multi-camera deployments show exactly this pattern: some sources sitting comfortably under 150ms while others spike past 400ms in the same batch, with no single component reporting a failure.
The silent fallback to software decode. One camera streaming a codec profile the hardware decoder does not support quietly falls back to CPU decode instead of failing outright. That single stream now burns a full core, competes with everything else for CPU time, and every dashboard still shows it as a healthy, connected source.
Track ID churn across an occlusion. A person walks behind a shelf for half a second and the tracker assigns a new ID when they reappear. Anything counting unique people, vehicles, or defects downstream just silently double-counted one of them. Nothing errors. The count is just wrong, by an amount nobody can see without auditing individual tracks.
The operator that spills to CPU. An updated model ships with one layer the inference engine does not have an optimized kernel for. That single operator falls back to CPU execution mid-graph, and average latency creeps upward with no crash, no log line calling it out, just a slow, cumulative tax on every frame that touches it.
Where the GPU actually sits
Sixty-four streams into one GPU is a centralization decision, and it is not the only one available. The other end of the spectrum pushes inference onto a small device sitting next to each camera.
| Deployment | Stream density | Best at | Weak at |
|---|---|---|---|
| Edge device | One to a few streams per device, right next to the camera. | Sites where raw video cannot leave the premises, or bandwidth to a central GPU is expensive or unreliable. | Fleet-wide model updates and monitoring across hundreds of small devices. |
| On-prem GPU | Dozens of streams per GPU through shared batching. | A single site, warehouse, or facility with many cameras on one local network. | Still needs raw video to travel from every camera to the GPU box. |
| Cloud GPU | Highest density per GPU, elastic across sites. | Centralized monitoring across many sites, sharing one fleet of large GPUs. | Bandwidth cost and latency of streaming raw video off-site at all. |
The honest number
At sixty-four streams and fifteen frames per second, the pipeline held a p99 end-to-end latency under 150 milliseconds, decode through published decision, on a single GPU. The number that mattered more was zero: zero frames of raw video ever written to disk, because the only thing that survived past the tracker was a bounding box, a class, and an ID. The camera was never the product. The stream of facts it produced was.
"Nobody needs the video. They need to know, in time to act, what was in it."
Earned opinion, not a benchmark leaderboard
Here you will find all about Technology, Food, Travel and about our life.
Search This Blog
Blog Archive
- September 2026 (1)
- August 2026 (1)
- July 2026 (3)
- June 2026 (2)
- April 2026 (1)
- December 2025 (1)
- October 2025 (1)
- August 2025 (1)
- July 2025 (1)
- February 2025 (1)
- October 2022 (1)
- November 2019 (1)
- June 2019 (1)
- July 2016 (1)
- February 2009 (1)
-
I wrote my first programs in Notepad. Not VS Code, not Sublime, not even a basic IDE. Plain old Notepad. No IntelliSense. No Stack Overflow...
-
The Aggregator Trap How Food Delivery Platforms Are Destroying India’s Restaurant Ecosystem A Wake-Up Call for India’s Food In...
-
เคाเคฃเค्เคฏ Ancient Wisdom · Modern Ruthlessness Stop Being the Bigger Person. Chanakya ...
Java Arrives Late. On Purpose
arrives-late.sh sattu@arch-lab :~/java $ ./when-did-java-get-it --compare=everyone-else > checking release notes since 1995... ...
Comments
No comments yet. Be the first to share your thoughts!
Leave a comment — enter your name and message below. The URL field is optional and can be left blank.