feat(venc): expose video0.maxIpProp, the RC I-to-P size cap the firmware honours - #111
feat(venc): expose video0.maxIpProp, the RC I-to-P size cap the firmware honours#111vertexodessa wants to merge 1 commit into
Conversation
PR Summary by QodoExpose video0.maxIpProp (u32MaxIPProp) as live CBR I/P size cap
AI Description
Diagram
High-Level Assessment
Files changed (12)
|
Code Review by Qodo
1. Non-CBR returns 500
|
…are honours The per-frame byte caps maxIBytes/maxPBytes are dead on Star6E firmware: probed live 2026-08-22 under H.265 CBR, IDRs measured an identical 42-44 KB with the caps at 2000, 26000, and 8, and the RC priority switch changed nothing. qpDelta barely moves IDR size either (43 KB at 0 and at -6) because the CBR rate controller owns the I/P QP relationship. The parameter the SigmaStar CBR RC actually honours for I-frame size is u32MaxIPProp in MI_VENC_RcParam_t (stParamH265Cbr / stParamH264Cbr), the cap on I-frame size as a proportion of P frames. waybeam never set it, so the permissive SDK default is why recovery IDRs land at ~3x the P-frame budget and occupy the air for ~60 ms at 10 Mbps. This adds video0.maxIpProp (canonical video0.max_ip_prop), live on Star6E and Maruko, CBR only (other rate modes fail the apply with 409). 0 = SDK default: the first apply captures the driver's value so 0 can restore it live, mirroring the minQp/maxQp pattern. Applied at boot when persisted and via /set and /live/set through a new LIVE_GROUP_MAX_IP_PROP. CV610 reports the field unsupported. Validation follows minQp/maxQp: validate_field_cfg() bounds the value to 0..100 and rejects a non-zero value under any rc_mode other than cbr, and the key is in the loaded-config set. That is what makes the documented 409 true — the backend apply returns -1 on non-CBR, which the live-set path would otherwise report as 500 — and it also catches a negative JSON value, which the loader wraps large through the unsigned field. The captured driver default lives in each backend's existing control context rather than a new file-scope global. Contract 0.18.2 -> 0.18.3 (additive). config/waybeam.default.json gains the field at 0 so the save-layout byte-equal test keeps policing the printer. tests/test_venc_config.c pins the loader-side rules. Verified: make test 2491/0; star6e and maruko cross-builds clean.
429b86b to
e151a37
Compare
|
Adversarial review at Blocking defect: the CBR dependency is validated only when the changed key is The current tests cover loader validation only. Please also cover:
The PR text is accurate that Star6E and Maruko are wired through RC-param read/modify/write, CV610 is capability-gated, persisted validation catches wrapped negatives, and Maruko is compile-tested only. The statements that I reproduced |
|
Maruko device test report (device observations only)
Live/API checks under H.265 CBR, 1280x720@30, 10000 kbps, one-second GOP,
The probe received 480 sidecar FRAME datagrams per run; the size table includes only frames for which the probe matched RTP and sidecar metadata. In this scene, IDRs were already smaller than median P frames, and the tested values did not produce a monotonic/reproducible decrease. This test therefore verifies API/apply stability but does not demonstrate a binding A second matrix used 3000 kbps,
Validation/persistence observations:
Existing byte-field comparison on the same device/config family, using forced IDRs:
Not tested here: Star6E, non-CBR modes, H.264, or a scene/config where IDRs exceed P frames enough to demonstrate whether |
|
Star6E high-bitrate device test report (device observations only)
Isolation correction: the first run was excluded after Common isolated config: CBR, one-second GOP, At an achieved 24.7..25.5 Mbps, a continuous-motion paired sidecar sample produced:
Direct off-device H.265 access-unit measurements (
At an achieved 38.1..40.8 Mbps, direct six-second captures produced:
In these 25/40 Mbps configurations, value 1 reproducibly reduced key-AU size; value 2 reduced it in the 25 Mbps samples but not the 40 Mbps sample; values 4 and 100 matched the default-sized key AUs. Key AUs were already much smaller than ordinary AUs in every sample. Full-frame motion did not create the 42–44 KB IDR population described in the PR text on this device/config. Existing byte-field comparison at achieved 25 Mbps:
Not tested here: H.264, non-CBR rate modes, IMX415, or another Star6E firmware build. After testing, the original binary and config SHA-256 hashes matched their pre-test values, the original frame-SHM configuration was active, and |
|
Setup details for the Star6E measurements above The encoder binary under test was the PR-head Star6E build already identified above:
Sensor/IQ environment:
Encoder/test options after stopping the interfering
No recording path was enabled and no capture was written on the device. |
|
Heads-up: #114 (parity sync v0.65.2 → v0.67.1, 54 commits) is open and will conflict with this one. This PR claims Code overlap is real but small: #114 touches Sorry for the churn — happy to help with the rebase if useful. |
|
#114 is merged, so this now shows as conflicting. Nine files overlap: Most of it is mechanical — the sync added Bookkeeping to re-cut: |
|
Closing this. Thanks for the two device reports, and for the isolation work behind them (catching Your code blocker is real and I have not fixed it: the CBR rule runs only when the changed key is On the evidence, one note for whoever picks this up. I would rather withdraw the PR than leave an unverified claim and a known validation hole open, and I can't commit the bench time to finish it properly. The branch stays up if anyone wants it. Also worth flagging that #116 points at One correction to my own PR text while I'm here: it called the byte caps inert, and your Maruko data disproves that — |
The previous commit said the caps are "NOT ENFORCED" and that the SDK "does nothing". Both overstate, and OpenIPC#111 is why. That PR probed the same behaviour on 2026-08-22 -- IDRs an identical 42-44 KB with the caps at 2000, 26000 and 8, RC priority switch changing nothing -- so the Star6E result here is a confirmation, not a discovery, and the comment now says so. More importantly its author WITHDREW the "inert" wording on Maruko evidence, where maxIBytes=2000 moved the IDR median from 12195 to 5866 bytes. The caps do influence frame size on at least one backend. What they do not do is impose the value they name, and that weaker claim is the one the evidence carries. Two scope corrections while narrowing it. The measurement was P frames on a GDR stream, so there were no I frames for maxIBytes to act on and this arm says nothing about it -- the tooltip previously implied both caps. And Maruko is no longer described as "compile-tested only, no evidence either way", because there is Maruko evidence and it points the other way. Also records where the answer may actually lie: u32MaxIPProp, which #111 reports the SigmaStar CBR RC does honour, reachable through SetRcParam and so IDR-free like the byte caps. It caps I size as a proportion of P, so it can only bind where I > P -- dead on a GDR craft, and the regime it was built for (720p120 at ~11 Mbps, IDRs 46-70 KB against much smaller P) is still unswept. It bounds what an IDR costs rather than replacing the bitrate knob, which is a different answer to the problem than this file's comment was reaching for. #111 closed over a config-validation hole that can leave the daemon unable to restart, not over its evidence; anyone reviving it fixes that first. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018Qw7SqCrFpGy4cqRPMicEp
video0.maxIBytes and video0.maxPBytes are deleted from the config, the
capabilities payload, and the Star6E and Maruko backends, together with
apply_max_frame_size() and the MI_VENC_SetRcPriority binding that only
existed to serve them. CV610 never implemented them.
Device-measured on a SSC338Q (IMX335 1280x720@60, H.265 CBR, GDR via racing),
2026-08-28, venc's own recorder as the bitstream tap, every step confirmed
applied by the apply layer's own "priority=framebits" log line:
maxPBytes 33144 B (pred 15909 kbps) -> 19333 kbps
25000 B (pred 12000 kbps) -> 19319 kbps
16000 B (pred 7680 kbps) -> 19285 kbps
10000 B (pred 4800 kbps) -> 19319 kbps
6000 B (pred 2880 kbps) -> 19327 kbps
Flat across a 5.5x range; at 6000 B every one of 863 access units exceeded
the cap, mean 40247 bytes. maxIBytes 91788 -> 26000 -> 8000 -> 2000 left IDR
size at 66-81 KB across 16 sampled IDRs. That second arm is the weaker one and
is labelled as such in HISTORY: the stream is GDR, so its IDRs are on-demand
artefacts of the measurement tap rather than a natural population.
Three controls make the result attributable rather than merely observed. CBR
held its 19092 kbps target to 98.8%, so the rate controller was working and
only MaxISize/MaxPSize failed to bind. Raising video0.minQp to 30 on the same
scene gave ~490 bytes/frame, so the encoder can produce the frame sizes the
cap asks for -- this is not content that would not fit. And every step was
re-read from /api/v1/get, so the config carried what the apply layer logged.
Startup application was not the gap either.
THE CLAIM IS BOUNDED. 0.45.0 recorded maxPBytes=2000 moving a Star6E from
5619 to 1868 kbps -- real influence, 3x below this sweep's floor, and this
sweep did not re-test at 2000 B. It reconciles rather than contradicts: 1868
kbps at 60 fps is ~3892 B/frame against a 2000 B cap, ~1.95x over, and the
Maruko datum in OpenIPC#111 (maxIBytes=2000 -> IDR median 12195
-> 5866) is ~3x over. The caps influence below ~6000 B and bind nowhere they
have been measured. It is the not-binding that disqualifies them as a ceiling,
not an absence of effect. Removing on both backends is the operator's call.
DEPLOY ORDER IS CRAFT-SIDE. The controller that pushed these caps
(waybeam-link) runs on the same box as venc against 127.0.0.1:80; ground nodes
never pushed them. On each craft, update the controller BEFORE this venc.
Backwards, the stale controller's cap transaction 404s at the head of its
queue forever -- write-on-change never advances past a request that never
succeeds -- starving its bitrate, fps and IDR pushes too, not only the caps.
That starvation was already observed on CV610, which answers 501 to these
fields.
Contract 0.20.1 -> 0.21.0 (breaking), VERSION 0.71.0 -> 0.72.0. A config file
still carrying the keys loads (unknown keys ignored); a GET /api/v1/set or
/api/v1/live/set naming them now fails the whole request with 404 unknown
config field, /api/v1/live/set being the path a volatile-first controller hits
first. New regression test covers both paths and asserts a mixed batch applies
nothing.
Use video0.qpDelta to bound I-frame size -- 68x range on the same rig, no
keyframe -- but see #255: applied from the startup path it logs success
without reaching the encoder, so only a live write takes effect today.
specs/2026-07-17-capped-vbr-rc-mode is closed as WITHDRAWN: it was built on
these caps delivering a deterministic ceiling, and its acceptance gate ("no
frame exceeds its maxIBytes/maxPBytes") is unmeetable on this hardware.
make test 2757 passed / 0 failed; make test-werror clean; SOC_BUILD=star6e and
maruko build with no warnings. cv610 does not build in this workspace for an
unrelated pre-existing reason (OpenHisilicon headers absent), confirmed on
master.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018Qw7SqCrFpGy4cqRPMicEp
Summary
Exposes
video0.maxIpProp(canonicalvideo0.max_ip_prop): theu32MaxIPPropfield ofMI_VENC_RcParam_t(stParamH265Cbr/stParamH264Cbr), the CBR rate controller's cap on I-frame size as a proportion of P frames.Motivation: the per-frame byte caps
maxIBytes/maxPBytesare inert on Star6E firmware. Probed live 2026-08-22 under H.265 CBR at 10 Mbps, IDRs measured an identical 42-44 KB with the caps at 2000, 26000, and 8, and switching RC priority changed nothing.qpDeltabarely moves IDR size either (43 KB at 0 and at -6) because the CBR RC owns the I/P QP relationship.u32MaxIPPropis the parameter the SigmaStar CBR RC actually honours; waybeam never set it, so the permissive SDK default is why recovery IDRs land at ~3x the P-frame budget and occupy ~60 ms of air at 10 Mbps.Behaviour
/setand/live/set, through a newLIVE_GROUP_MAX_IP_PROP. Applied at boot when persisted.0..100, CBR only. Validated invalidate_field_cfg()likeminQp/maxQp: values above 100 and a non-zero value under a non-CBRrc_modeare rejected with 409 on/set,/live/set, and at config load, so the backend apply never sees them (and a negative JSON value, which the loader wraps large, is caught the same way).0= SDK default. The first apply captures the driver's value so0can restore it live, mirroring theminQp/maxQppattern. The captured default lives in each backend's existing control context struct, not a new file-scope global.HTTP_API_CONTRACT.md,/api/v1/versionstring bumped.config/waybeam.default.jsongains"maxIpProp": 0so the save-layout byte-equal test keeps policing the printer.VERSION0.65.2 -> 0.66.0,HISTORY.mdentry.Verification
make test: 2491 passed, 0 failed (adds a loader validation table formaxIpProp)make build SOC_BUILD=star6eandSOC_BUILD=maruko: cleanIndependent of #110; whichever merges second needs a trivial
VERSION/HISTORY.mdrebase.