At 10,000 feet

Setting: consumer IP cameras (Reolink family) expose a performance API with a cpuUsed percentage, tempting to read as encode headroom.

Problem: these cameras pair a Linux supervisor CPU with a separate video-encoder ASIC, and cpuUsed does not track the encoder (most likely it samples the supervisor CPU: inferred, see below), so it can read comfortable while the encoder falls behind its configured rate.

What this note establishes (measured + inferred): a 4K camera on a low-end encoder SoC configured for 4K HEVC at 20 fps emits only ~17 fps (a 3-frame deficit) while three cameras on other SoC families sustain ~20 fps. The shortfall surfaced as playback stutter, and cpuUsed gave no warning.

Takeaway: don’t infer encoder headroom from cpuUsed. Measure the emitted frame rate off recorded segments and lower the configured rate to one the encoder sustains.

Notes. Traced on one 4K Wi-Fi camera on a low-end encoder SoC, compared against three cameras on other chip families. Frame rates measured from the recorded streams. The CPU-metric interpretation is inferred from the chip architecture, not read off the silicon. No warranty, corrections welcome.

The finding: the deficit is in the encoder, and the metric can’t see it

The stuttering camera’s recorded MP4 segments carried duplicate presentation timestamps on ~10% of frames. It runs a low-end encoder SoC (Fullhan FH1 class). The other three run different chip families. All at 4K HEVC 20 fps:

camera configured fps measured emitted fps
low-end encoder SoC (this one) 20 ~17 (3-frame deficit)
SoC family B 20 20.7
SoC family C 20 20.2
SoC family D 20 20.7

The under-production filled the downstream consumer’s buffer, causing the stutter. The camera with the worst network (much higher ping jitter) held 20.7 fps, ruling out the network: this encoder cannot hold 4K HEVC at 20 fps. Fix (measured): drop to 15 fps: clean constant rate, duplication gone. 15 fps is the vendor’s rated operating point. The spec sheet lists 3840x2160 at 15 fps, with a 2 to 20 fps range and 15 as the default, so 20 fps was a setting above the rating.

Transport is a second cause of the same stutter on this brand. A different 4K Reolink model (Frigate discussion #21224, 2026-05) stuttered and went gray over both RTSP and http-flv, and played cleanly through a proxy speaking the camera’s native protocol. Its emitted frame rate was not measured there. If the emitted rate is full and the stutter persists, the encoder is not the cause.

Honesty and prior art

  • Measured: all frame rates above, the duplicate-PTS symptom, the 15 fps fix.
  • Inferred: that cpuUsed specifically reports the supervisor CPU, from the dual-processor architecture and the metric reading fine during the shortfall. No register-level confirmation.
  • Prior art / novelty: the hn/reolink-camera teardown on GitHub documents the dual-CPU split, and the vendor’s spec sheet rates this model at 15 fps for 4K. New here: the metric’s blindness to encode load, shown by the supervisor-load experiment, and the duplicate-PTS signature of the shortfall.

Validation (2026-08-31)

Read-only re-test on the four live cameras via HTTPS API (GetDevInfo/GetEnc/GetPerformance) plus ffprobe (~25 s/stream, PTS-span fps + duplicate-PTS count). The 4K Wi-Fi camera’s hardware version string contains “FH1”, so the SoC attribution rests on that hardware version string (inferred, not a silicon readout). The other three (4K wired control, ~8 MP panorama, 5 MP doorbell) are different families, all on recent firmware.

State caveat: every stream now runs 15 fps (the FH1 drop was this finding’s own fix, 2026-04) and read-only validation forbids recreating the failing 20 fps state, so the 20→~17 deficit was not re-measured.

camera configured measured (PTS-span) duplicate PTS in 25 s
FH1 4K (via its stream proxy, no direct RTSP on this model) 15 15.00 0
control 4K (direct RTSP) 15 15.03 0
panorama (direct RTSP) 15 15.04 0
  • cpuUsed, all encoding (3–5 samples): FH1 ≈ 20–40, control 4K ≈ 56–64, panorama ≈ 11–13, doorbell ≈ 51–68. The panorama (~119 Mpx/s HEVC, second-highest pixel rate) reports the lowest. The lowest-pixel-rate doorbell (~74 Mpx/s H.264) the highest (cross-model, so chips confound it), but the opposite of what “cpuUsed = encoder load” predicts.
  • Supervisor-load experiment (measured): four parallel HTTPS API loops (pure TLS + JSON, zero encoder involvement) raised the FH1’s cpuUsed from 20–37 (mean ≈ 31) to 43–51 (mean ≈ 48), recovering to 27–39 after.

Verdict: (A) reproduced, register-level caveat intact: cpuUsed tracks supervisor-side load and does not track encoder workload. That it is exclusively the supervisor core remains inferred. (B) partially reproduced: FH1 hardware ID confirmed via GetDevInfo. At 15 fps the camera emits a clean 15.00 fps with zero duplicate PTS, as the fix predicted. The ~17-at-20 deficit is the original April 2026 measurement only. Controls hit 15.03 / 15.04.

Licensed under the site footer’s CC BY 4.0. If this saved you a debugging session, the optional thanks link in the footer is appreciated, no obligation.