LCamDev: implement configureSessionModeCReq

We can, theoretically, now change the v4l camera's mode.
This commit is contained in:
2026-06-13 20:56:33 -04:00
parent 25d7b9c013
commit 3e85b920fb
20 changed files with 1926 additions and 11 deletions
+79 -8
View File
@@ -36,8 +36,10 @@ Channel splitting, colourspace conversion, threshold masks, and stencils belong
in a separate shared raster library (`rasterStimulus`, future) and in
`lcameraBuff`; `lcameraDev` stops at selector resolution, `CameraManager`
lifecycle, and a refcounted, **acquired** `libcamera::Camera` handle per
resolved device. Stream negotiation, pixel-format selection, frame buffers,
and capture timing belong in `lcameraBuff` (and supporting libraries), not here.
resolved device. Session mode negotiation (width, height, colour-space,
fully-planar YUV requirement) happens in `lcameraDev` before capture starts.
Frame buffers, request queues, and capture timing belong in `lcameraBuff` (and
supporting libraries), not here.
## Why libcamera (for now)
@@ -228,9 +230,39 @@ Rules:
the same physical device from SMOs perspective; channel differences come from
the qualeIface name on each DAP line.
Streaming, frame delivery, and colourspace work are **out of scope** for
`lcameraDev`; `lcameraBuff` uses the sessions acquired camera handle to set up
capture on attach.
## Session mode configuration (Stage 1)
Before `lcameraBuff` starts capture, each producer calls
`lcameraDev_configureSessionModeCReq` on the shared `CameraSession` with the
requested mode:
| Field | Role |
|---|---|
| `width` / `height` | Requested capture dimensions (non-zero) |
| `colourSpace` | Semantic colour model (`Yuv` in v1) |
| `fullPlanarIsOptional` | Default `false` — must select fully planar YUV |
`lcameraDev` chooses a concrete libcamera pixel format (e.g. YUV420) from the
cameras supported formats. DAPS lines name the semantic colour-space, not a
raw fourcc.
Rules:
* Configure only while the session exists and capture has not started.
* **Identical** configure request on an already-configured session is a **no-op**
(multiple `lcameraBuff` producers sharing the same device selector each call
get-or-create then configure with the same mode).
* **Different** configure request on an already-configured session throws
(conflicting mode requests on the same physical camera).
* `fullPlanarIsOptional == false` (default): must select a fully planar YUV
format or throw with candidate-format diagnostics.
* `fullPlanarIsOptional == true`: rejected at the configure API until
`lcameraBuff` implements non-planar producer deinterleaving (Stage 2). The
policy helper still accepts optional planar selection for future use.
Streaming, frame delivery, and per-frame colourspace work remain **out of scope**
for `lcameraDev`; `lcameraBuff` uses the configured session to allocate buffers
and start capture on attach.
## dlopen API
@@ -273,8 +305,42 @@ typedef sscl::co::ViralNonPostingInvoker<void>
Failures throw `std::exception`. `lcameraBuff` holds the returned
`shared_ptr<CameraSession>` and passes it back to `releaseDeviceCReq`. The
session wraps the acquired `libcamera::Camera`; higher layers configure and
stream from that handle`lcameraDev` does not expose frame or stream APIs.
session wraps the acquired `libcamera::Camera`; higher layers configure the mode
then stream from that handle.
### Session mode configuration
```cpp
enum class LcameraDevColourSpace { Yuv };
struct LcameraDevCameraModeRequest
{
unsigned width = 0;
unsigned height = 0;
LcameraDevColourSpace colourSpace = LcameraDevColourSpace::Yuv;
bool fullPlanarIsOptional = false;
};
struct LcameraDevConfiguredCameraMode
{
unsigned width;
unsigned height;
LcameraDevColourSpace colourSpace;
std::string pixelFormatName;
bool isFullyPlanar;
unsigned planeCount;
};
typedef sscl::co::ViralNonPostingInvoker<LcameraDevConfiguredCameraMode>
lcameraDev_configureSessionModeCReqFn(
const std::shared_ptr<CameraSession>& deviceSession,
const LcameraDevCameraModeRequest& request);
```
`lcameraDev_configureSessionModeCReq` delegates to
`CameraSession::configureSessionModeCReq`, which runs libcamera
`generateConfiguration` + `configure` and stores the result on the session.
Identical reconfigure is a no-op; conflicting reconfigure throws.
### Enumeration (discovery)
@@ -298,6 +364,10 @@ When built with `-DENABLE_LIB_lcameraDev=ON`:
`ComponentThread`.
* `lcameraDev_probe <deviceSelector>``getOrCreateDeviceCReq`, then
`releaseDeviceCReq` (selector and session attach/detach only).
* `lcameraDev_configure_probe <deviceSelector> <width> <height> [options]`
`getOrCreateDeviceCReq`, `configureSessionModeCReq`, print resolved mode (or
exception), then `releaseDeviceCReq`. Options: `--colour-space=yuv`,
`--opt-planar` / `--full-planar-is-optional`, `--reconfigure-twice`.
## Module layout
@@ -310,7 +380,8 @@ commonLibs/lcameraDev/
cameraIdentity.h / .cpp Discovery identity records
selectorParse.h / .cpp Compound selector parsing
selectorResolve.h / .cpp AND-match resolution
tools/ lcameraDev_list_cameras, lcameraDev_probe
tools/ lcameraDev_list_cameras, lcameraDev_probe,
lcameraDev_configure_probe
```
Build links against `libcamera` (pkg-config). Does **not** link Salmanoff