Two hundred cameras. A dozen operators. One video wall of live tiles that has to stay fluid while somebody watches a loading bay at 2 a.m. Build it naïvely and it stutters — tiles freeze, the grid goes soft — and the first reflex, every time, is to blame the network and buy a fatter pipe. Bandwidth is a real constraint, and at a true fleet-of-cameras scale you will provision for it. But the wall rarely dies of bandwidth. It dies because the machine drawing it ran out of a resource nobody put on the quote: decode. Getting a live video wall architecture to hold at 50, 200, 500 cameras is, first and last, a decode-budgeting problem — and once you see it that way, the design writes itself.
What actually happens between the wire and the screen
Before you can call bandwidth the villain, follow one tile from packet to pixel. A live feed arrives as compressed video — H.264 or H.265 off the camera. To show it, the client demuxes the stream, hands it to a decoder that reconstructs every frame, composites the result into its tile, and paints it. Bandwidth governs only the first step: getting the bytes there. Everything after is decode and draw, and that is the expensive part.
Here is the asymmetry that matters. Bandwidth scales roughly linearly and it is cheap to add — more megabits is a line item. Decode does not scale like that. Hardware decoders — the dedicated GPU block (NVDEC on NVIDIA, Quick Sync on Intel) that makes HD video cheap to play — expose a fixed number of concurrent decode sessions. Cross that number and you do not degrade gracefully; you fall off a cliff into CPU software decode, an order of magnitude heavier, or you simply start dropping frames. A workstation that plays four 1080p feeds without noticing will not play forty by adding RAM. The ceiling is the decoder, and it is a wall, not a slope.
So if decode is the ceiling, the fix is not a fatter pipe. It is sending the client less to decode — and surveillance solved that specific problem years before WebRTC existed.
Dual-stream: the surveillance-native trick the web forgot
Nearly every IP camera made in the last decade emits two streams at once. A main-stream at full resolution — 4K or 1080p, high bitrate — meant for recording, where detail is evidence. And a sub-stream at low resolution — often D1 (720×576) or CIF, low bitrate — meant for exactly this: live preview, thumbnails, a wall of tiles nobody is yet scrutinising pixel by pixel. This is dual-streaming, and it is native surveillance vocabulary; a webcam has no such concept.
The mistake web-first teams make is pulling the main-stream for every tile because it is the "real" stream. On a wall, that is decode suicide. A tile 300 pixels wide does not need a 4K decode behind it. Pull sub-streams for the grid and the decode cost per tile collapses — you hold far more tiles inside the same fixed decoder budget, because each one is a fraction of the work. The main-stream is for the recorder and for the one feed a human zooms into. The wall runs on sub-streams.
Sub-streaming buys you an order of magnitude. But an order of magnitude is not infinity — at a couple hundred tiles you still cannot decode a couple hundred of anything on one client. That is where the work has to move off the client entirely.
Server-side mosaic: composite before it reaches the client
When tile count outruns even the sub-stream budget, the move is to stop shipping the client many streams and ship it one. A server composites — decodes many camera feeds, lays them into a single grid frame, re-encodes that grid as one stream — and the client decodes exactly one video to show sixteen, twenty-five, sixty-four cameras. This is server-side mosaic, or tiling, and it turns an impossible client decode into a trivial one.
Nothing is free, and the trade is worth naming honestly: the decode-and-compose work did not vanish, it moved to the server, which now pays a real-time encode cost per mosaic — the same encode tax that makes recording expensive, in a new place. But that cost is shared and controllable. One server-side mosaic serves every operator looking at that grid, instead of every operator's workstation decoding the grid independently. You spend server CPU — ideally GPU-accelerated encode — to buy back client decode you do not have. The rule of thumb: forward individual sub-streams while the client can still decode them; mosaic when the tile count would blow the client's budget.
Mosaic makes the overview cheap. But an overview is not why the operator is there — the moment something moves, they click one tile to full-screen, and now they need a real stream, at full resolution, right now.
Focus and spot: full resolution only where a human is looking
A good wall is mostly low-cost overview with one high-cost point of attention, and the architecture should mirror that. The grid runs on sub-streams or a mosaic; the instant an operator promotes a tile to full-screen — the spot monitor, in surveillance terms — you switch that one feed to the main-stream and give it the full-resolution decode it now deserves. Twenty-four tiles at preview quality plus one at full quality is a decode budget any workstation can hold. Twenty-five at full quality is not.
The catch is the switch itself. Surveillance cameras run long GOPs — a keyframe, the complete frame a decoder needs to start, only every one to four seconds, to save bandwidth and storage — so a naïve switch to the main-stream shows the operator a black tile until the next keyframe arrives. On the feed they clicked precisely because something is happening, a two-second black screen is the worst possible moment to stall. The fix lives on the media server: keep a rolling cache of the last keyframe, and the frames since, per stream, and replay from it the moment a viewer joins so decode starts immediately. Done right, click-to-full-res feels instant instead of laggy.
So the wall is a budget — a decode budget, allocated deliberately across many cheap tiles and one expensive focus. The last question is whether that budget survives contact with reality: many operators, and cameras whose networks flap.
One pull per camera: a video wall that degrades gracefully
Two failure modes separate a demo wall from a deployed one. The first is duplication. If ten operators watch the same camera and the system opens ten pulls on it, you have multiplied load on the constrained end — the camera and its uplink — for nothing. The fix is fan-out: pull each camera once, into a media server, and forward that single ingest to every operator watching it. A camera should never feel the viewer count. This selective-forwarding model is the whole reason a media server sits in the middle at all.
The second is fragility under loss. On a wall of two hundred feeds, at any moment some camera's network is flapping — a PoE switch reboots, a wireless link drops. The question is whether that one bad feed stalls its tile and leaves the other 199 fluid, or drags the whole grid. Per-tile isolation — each feed decoded and recovered independently, a frozen tile showing a last frame or a reconnecting state rather than blocking the compositor — is the difference. It is also why you cannot lean on the camera to smooth things for you: an IP camera's hardware encoder emits one fixed bitrate and cannot do the per-viewer quality laddering (simulcast) a webcam does, so the adaptation has to happen in the infrastructure — sub-stream selection, mosaic, graceful per-tile recovery — not at the source.
Put the pieces together — decode budget, dual-stream, mosaic, focus-switch, single-pull fan-out — and "can it handle 500 cameras?" stops being a bandwidth quote and becomes an architecture you either own or rent.
Build, buy, or deploy
Getting one grid on screen is a weekend. Getting a 200-camera wall fluid across a dozen operators, 24/7, is an infrastructure decision — build, buy, or deploy.
Build on open source. Media servers like go2rtc and MediaMTX already do the hard per-stream parts — RTSP ingest, H.264 passthrough, sub-stream handling, RTSP-to-WebRTC conversion for low-latency tiles. What they do not hand you is the wall: mosaic composition, the focus-switch logic, keyframe caching, per-tile recovery, and fan-out orchestration are yours to build and operate. Right when the wall is core to your product and you have the media engineers to run it.
Use a managed cloud relay. Fastest to a working browser wall with no infrastructure to run — but your camera feeds route through a third party, you pay per stream as the wall grows, and mosaic or compose at their pricing gets expensive at density. Right when speed matters more than owning the path or the unit economics.
Deploy a commercial platform. A full media stack — ingest, sub-stream selection, server-side mosaic, WebRTC fan-out, keyframe-aware switching — delivered as something you run on your own infrastructure or as a managed cloud deployment, under a flat license. Samvyo is one such option; it is based on SFU architecture and deploys on-premise or on your chosen cloud, which keeps the feeds inside infrastructure you control and the cost flat as the wall scales. Where it does not fit: a handful of cameras, or a wall a single workstation already decodes — a media server or a relay is more than enough, and a full platform is over-engineering.
Three paths, one underlying question: who operates the decode budget — you, a vendor's cloud, or a stack you deploy.
The Bottom Line
The video wall's bottleneck was never the pipe. Bandwidth is linear and cheap; the client's decoder is fixed and unforgiving, and the whole discipline of a live video wall architecture is spending that decode budget deliberately — sub-streams for the overview, a server-side mosaic when the tiles outrun the client, and the full-resolution main-stream only where an operator is actually looking. Name decode as the ceiling, and 500 cameras stops being a bandwidth question and becomes a budget you architect.
What's Next?
The wall assumes the stream already made it into a browser — but that handshake is its own problem. The companion piece on RTSP-to-WebRTC walks why cameras can't talk to browsers directly, and the H.265 transcode trap that decides whether one camera or two hundred is affordable: link to RTSP-to-WebRTC blog
Frequently Asked Questions
Why can't a workstation show 50 live camera feeds at once?
Because the limit is decode, not bandwidth. A GPU's hardware decoder exposes a fixed number of concurrent sessions; past it, playback falls back to CPU software decode or drops frames. The network can deliver 50 streams long before one machine can decode 50 — which is why walls run on low-resolution sub-streams and server-side mosaics instead of 50 full decodes.
What is a sub-stream in CCTV?
Most IP cameras emit two streams at once: a full-resolution main-stream for recording, and a low-resolution sub-stream (often D1 or CIF) for live preview and thumbnails. A video wall should pull sub-streams for its tiles — a 300-pixel tile does not need a 4K decode — and reserve the main-stream for the one feed an operator zooms into.
What is a server-side mosaic, and when should I use it?
A mosaic composites many camera feeds into one grid stream on the server, so the client decodes a single video to see 16 or 25 cameras. Use it when the tile count would exceed the client's decoder budget even on sub-streams. The trade is a real-time encode cost on the server — shared across every operator viewing that grid — in exchange for client decode you do not have.
How do you show a camera full-screen instantly when an operator clicks it?
Cache the last keyframe per stream on the media server and replay from it on viewer join. Surveillance cameras send keyframes only every one to four seconds (long GOP), so a naïve switch to the full-resolution stream shows black until the next one arrives. A server-side keyframe cache lets decode start immediately, making the switch feel instant.
WebRTC or HLS for a video wall?
WebRTC for anything an operator watches and acts on live — sub-second latency for the focused feed and interactive tiles. HLS is acceptable for low-priority overview tiles or poor networks where a few seconds of delay is tolerable. Many walls mix both: WebRTC for focus, higher-latency playback for the long tail.
Can a platform like Samvyo handle a large multi-camera wall?
That is the class of problem SFU-based, self-hosted infrastructure is built for: single-pull ingest, fan-out to many operators, and forwarding streams without re-decoding each one. Samvyo is based on SFU architecture and deploys on-premise or as a managed cloud deployment, so the feeds and the decode budget stay inside infrastructure you control, flat-licensed rather than per-stream. For a handful of cameras it is more than you need; for a dense wall at scale it is the tier that fits.