Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
329e919
feat(cv610): compile and wire the RTP sidecar into the CV610 backend
snokvist Aug 30, 2026
d679846
fix(cv610): convert the encoder PTS to CLOCK_MONOTONIC for sidecar ca…
snokvist Aug 30, 2026
a050e0d
fix(cv610): populate sidecar qp and frames_since_idr; correct a wrong…
snokvist Aug 30, 2026
cb033e5
fix(cv610): sidecar wire-semantics fixes from adversarial review
snokvist Aug 30, 2026
add5f03
fix(cv610): three defects the review found in the review fixes themse…
snokvist Aug 30, 2026
1219472
Merge pull request #264 from snokvist/feat/cv610-rtp-sidecar
snokvist Aug 30, 2026
2f341be
cv610: honour image.mirror / image.flip at the sensor
snokvist Aug 30, 2026
375d8d5
cv610: review fixes — drop image.rotate, write orientation unconditio…
snokvist Aug 30, 2026
66bb95b
Merge pull request #265 from snokvist/feat/cv610-image-orientation
snokvist Aug 30, 2026
af6c2a3
feat(cv610): centre-priority ROI, and stop skipping it at boot on Maruko
snokvist Aug 30, 2026
3465027
fix(fpv): ship coherent ROI defaults, and name why ROI is disabled
snokvist Aug 30, 2026
2cd7e85
fix(roi): act on adversarial review -- total the shared primitive, stop
snokvist Aug 30, 2026
2e06022
Merge pull request #266 from snokvist/feat/cv610-roi-qp
snokvist Aug 30, 2026
3b52122
feat(cv610): live output retarget, without regressing the ring transp…
snokvist Aug 30, 2026
62a9a03
fix(cv610): act on review -- six defects in the retarget change, thre…
snokvist Aug 30, 2026
ab700c2
Merge pull request #267 from snokvist/feat/cv610-live-output-retarget
snokvist Aug 30, 2026
e1ea029
fix(cv610): the audio side channel follows a live output retarget
snokvist Aug 30, 2026
8897093
Merge pull request #268 from snokvist/fix/cv610-audio-retarget
snokvist Aug 30, 2026
6a22c59
docs: the SigmaStar backends already follow a retarget -- correct the…
snokvist Aug 30, 2026
6f47ebb
Merge pull request #269 from snokvist/docs/sigmastar-audio-already-fo…
snokvist Aug 30, 2026
4515608
feat(cv610): the portable AE ceilings reach the ISP
snokvist Aug 30, 2026
47432b5
review: correct the AWB rationale; guard ae_defaults on isp_ready
snokvist Aug 30, 2026
f3b5a9e
fix: bound fpv.roiQp to +-20, where the delta still reaches the encoder
snokvist Aug 30, 2026
12fa439
review: fix the sites the roiQp bound left behind
snokvist Aug 30, 2026
f6d2447
Merge pull request #270 from snokvist/feat/cv610-ae-limits
snokvist Aug 30, 2026
19778d8
Merge pull request #271 from snokvist/fix/roi-qp-range
snokvist Aug 30, 2026
9606589
docs: the sidecar qp is CV610-only, and SigmaStar cannot do better
snokvist Aug 30, 2026
80a9d3c
feat: report a sustained bitrate overrun, and document the roiQp/maxQ…
snokvist Aug 30, 2026
ece4242
review: say why the config read is unlocked, and note the dual-VENC s…
snokvist Aug 30, 2026
ebd26b8
Merge pull request #272 from snokvist/docs/sigmastar-sidecar-qp-unava…
snokvist Aug 30, 2026
04b643c
Merge pull request #273 from snokvist/feat/bitrate-overrun-watch
snokvist Aug 30, 2026
a795d25
feat(cv610): PQTools .bin import and export reach the ISP (#274)
snokvist Sep 5, 2026
99be1f3
build(cv610): stage libbin.so so a flashed craft can import a .bin (#…
snokvist Sep 5, 2026
206c2bb
fix(cv610): act on the upstream review -- symlink, honesty, and a doc…
snokvist Sep 5, 2026
c39fa5c
fix: act on the three-agent review -- a truncate-before-guard, a lost…
snokvist Sep 5, 2026
39c25e2
fix: five from the fresh-eyes review -- a streak that was not consecu…
snokvist Sep 5, 2026
abed7e7
fix(cv610): validate a retarget destination before anything mutates (…
snokvist Sep 6, 2026
4c5a342
fix(cv610): validate a retarget URI above the ring branch, not below …
snokvist Sep 6, 2026
e0f8de2
fix: no new global mutable state -- AGENTS.md:551, and the reviewer w…
snokvist Sep 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
589 changes: 589 additions & 0 deletions HISTORY.md

Large diffs are not rendered by default.

23 changes: 21 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ CV610_SDK_INC ?= ../openhisilicon
CV610_SDK_LIB ?= ../firmware/output/target/usr/lib
CV610_CC_SUBMAKE := $(if $(findstring /,$(CV610_CC)),$(abspath $(CV610_CC)),$(CV610_CC))

# Vendor PQ library, needed for isp.sensorBin and /api/v1/iq/export_bin on
# CV610. It is NOT in this repo: it is a third-party blob whose licensing is
# the vendor's, so `make stage` copies it when the path resolves and says so
# when it does not. A craft without it boots normally; the import warns and
# no-ops. Override with CV610_PQ_LIB=/path/to/libbin.so.
Comment thread
qodo-free-for-open-source-projects[bot] marked this conversation as resolved.
CV610_PQ_LIB ?= ../hisilicon/vendor/pq/libbin.so

OUT_DIR := out/$(SOC_BUILD)
OBJ_DIR := $(OUT_DIR)/obj
TARGET := $(OUT_DIR)/waybeam
Expand Down Expand Up @@ -67,6 +74,7 @@ CV610_SRC := src/main.c src/backend_cv610.c src/cv610_runtime.c \
src/cv610_encoder_config.c \
src/cv610_iq.c \
src/cv610_modes.c \
src/cv610_pq_bin.c \
src/cv610_jpeg.c \
src/cv610_pipeline.c src/cv610_validation.c src/backend.c \
src/venc_config.c src/venc_httpd.c src/venc_api.c src/venc_webui.c \
Expand All @@ -76,7 +84,7 @@ CV610_SRC := src/main.c src/backend_cv610.c src/cv610_runtime.c \
src/framing_kalman.c src/attitude_est.c src/debug_osd.c \
src/debug_osd_draw.c lib/cJSON.c \
src/h26x_util.c src/h26x_param_sets.c src/rtp_packetizer.c \
src/hevc_rtp.c src/rtp_session.c src/output_socket.c \
src/hevc_rtp.c src/rtp_session.c src/rtp_sidecar.c src/output_socket.c \
src/venc_frame_ring.c src/mdns_wire.c src/mdns_beacon.c \
src/device_id.c src/venc_respawn.c
# Image-stabilization framing module (Star6E). STAB=1 (default) compiles it
Expand Down Expand Up @@ -378,6 +386,17 @@ stage: build qr-decode
chmod +x $(OUT_DIR)/load-cv610-online; \
cp -f config/waybeam-cv610-platform.conf \
$(OUT_DIR)/waybeam-cv610.conf; \
if ls iq-profiles/cv610-bin/*.bin >/dev/null 2>&1; then \
mkdir -p $(OUT_DIR)/isp-bins; cp -f iq-profiles/cv610-bin/*.bin $(OUT_DIR)/isp-bins/; \
fi; \
if [ -f "$(CV610_PQ_LIB)" ]; then \
mkdir -p $(OUT_DIR)/lib; cp -f "$(CV610_PQ_LIB)" $(OUT_DIR)/lib/libbin.so; \
echo " stage: libbin.so from $(CV610_PQ_LIB)"; \
else \
echo " stage: NOTE no libbin.so at $(CV610_PQ_LIB) -- isp.sensorBin"; \
echo " and /api/v1/iq/export_bin will no-op on the craft."; \
echo " Set CV610_PQ_LIB to stage it."; \
fi; \
fi

print-config:
Expand Down Expand Up @@ -435,7 +454,7 @@ TEST_LIB_SRCS := src/qr_scan.c tools/qr/waybeam_qr_format.c \
tools/qr/quirc/identify.c tools/qr/quirc/version_db.c \
src/backend.c src/venc_config.c src/venc_api.c src/venc_httpd.c src/venc_webui.c src/venc_recordings.c src/sensor_select.c src/venc_ring.c src/venc_frame_ring.c src/file_util.c src/h26x_util.c src/h26x_param_sets.c src/intra_refresh.c src/isp_runtime.c src/maruko_config.c src/maruko_video.c src/maruko_output.c src/codec_config.c src/pipeline_common.c src/rtp_session.c src/sdk_quiet.c src/rtp_packetizer.c src/hevc_rtp.c src/star6e_hevc_rtp.c src/star6e_output.c src/star6e_audio.c src/audio_codec.c src/star6e_video.c src/star6e_recorder.c src/star6e_ts_recorder.c src/ts_mux.c src/venc_rec_writer.c src/rtp_sidecar.c src/stream_metrics.c src/output_socket.c src/timing.c src/idr_rate_limit.c src/debug_osd_draw.c src/venc_jpeg.c src/mdns_wire.c src/mdns_beacon.c src/device_id.c src/framing_kalman.c src/attitude_est.c src/detect_dequant.c src/detect_wire.c src/star6e_vpe_ports.c src/maruko_scl_ports.c lib/cJSON.c

$(TEST_RUNNER): $(TEST_SRCS) $(TEST_LIB_SRCS) tests/test_helpers.h include/backend.h include/h26x_param_sets.h include/hevc_rtp.h include/isp_runtime.h include/maruko_config.h include/pipeline_common.h include/rtp_packetizer.h include/rtp_session.h include/rtp_sidecar.h include/star6e_audio.h include/star6e_hevc_rtp.h include/star6e_output.h include/star6e_recorder.h include/star6e_ts_recorder.h include/ts_mux.h include/audio_ring.h include/star6e_video.h include/stream_metrics.h include/venc_frame_ring.h
$(TEST_RUNNER): $(TEST_SRCS) $(TEST_LIB_SRCS) tests/test_helpers.h include/backend.h include/venc_api.h include/h26x_param_sets.h include/hevc_rtp.h include/isp_runtime.h include/maruko_config.h include/pipeline_common.h include/rtp_packetizer.h include/rtp_session.h include/rtp_sidecar.h include/star6e_audio.h include/star6e_hevc_rtp.h include/star6e_output.h include/star6e_recorder.h include/star6e_ts_recorder.h include/ts_mux.h include/audio_ring.h include/star6e_video.h include/stream_metrics.h include/venc_frame_ring.h
$(HOST_CC) $(HOST_CFLAGS) $(TEST_SRCS) $(TEST_LIB_SRCS) -lpthread -ldl -lm -o $@

$(CV610_VALIDATION_TEST): tests/test_cv610_validation.c src/cv610_validation.c \
Expand Down
26 changes: 15 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ omitted fields keep their compiled-in defaults.
"audioPort": 5601, "sidecarPort": 5602
},
"fpv": {
"roiEnabled": true, "roiQp": 0, "roiSteps": 2,
"roiEnabled": false, "roiQp": -20, "roiSteps": 2,
"roiCenter": 0.4, "noiseLevel": 0
},
"audio": {
Expand Down Expand Up @@ -309,7 +309,10 @@ omitted fields keep their compiled-in defaults.
userspace cus3a; on Maruko `custom` additionally installs the no-op
adaptor + supervisory thread for the CPU win), AE rate, gain
ceiling, AWB mode, aspect-preserving crop.
- **`image`** — mirror / flip / rotate.
- **`image`** — mirror / flip / rotate. mirror and flip are applied at the
sensor on all three backends. `rotate` is file-level sugar: `load_image()`
turns `180` into mirror + flip and anything else into 0, on a config parse
only — it is not reachable through `/api/v1/set`.
- **`video0`** — rate control, fps, resolution, bitrate, GOP,
per-section QP delta. Video codec is hardcoded H.265 (HEVC).
Scene-change-triggered IDR (`sceneThreshold`,
Expand Down Expand Up @@ -388,7 +391,7 @@ curl http://<device-ip>:<port>/api/v1/version
```

```json
{"ok":true,"data":{"app_version":"0.73.3","backend":"star6e","contract_version":"0.22.0","config_schema_version":"1.0.0"}}
{"ok":true,"data":{"app_version":"0.81.0","backend":"star6e","contract_version":"0.29.0","config_schema_version":"1.0.0"}}
```

#### GET /api/v1/config
Expand Down Expand Up @@ -621,7 +624,7 @@ load cleanly; the keys are silently ignored.

| Field | Type | Mutability | Description |
|-------|------|------------|-------------|
| `isp.sensor_bin` | string | live | ISP tuning binary path (empty = auto-detect /etc/sensors/&lt;sensor&gt;.bin) |
| `isp.sensor_bin` | string | live | ISP tuning binary path. On Star6E/Maruko empty auto-detects `/etc/sensors/&lt;sensor&gt;.bin`; on CV610 empty is a no-op (no fallback) and the file is a HiSilicon PQTools `.bin`, not a SigmaStar one. |
| `isp.ae_engine` | string | restart | `"sdk"` (default) lets the SDK firmware run AE on Star6E and Maruko. `"custom"` runs userspace cus3a — on Star6E it spins the supervisory AE thread; on Maruko it installs the no-op adaptor + 15 Hz `SetAeParam` thread (~24% sys CPU saving at 120 fps). Alias: `isp.aeEngine`. |
| `isp.ae_fps` | uint | restart | Custom 3A processing rate in Hz (default 15) |
| `isp.gain_max` | uint | live | AE max ISP gain ceiling (0 = use ISP bin default) |
Expand All @@ -633,9 +636,9 @@ load cleanly; the keys are silently ignored.

| Field | Type | Mutability | Description |
|-------|------|------------|-------------|
| `image.mirror` | bool | restart | Horizontal mirror. Applied at the sensor (`MI_SNR_SetOrien`) once at bring-up. Star6E + Maruko. |
| `image.flip` | bool | restart | Vertical flip. Applied at the sensor (`MI_SNR_SetOrien`) once at bring-up. Star6E + Maruko. |
| `image.rotate` | int | restart | Rotation (0, 90, 180, 270) |
| `image.mirror` | bool | restart | Horizontal mirror. Applied at the sensor once at bring-up — `MI_SNR_SetOrien` on Star6E/Maruko, the sensor plugin's `pfn_mirror_flip` on CV610. All three backends **from 0.75.0**. |
| `image.flip` | bool | restart | Vertical flip. Applied at the sensor once at bring-up — `MI_SNR_SetOrien` on Star6E/Maruko, the sensor plugin's `pfn_mirror_flip` on CV610. All three backends **from 0.75.0**. |
| `image.rotate` | int | restart | `180` or `0`. File-level sugar only: `load_image()` turns `180` into `mirror`+`flip` and **anything else into `0`**, on a config parse. Not reachable through `/api/v1/set` — `supported:false` on CV610 for that reason. Star6E + Maruko report it supported because they have no per-backend allowlist. |

#### Video

Expand Down Expand Up @@ -749,7 +752,8 @@ overshoot.
| `video0.qp_delta` | yes | yes | **not offered** |
| `video0.min_qp` / `max_qp` | yes | yes | yes |
| `video0.intra_refresh_qp` | **inert, not offered** | **inert, not offered** | yes |
| `outgoing.sidecar_port` | yes | yes | not implemented |
| `fpv.roi_*` | yes | yes | yes **from 0.76.0** |
| `outgoing.sidecar_port` | yes | yes | yes **from 0.74.0** |

`video0.intra_refresh_qp` is advertised on CV610 only. It reaches
`MI_VENC_SetIntraRefresh` on Star6E and Maruko as well, and both log it as
Expand Down Expand Up @@ -1269,7 +1273,7 @@ Notes:
| Field | Type | Mutability | Description |
|-------|------|------------|-------------|
| `outgoing.enabled` | bool | live | Enable/disable streaming output |
| `outgoing.server` | string | live | Destination URI (`udp://ip:port`, `unix://name`, `shm://name`, or `frame-shm://name`) |
| `outgoing.server` | string | live | Destination URI (`udp://ip:port`, `unix://name`, `shm://name`, or `frame-shm://name`). Live on all three backends — **CV610 from 0.77.0**. A `udp://` ↔ `unix://` change takes effect in place. The ring transports are created once at start and cannot move in place: Star6E and Maruko **refuse** such a write, while CV610 **commits it and respawns**, answering `200` with `reinit_pending` (it was restart-required there until 0.77.0, and refusing would have made `frame-shm://` unreachable through the API) |
| `outgoing.stream_mode` | string | restart | `"rtp"` or `"compact"` |
| `outgoing.max_payload_size` | uint16 | restart | Max UDP payload bytes |
| `outgoing.connected_udp` | bool | restart | Connect UDP socket (applies only to `udp://`) |
Expand Down Expand Up @@ -1334,8 +1338,8 @@ audio track). Settable via the config file or the runtime API

| Field | Type | Mutability | Description |
|-------|------|------------|-------------|
| `fpv.roi_enabled` | bool | live | Enable horizontal ROI bands |
| `fpv.roi_qp` | int | live | Signed ROI delta QP (-30..30, negative = sharper center) |
| `fpv.roi_enabled` | bool | live | Enable horizontal ROI bands. Ships **off**, paired with a non-zero `roi_qp`, so switching it on has an effect |
| `fpv.roi_qp` | int | live | Signed ROI delta QP (-20..20, negative = sharper center). **`0` clears every region regardless of `roi_enabled`** — a zero delta is not a region worth programming. Ships at `-20`. **The safe magnitude depends on `video0.maxQp`**: the delta is subtracted from the frame QP, so the controller raises the base QP ~1:1 to compensate and pins at the ceiling once `base + |roiQp|` passes it — at `maxQp 40`, even `-20` delivered 5.8x its target. `±20` is calibrated for the *default* ceiling. Range narrowed from `-30..30` **in 0.79.0**: past `±20` the delta exceeds the encoder's QP range, and a large negative value saturates rate control and overruns the bitrate target. All three backends **from 0.76.0** (CV610 had no implementation before it) |
| `fpv.roi_steps` | uint16 | live | Number of horizontal bands (1-4) |
| `fpv.roi_center` | double | live | Center band width ratio (0.1-0.9) |
| `fpv.noise_level` | int | restart | 3DNR noise reduction level |
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.73.3
0.81.0
4 changes: 2 additions & 2 deletions config/waybeam.default.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@
"bareAlias": true
},
"fpv": {
"roiEnabled": true,
"roiQp": 0,
"roiEnabled": false,
"roiQp": -20,
"roiSteps": 2,
"roiCenter": 0.4,
"noiseLevel": 0
Expand Down
4 changes: 2 additions & 2 deletions config/waybeam.default.maruko.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@
"bareAlias": true
},
"fpv": {
"roiEnabled": true,
"roiQp": 0,
"roiEnabled": false,
"roiQp": -20,
"roiSteps": 2,
"roiCenter": 0.4,
"noiseLevel": 0
Expand Down
6 changes: 4 additions & 2 deletions docs/CV610_BACKEND.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,10 @@ verifies the requested mode by reading it back before creating the VI pipe.
CV610 has a substantially broader vendor encoder surface than the current
backend exposes: nine declared RC families, multiple P/CRR GOP structures,
intra refresh, reference prediction, SVC, hierarchical QP, native frame-loss
and super-frame policies, ROI/QP maps, VUI/user data, and slice/low-delay
controls. SSC338Q currently has the broader device-proven Waybeam integration.
and super-frame policies, QP maps, VUI/user data, and slice/low-delay
controls. (Plain delta-QP **ROI is no longer in that list** -- it landed in
0.76.0 as `fpv.roi*`; the QP-map and per-frame-ROI halves of the vendor surface
are still unexposed.) SSC338Q currently has the broader device-proven Waybeam integration.

The evidence levels, live-device readback, exact comparison and deliberately
deferred controls are documented in
Expand Down
Loading
Loading