A camera stream that plays at a few percent CPU in a desktop browser can pin an entire core inside an HMI client. The stream did not change; the decoder did. If you are wiring MJPEG camera views into an HMI or SCADA client and watching the CPU meter climb, here is the cause, a per-stream core budget for sizing operator stations, a worked example with the arithmetic shown, and the fixes in the order that pays.
Same stream, two very different CPU numbers
The case behind this question: one live MJPEG view at 800 x 450 pixels, 60 fps, about 1,200 kbps. Three ways to play it, three outcomes. A desktop browser holds about 5% total CPU. The HMI's built-in camera viewer saturates one core at 100%. The client's embedded browser component lands near 35% CPU and leans hard on memory. Same URL, same camera, same network.
The signature makes this diagnosable: idle cores everywhere, a browser that barely registers, a custom viewer that saturates a core. Decode architecture is the difference, nearly every time. The browser spreads JPEG decode across cores and hardware paths. The native viewer does the whole job in software, on one thread, often the same thread that draws the window.
Likely causes, in order of probability
Work down this list. The first cause explains most cases with this exact shape.
- Software decode of every frame. A Java Swing-based viewer widget decompresses each JPEG on the CPU, single-threaded, while the browser hands video work to multi-core and hardware paths. Test: open the same stream URL in a desktop browser beside the viewer. A gap of five to one or more confirms it.
- Decode on the UI thread. Decode and drawing share one thread, so the interface stutters even while three cores sit idle. Test: does the UI lag scale with the stream's frame rate?
- More frames than the display needs. 60 fps into an operator view that conveys nothing past 10-15 fps wastes most of the decode. Test: cap the camera's frame rate and watch CPU fall roughly in proportion.
- An embedded browser engine without hardware acceleration. It decodes on the CPU too, which is why it sits between the two extremes, and it adds engine memory on top. Test: re-measure after an engine update; the reported case fell from about 35% to about 25%.
- Something else owns the core. Diagnostics services, logging, or a tight polling loop in your own code. Test: sort processes by CPU before you touch the viewer.
What one MJPEG stream costs in cores
A single-threaded decoder can never exceed one logical core, however idle the rest of the machine is. It must also keep pace: each frame has to be decoded within one frame interval, or the queue grows and the picture falls behind the line.
Decode work scales close to linearly with frames per second and with pixels per frame. Normalize against a reference stream - here, the 800 x 450 at 60 fps case, 360,000 pixels per frame:
The working rule for software JPEG decode at this scale: budget one logical core per 800 x 450 stream at 60 fps, and keep one core for the client itself. Treat it as an estimate. JPEG-class decode is close to linear in fps and pixels, but measure your delivered stream before you commit a station design.
Worked example: an 800 x 450 stream at 60 fps on a 4-thread client
Inputs, from the reported case: a stream of 800 x 450 pixels (360,000 per frame) at 60 fps and about 1,200 kbps, played on a client with an i7-6600U - a dual-core mobile CPU with two threads per core, so 4 logical CPUs. Measured on that machine: about 5% total CPU in a desktop browser, one saturated core in the native viewer, 25-35% for the embedded browser engine.
The rule, in words: single-threaded software decode costs one full logical core whatever the thread count, and its share of total CPU is one divided by the number of logical CPUs.
The arithmetic:
- Frame interval: 1000 ms ÷ 60 fps = 16.7 ms per frame. Every 16.7 ms, one core must finish one JPEG.
- Data per frame: 1,200,000 bits/s ÷ 60 fps = 20,000 bits ≈ 2.5 kB per frame, about 0.06 bits per pixel across 360,000 pixels. Light, quickly decoded frames - the load is the pace, not the size.
- Machine-level cost of the viewer: 1 saturated core ÷ 4 logical CPUs = 25% of total CPU. The core reads 100%; the machine reads 25%.
- Browser against viewer: 25% ÷ 5% = 5 times cheaper for identical frames.
Result: software decode of this stream costs about one logical core, or 25% of this machine. The embedded engine costs 25-35%. The desktop browser costs about 5%.
Decision: budget one logical core per stream of this class. On this 4-thread client, software decode tops out at three such streams: 4 threads minus 1 kept for the client. The threshold to act on is stream count × 1 core exceeding logical cores - 1; past it, cut the delivered frame rate or move decode to a hardware path. On the browser route at about 5% each, CPU stops being the limit. Ten such streams draw 10 × 1.2 Mbps = 12 Mbps, which 100 Mbps Ethernet carries with room to spare.
Fixes, in the order to try them
- Move playback to a path that decodes for you. The embedded browser engine is usually the smallest change: same stream, and the decode moves into an engine built for it. The reported case fell from about 35% to about 25% after an engine update, so keep the engine current. Show a camera live stream in an HMI web viewer widget covers that set-up. If your platform can take RTSP or H.264 instead, dedicated video decode blocks on the CPU take over most of the work; RTSP decode CPU overload: offload decode and conversion to the GPU walks through that pipeline.
- Cut what the camera delivers. Frame rate first: 60 fps down to 15 fps removes 75% of the decode work at unchanged image quality. Resolution second: 800 x 450 down to 640 x 360 trims another 36% of the pixels (230,400 against 360,000). Both together cost 0.25 × 0.64 = 0.16 of the original load, about six times less. An operator judging presence, position or a gauge reads a 10-15 fps picture comfortably. The fps, resolution and quality settings live on the camera and in the viewer's stream configuration; the SCADA IP camera MJPEG stream configuration walkthrough covers the SCADA side of those settings.
- Take decode off the UI thread. If you control the client code, decode in a background worker - the documented pattern is a worker class such as SwingWorker in Java-based clients - and draw the latest finished frame on a UI timer. Never poll the stream in a tight loop; the camera acquisition high CPU usage: replace busy waiting fix applies unchanged here too. If you own the decode call, cap its thread pool on purpose instead of letting it grab every core; OpenCV setNumThreads: cap CPU usage while streaming shows the control.
- Size the box for the stream count. If the station must show several streams with software decode, count cores first with the budget above, then pick hardware that clears the number with a core to spare. Keep software-decode viewers off N-series and Celeron-class CPUs; they anchor the low-power end and saturate first on exactly this workload. On such machines, use the browser route or cut the delivered frame rate hard.
The display-side version of the frame-rate trick is in low resolution preview stream: cut decoder CPU load on small displays. If the inspection itself still needs full frames, keep capture and the operator preview separate as in full resolution capture while showing a low res preview. When you choose the smart cameras for the next cell, make a slow display stream part of the requirement.
Sizing the client for several streams
Decide the stream count first, then the decode path, then the hardware. Software decode scales with streams. The browser-engine route trades CPU for memory per widget instead. For a permanent station, PC-class vision hardware makes the budget predictable: fixed CPU and memory, PoE camera ports, and enough LAN to feed several streams from one box.
The MV-VC5525-256G70-NN pairs a 12th-generation Intel Core i5 with 32 GB of memory and PoE camera ports. Any current desktop i5 clears three 800 x 450 software-decoded streams with a core to spare, comfortably inside the budget above.
- LAN ports
- 5+ LAN ports
- USB 3 ports
- 3-4 USB 3 ports
- PoE
- PoE camera ports
- Light outputs
- 8 built-in channels
The MV-VC3301H-128G66 runs an Intel Core i3-8100 with 8 GB of memory and five or more LAN ports. A four-thread i3-class desktop part holds one or two streams of this size by the same budget.
- LAN ports
- 5+ LAN ports
- USB 3 ports
- 3-4 USB 3 ports
- Light outputs
- 4 built-in channels
- Memory
- 8 GB
When the same box also runs the inspection, add that core budget first. The MV-VC4712-256G10-2TH steps up to an Ultra 7 255H with 16 GB x 2 of memory, a 256 GB SSD, a 2 TB HDD and PoE camera ports.
- LAN ports
- 3-4 LAN ports
- USB 3 ports
- 2 USB 3 ports
- PoE
- PoE camera ports
- Light outputs
- 6 built-in channels
Vision computers and fanless industrial PCs
190 models · from $1,119.00Checks before you change anything
- Sort processes by CPU and confirm the viewer owns the load, not a diagnostics service. The wrong owner wastes every fix above.
- Open the stream URL in a desktop browser and write the percentage down. That number is your floor and your proof.
- Halve the camera's frame rate and re-measure. CPU falling in proportion proves the load is decode-bound.
- Record the delivered resolution, frame rate and bitrate. The core budget is computed from exactly these three.
- Count logical cores on the client - threads, not just cores. Your per-core share of total CPU is one divided by that count.
- Note the embedded engine build if you use the browser component. Decode cost and memory move between builds.
When the usual answer is wrong
- The embedded browser component at 25-35% can be the right answer anyway. You get native pan and zoom, no custom code, and the price is memory rather than CPU. Buy the memory and move on.
- If even the desktop browser is expensive, the problem sits upstream of any decoder: the delivered frame rate, resolution or bitrate is too high for the box. Fix it at the camera.
- If the stream stalls, freezes or serves stale frames instead of eating CPU, that is plumbing, not decode. Start at MJPEG stream restart: close the client socket and bust the cache.
- If the viewer accepts only MJPEG while the camera speaks RTSP, converting the feed at the source is a documented pattern; see converting an RTSP feed to MJPEG for an MJPEG-only viewer. Conversion solves format, not CPU. It will not lower the decode bill.
- For plain operator viewing, serving the camera view as a browser page keeps decode where it is cheapest; vision sensor browser display for local operator viewing walks through that display.
The decision and the next step
Count cores, not streams. One logical core per 800 x 450 stream at 60 fps for software decode, one core kept for the client, and when the streams outrun the threads, cut fps first and add hardware second. Shortlist the box in the vision controllers category, pick the camera side in the camera finder, or lay the whole station out in the system configurator. If your budget lands close to the threshold, send the stream specs through the contact page and we will work the numbers with you.
Questions
Why does the same MJPEG stream use far less CPU in a browser?
A desktop browser decodes video away from its UI thread, spreads JPEG work across cores, uses SIMD-tuned decode routines and composites on the GPU. A single-threaded viewer does every step of the decode on one core, often the same core that draws the window. The stream is identical; only the decoder differs. On the 800 x 450, 60 fps case in this guide, that architecture gap measured as 5% against a saturated core.
How many camera streams can one viewer PC show?
Count cores, not streams. Software decode costs about one core-equivalent per 800 x 450 stream at 60 fps, scaled by frame rate and pixels; a 1920 x 1080 stream at 30 fps works out at (30 / 60) x (2073600 / 360000) = about 2.9 core-equivalents. Keep one logical core for the client itself. A four-thread machine therefore shows two to three simple streams; double the threads and you roughly double the count.
Does dropping the camera's frame rate cut CPU proportionally?
Close to linearly, because JPEG decode work scales with the number of frames decompressed, not with what the display shows. Going from 60 fps to 15 fps removes about 75% of the decode cost at unchanged image quality. Pair it with a resolution step and the savings multiply: the worked example combines 0.25 from frame rate with 0.64 from pixels for about six times less work. Presence, position and gauge reads survive 10-15 fps comfortably.
Is MJPEG the wrong format for live viewing?
No. MJPEG sends a complete JPEG every frame, so bitrate runs high but every frame decodes independently: no reference frames, no chain to stall, no accumulating drift. The CPU problem is who decodes the frames and how many arrive, not the format itself. If your platform also accepts H.264 or RTSP with hardware decode, that route engages dedicated silicon on the CPU and usually lands well below software MJPEG decode.


