lcameraDev: add resolve-only deviceSelector API and deduplicate resolve paths.
Export lcameraDev_resolveDeviceSelectorCReq for attach-identity consumers, factor live-camera snapshot helpers, and share resolveDeviceSelectorAgainstRecords with get-or-create session acquisition. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#include <cameraIdentity.h>
|
#include <cameraIdentity.h>
|
||||||
#include <cameraManagerState.h>
|
#include <cameraManagerState.h>
|
||||||
#include <selectorParse.h>
|
|
||||||
#include <selectorResolve.h>
|
#include <selectorResolve.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
@@ -49,6 +48,40 @@ std::shared_ptr<libcamera::Camera> findCameraById(
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct LiveCameraSnapshot
|
||||||
|
{
|
||||||
|
std::vector<std::shared_ptr<libcamera::Camera>> cameras;
|
||||||
|
std::vector<CameraIdentityRecord> identityRecords;
|
||||||
|
};
|
||||||
|
|
||||||
|
LiveCameraSnapshot snapshotLiveCameras(CameraManagerResources& resources)
|
||||||
|
{
|
||||||
|
LiveCameraSnapshot snapshot;
|
||||||
|
snapshot.cameras = resources.cameraManager->cameras();
|
||||||
|
snapshot.identityRecords = buildIdentityRecords(snapshot.cameras);
|
||||||
|
return snapshot;
|
||||||
|
}
|
||||||
|
|
||||||
|
CameraIdentityRecord resolveDeviceSelectorForLiveCameras(
|
||||||
|
const std::string& deviceSelector,
|
||||||
|
CameraManagerResources& resources)
|
||||||
|
{
|
||||||
|
const LiveCameraSnapshot snapshot = snapshotLiveCameras(resources);
|
||||||
|
return resolveDeviceSelectorAgainstRecords(
|
||||||
|
deviceSelector, snapshot.identityRecords);
|
||||||
|
}
|
||||||
|
|
||||||
|
void requireNonEmptyDeviceSelector(
|
||||||
|
const std::string& deviceSelector,
|
||||||
|
const char *apiName)
|
||||||
|
{
|
||||||
|
if (deviceSelector.empty())
|
||||||
|
{
|
||||||
|
throw std::runtime_error(
|
||||||
|
std::string(apiName) + ": deviceSelector is empty");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
LcameraDevState& getLcameraDevState()
|
LcameraDevState& getLcameraDevState()
|
||||||
@@ -110,29 +143,38 @@ void lcameraDevExit()
|
|||||||
state.isInitialized = false;
|
state.isInitialized = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
sscl::co::ViralNonPostingInvoker<LcameraDevGetOrCreateResult>
|
sscl::co::ViralNonPostingInvoker<CameraIdentityRecord>
|
||||||
getOrCreateDeviceSessionCReq(const std::string& deviceSelector)
|
resolveDeviceSelectorCReq(const std::string& deviceSelector)
|
||||||
{
|
{
|
||||||
if (deviceSelector.empty())
|
requireNonEmptyDeviceSelector(
|
||||||
{
|
deviceSelector, "lcameraDev_resolveDeviceSelectorCReq");
|
||||||
throw std::runtime_error(
|
|
||||||
"lcameraDev_getOrCreateDeviceCReq: deviceSelector is empty");
|
|
||||||
}
|
|
||||||
|
|
||||||
LcameraDevState& state = getLcameraDevState();
|
LcameraDevState& state = getLcameraDevState();
|
||||||
|
|
||||||
sscl::co::CoQutex::ReleaseHandle managerGuard =
|
sscl::co::CoQutex::ReleaseHandle managerGuard =
|
||||||
co_await state.managerState.lock.getAcquireInvocationAndSuspensionPolicy();
|
co_await state.managerState.lock.getAcquireInvocationAndSuspensionPolicy();
|
||||||
|
|
||||||
const std::vector<SelectorCriterion> criteria =
|
co_return resolveDeviceSelectorForLiveCameras(
|
||||||
parseDeviceSelector(deviceSelector);
|
deviceSelector, state.managerState.rsrc);
|
||||||
const std::vector<std::shared_ptr<libcamera::Camera>> cameras =
|
}
|
||||||
state.managerState.rsrc.cameraManager->cameras();
|
|
||||||
const std::vector<CameraIdentityRecord> identityRecords =
|
sscl::co::ViralNonPostingInvoker<LcameraDevGetOrCreateResult>
|
||||||
buildIdentityRecords(cameras);
|
getOrCreateDeviceSessionCReq(const std::string& deviceSelector)
|
||||||
|
{
|
||||||
|
requireNonEmptyDeviceSelector(
|
||||||
|
deviceSelector, "lcameraDev_getOrCreateDeviceCReq");
|
||||||
|
|
||||||
|
LcameraDevState& state = getLcameraDevState();
|
||||||
|
|
||||||
|
sscl::co::CoQutex::ReleaseHandle managerGuard =
|
||||||
|
co_await state.managerState.lock.getAcquireInvocationAndSuspensionPolicy();
|
||||||
|
|
||||||
|
const LiveCameraSnapshot snapshot =
|
||||||
|
snapshotLiveCameras(state.managerState.rsrc);
|
||||||
|
|
||||||
const CameraIdentityRecord resolvedRecord =
|
const CameraIdentityRecord resolvedRecord =
|
||||||
resolveSelectorAgainstRecords(criteria, identityRecords);
|
resolveDeviceSelectorAgainstRecords(
|
||||||
|
deviceSelector, snapshot.identityRecords);
|
||||||
const std::string& resolvedCameraId = resolvedRecord.id;
|
const std::string& resolvedCameraId = resolvedRecord.id;
|
||||||
|
|
||||||
auto sessionIt =
|
auto sessionIt =
|
||||||
@@ -153,7 +195,7 @@ getOrCreateDeviceSessionCReq(const std::string& deviceSelector)
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<libcamera::Camera> camera =
|
std::shared_ptr<libcamera::Camera> camera =
|
||||||
findCameraById(cameras, resolvedCameraId);
|
findCameraById(snapshot.cameras, resolvedCameraId);
|
||||||
if (!camera)
|
if (!camera)
|
||||||
{
|
{
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
@@ -228,15 +270,13 @@ enumerateCamerasCReq()
|
|||||||
sscl::co::CoQutex::ReleaseHandle managerGuard =
|
sscl::co::CoQutex::ReleaseHandle managerGuard =
|
||||||
co_await state.managerState.lock.getAcquireInvocationAndSuspensionPolicy();
|
co_await state.managerState.lock.getAcquireInvocationAndSuspensionPolicy();
|
||||||
|
|
||||||
const std::vector<std::shared_ptr<libcamera::Camera>> cameras =
|
const LiveCameraSnapshot snapshot =
|
||||||
state.managerState.rsrc.cameraManager->cameras();
|
snapshotLiveCameras(state.managerState.rsrc);
|
||||||
const std::vector<CameraIdentityRecord> identityRecords =
|
|
||||||
buildIdentityRecords(cameras);
|
|
||||||
|
|
||||||
std::vector<LcameraDevCameraInfo> cameraInfos;
|
std::vector<LcameraDevCameraInfo> cameraInfos;
|
||||||
cameraInfos.reserve(identityRecords.size());
|
cameraInfos.reserve(snapshot.identityRecords.size());
|
||||||
|
|
||||||
for (const CameraIdentityRecord& record : identityRecords)
|
for (const CameraIdentityRecord& record : snapshot.identityRecords)
|
||||||
{
|
{
|
||||||
cameraInfos.push_back(LcameraDevCameraInfo{
|
cameraInfos.push_back(LcameraDevCameraInfo{
|
||||||
record.id,
|
record.id,
|
||||||
|
|||||||
@@ -40,6 +40,9 @@ void lcameraDevExit();
|
|||||||
|
|
||||||
std::vector<std::shared_ptr<libcamera::Camera>> listLibcameraCameras();
|
std::vector<std::shared_ptr<libcamera::Camera>> listLibcameraCameras();
|
||||||
|
|
||||||
|
sscl::co::ViralNonPostingInvoker<CameraIdentityRecord>
|
||||||
|
resolveDeviceSelectorCReq(const std::string& deviceSelector);
|
||||||
|
|
||||||
sscl::co::ViralNonPostingInvoker<LcameraDevGetOrCreateResult>
|
sscl::co::ViralNonPostingInvoker<LcameraDevGetOrCreateResult>
|
||||||
getOrCreateDeviceSessionCReq(const std::string& deviceSelector);
|
getOrCreateDeviceSessionCReq(const std::string& deviceSelector);
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,19 @@ lcameraDev_getOrCreateDeviceCReq(const std::string& deviceSelector)
|
|||||||
co_return co_await lcamera_dev::getOrCreateDeviceSessionCReq(deviceSelector);
|
co_return co_await lcamera_dev::getOrCreateDeviceSessionCReq(deviceSelector);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sscl::co::ViralNonPostingInvoker<lcamera_dev::CameraIdentityRecord>
|
||||||
|
lcameraDev_resolveDeviceSelectorCReq(const std::string& deviceSelector)
|
||||||
|
{
|
||||||
|
lcamera_dev::LcameraDevState& state = lcamera_dev::getLcameraDevState();
|
||||||
|
if (!state.isInitialized)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(
|
||||||
|
"lcameraDev_resolveDeviceSelectorCReq: call lcameraDev_main first");
|
||||||
|
}
|
||||||
|
|
||||||
|
co_return co_await lcamera_dev::resolveDeviceSelectorCReq(deviceSelector);
|
||||||
|
}
|
||||||
|
|
||||||
sscl::co::ViralNonPostingInvoker<void>
|
sscl::co::ViralNonPostingInvoker<void>
|
||||||
lcameraDev_releaseDeviceCReq(
|
lcameraDev_releaseDeviceCReq(
|
||||||
const std::shared_ptr<lcamera_dev::CameraSession>& deviceSession)
|
const std::shared_ptr<lcamera_dev::CameraSession>& deviceSession)
|
||||||
|
|||||||
@@ -40,6 +40,9 @@ typedef void lcameraDev_exitFn(void);
|
|||||||
typedef sscl::co::ViralNonPostingInvoker<lcamera_dev::LcameraDevGetOrCreateResult>
|
typedef sscl::co::ViralNonPostingInvoker<lcamera_dev::LcameraDevGetOrCreateResult>
|
||||||
lcameraDev_getOrCreateDeviceCReqFn(const std::string& deviceSelector);
|
lcameraDev_getOrCreateDeviceCReqFn(const std::string& deviceSelector);
|
||||||
|
|
||||||
|
typedef sscl::co::ViralNonPostingInvoker<lcamera_dev::CameraIdentityRecord>
|
||||||
|
lcameraDev_resolveDeviceSelectorCReqFn(const std::string& deviceSelector);
|
||||||
|
|
||||||
typedef sscl::co::ViralNonPostingInvoker<void>
|
typedef sscl::co::ViralNonPostingInvoker<void>
|
||||||
lcameraDev_releaseDeviceCReqFn(
|
lcameraDev_releaseDeviceCReqFn(
|
||||||
const std::shared_ptr<lcamera_dev::CameraSession>& deviceSession);
|
const std::shared_ptr<lcamera_dev::CameraSession>& deviceSession);
|
||||||
@@ -55,6 +58,7 @@ typedef sscl::co::ViralNonPostingInvoker<lcamera_dev::LcameraDevConfiguredCamera
|
|||||||
lcameraDev_mainFn lcameraDev_main;
|
lcameraDev_mainFn lcameraDev_main;
|
||||||
lcameraDev_exitFn lcameraDev_exit;
|
lcameraDev_exitFn lcameraDev_exit;
|
||||||
lcameraDev_getOrCreateDeviceCReqFn lcameraDev_getOrCreateDeviceCReq;
|
lcameraDev_getOrCreateDeviceCReqFn lcameraDev_getOrCreateDeviceCReq;
|
||||||
|
lcameraDev_resolveDeviceSelectorCReqFn lcameraDev_resolveDeviceSelectorCReq;
|
||||||
lcameraDev_releaseDeviceCReqFn lcameraDev_releaseDeviceCReq;
|
lcameraDev_releaseDeviceCReqFn lcameraDev_releaseDeviceCReq;
|
||||||
lcameraDev_enumerateCamerasCReqFn lcameraDev_enumerateCamerasCReq;
|
lcameraDev_enumerateCamerasCReqFn lcameraDev_enumerateCamerasCReq;
|
||||||
lcameraDev_configureSessionModeCReqFn lcameraDev_configureSessionModeCReq;
|
lcameraDev_configureSessionModeCReqFn lcameraDev_configureSessionModeCReq;
|
||||||
|
|||||||
@@ -173,4 +173,13 @@ CameraIdentityRecord resolveSelectorAgainstRecords(
|
|||||||
return *matches.front();
|
return *matches.front();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CameraIdentityRecord resolveDeviceSelectorAgainstRecords(
|
||||||
|
const std::string& deviceSelector,
|
||||||
|
const std::vector<CameraIdentityRecord>& records)
|
||||||
|
{
|
||||||
|
const std::vector<SelectorCriterion> criteria =
|
||||||
|
parseDeviceSelector(deviceSelector);
|
||||||
|
return resolveSelectorAgainstRecords(criteria, records);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace lcamera_dev
|
} // namespace lcamera_dev
|
||||||
|
|||||||
@@ -12,6 +12,10 @@ CameraIdentityRecord resolveSelectorAgainstRecords(
|
|||||||
const std::vector<SelectorCriterion>& criteria,
|
const std::vector<SelectorCriterion>& criteria,
|
||||||
const std::vector<CameraIdentityRecord>& records);
|
const std::vector<CameraIdentityRecord>& records);
|
||||||
|
|
||||||
|
CameraIdentityRecord resolveDeviceSelectorAgainstRecords(
|
||||||
|
const std::string& deviceSelector,
|
||||||
|
const std::vector<CameraIdentityRecord>& records);
|
||||||
|
|
||||||
std::string formatCameraListForDiagnostics(
|
std::string formatCameraListForDiagnostics(
|
||||||
const std::vector<CameraIdentityRecord>& records);
|
const std::vector<CameraIdentityRecord>& records);
|
||||||
|
|
||||||
|
|||||||
@@ -71,6 +71,16 @@ sscl::co::NonViralNonPostingInvoker releaseCInd(
|
|||||||
co_return;
|
co_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sscl::co::NonViralNonPostingInvoker resolveSelectorCInd(
|
||||||
|
std::exception_ptr &, std::function<void()>,
|
||||||
|
const char *deviceSelector,
|
||||||
|
lcamera_dev::CameraIdentityRecord& resolvedIdentity)
|
||||||
|
{
|
||||||
|
resolvedIdentity =
|
||||||
|
co_await lcameraDev_resolveDeviceSelectorCReq(deviceSelector);
|
||||||
|
co_return;
|
||||||
|
}
|
||||||
|
|
||||||
void runLcameraDevMainAndNurseryTask(
|
void runLcameraDevMainAndNurseryTask(
|
||||||
const std::function<void(
|
const std::function<void(
|
||||||
const std::shared_ptr<sscl::ComponentThread>&)>& work)
|
const std::shared_ptr<sscl::ComponentThread>&)>& work)
|
||||||
@@ -189,5 +199,62 @@ TEST_F(LcameraDevHilTest, GetOrCreateByBakedSelector)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(LcameraDevHilTest, ResolveDeviceSelectorMatchesGetOrCreateIdentity)
|
||||||
|
{
|
||||||
|
runLcameraDevMainAndNurseryTask(
|
||||||
|
[this](const std::shared_ptr<sscl::ComponentThread>& componentThread)
|
||||||
|
{
|
||||||
|
for (const test_fixtures::BakedCameraProfile *profile :
|
||||||
|
requiredProfiles)
|
||||||
|
{
|
||||||
|
lcamera_dev::CameraIdentityRecord resolvedIdentity;
|
||||||
|
lcamera_dev::LcameraDevGetOrCreateResult createResult;
|
||||||
|
|
||||||
|
sscl::tests::runNonViralNurseryOnComponentThread(
|
||||||
|
componentThread,
|
||||||
|
[profile, &resolvedIdentity](
|
||||||
|
sscl::co::NonViralTaskNursery::Slot::Lease& lease)
|
||||||
|
{
|
||||||
|
return resolveSelectorCInd(
|
||||||
|
lease.getExceptionStorage(),
|
||||||
|
lease.getCallerLambda(),
|
||||||
|
profile->exampleSelector,
|
||||||
|
resolvedIdentity);
|
||||||
|
});
|
||||||
|
|
||||||
|
EXPECT_EQ(resolvedIdentity.id, profile->libcameraId)
|
||||||
|
<< profile->profileTag;
|
||||||
|
|
||||||
|
sscl::tests::runNonViralNurseryOnComponentThread(
|
||||||
|
componentThread,
|
||||||
|
[profile, &createResult](
|
||||||
|
sscl::co::NonViralTaskNursery::Slot::Lease& lease)
|
||||||
|
{
|
||||||
|
return getOrCreateCInd(
|
||||||
|
lease.getExceptionStorage(),
|
||||||
|
lease.getCallerLambda(),
|
||||||
|
profile->exampleSelector,
|
||||||
|
createResult);
|
||||||
|
});
|
||||||
|
|
||||||
|
EXPECT_EQ(
|
||||||
|
createResult.resolvedIdentity.id,
|
||||||
|
resolvedIdentity.id)
|
||||||
|
<< profile->profileTag;
|
||||||
|
|
||||||
|
sscl::tests::runNonViralNurseryOnComponentThread(
|
||||||
|
componentThread,
|
||||||
|
[&createResult](
|
||||||
|
sscl::co::NonViralTaskNursery::Slot::Lease& lease)
|
||||||
|
{
|
||||||
|
return releaseCInd(
|
||||||
|
lease.getExceptionStorage(),
|
||||||
|
lease.getCallerLambda(),
|
||||||
|
createResult.deviceSession);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace lcamera_dev
|
} // namespace lcamera_dev
|
||||||
|
|||||||
@@ -45,6 +45,22 @@ TEST(FormatCameraListForDiagnosticsTest, ListsIndexedCameras)
|
|||||||
EXPECT_NE(text.find("location=front"), std::string::npos);
|
EXPECT_NE(text.find("location=front"), std::string::npos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(ResolveDeviceSelectorAgainstRecordsTest, BakedUsbHdmiCameraMatchesExampleSelector)
|
||||||
|
{
|
||||||
|
const std::vector<CameraIdentityRecord> records =
|
||||||
|
tests::bakedProfilesAsRecords(dellLaptopMachineTag);
|
||||||
|
|
||||||
|
const CameraIdentityRecord resolved =
|
||||||
|
resolveDeviceSelectorAgainstRecords(
|
||||||
|
"model-substr:HDMI;location:EXTERNAL",
|
||||||
|
records);
|
||||||
|
|
||||||
|
EXPECT_EQ(
|
||||||
|
resolved.id,
|
||||||
|
"\\_SB_.PCI0.XHC_.RHUB.HS01-1:1.0-32e4:9415");
|
||||||
|
EXPECT_EQ(resolved.locationLabel, "external");
|
||||||
|
}
|
||||||
|
|
||||||
TEST(ResolveSelectorAgainstRecordsTest, BakedUsbHdmiCameraMatchesExampleSelector)
|
TEST(ResolveSelectorAgainstRecordsTest, BakedUsbHdmiCameraMatchesExampleSelector)
|
||||||
{
|
{
|
||||||
const std::vector<CameraIdentityRecord> records =
|
const std::vector<CameraIdentityRecord> records =
|
||||||
|
|||||||
+51
-12
@@ -117,15 +117,33 @@ Possible future params (not implemented in v1):
|
|||||||
|
|
||||||
### `lcameraBuff()` stim-buff-api params
|
### `lcameraBuff()` stim-buff-api params
|
||||||
|
|
||||||
Reserved for per-producer options (frame rate caps, pixel format preference).
|
Channel selection is driven by the qualeIface name (`colour-yuv-y/u/v`), not by
|
||||||
Channel selection is driven by the qualeIface name, not by stim-buff-api params.
|
stim-buff-api params. Params configure the shared camera mode for all three
|
||||||
|
attachments on the same device.
|
||||||
|
|
||||||
Possible future params:
|
**Resolution (mutually exclusive — use one group only):**
|
||||||
|
|
||||||
* `fps-hz=30`
|
| Group | Synonyms | Meaning |
|
||||||
* `width=640|height=480`
|
|---|---|---|
|
||||||
* `pixfmt=NV12` — negotiation hint for `lcameraBuff` stream setup (not
|
| Explicit dimensions | `frame-width`, `frame-w`, `dimension-width`, `dimension-w`, `dim-width`, `dim-w` | Capture width in pixels |
|
||||||
`lcameraDev`)
|
| Explicit dimensions | `frame-height`, `frame-h`, `dimension-height`, `dimension-h`, `dim-height`, `dim-h` | Capture height in pixels |
|
||||||
|
| Vertical shorthand | `vertical-resolution`, `v-resolution`, `v-res`, `vres` | Preset token: `360`, `360p`, `480`, `480p`, `720`, `720p`, `1080`, `1080p` |
|
||||||
|
|
||||||
|
**Other params:**
|
||||||
|
|
||||||
|
| Synonyms | Meaning |
|
||||||
|
|---|---|
|
||||||
|
| `colorspace`, `color-space`, `colourspace`, `colour-space` | Semantic colour model (`yuv` in v1) |
|
||||||
|
| `full-planar-is-optional`, `opt-planar` | Allow semi-planar or packed YUV when fully planar is unavailable (presence or empty value means enabled; use `=false` to disable) |
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```text
|
||||||
|
lcameraBuff(v-res=480p|colour-space=yuv|opt-planar)
|
||||||
|
```
|
||||||
|
|
||||||
|
Stage 2 (`lcameraBuff`) attach/configure/classify is implemented; capture daemon
|
||||||
|
and frame publication remain future work.
|
||||||
|
|
||||||
## Device selector format
|
## Device selector format
|
||||||
|
|
||||||
@@ -256,13 +274,13 @@ Rules:
|
|||||||
(conflicting mode requests on the same physical camera).
|
(conflicting mode requests on the same physical camera).
|
||||||
* `fullPlanarIsOptional == false` (default): must select a fully planar YUV
|
* `fullPlanarIsOptional == false` (default): must select a fully planar YUV
|
||||||
format or throw with candidate-format diagnostics.
|
format or throw with candidate-format diagnostics.
|
||||||
* `fullPlanarIsOptional == true`: rejected at the configure API until
|
* `fullPlanarIsOptional == true`: may select semi-planar or packed YUV (e.g.
|
||||||
`lcameraBuff` implements non-planar producer deinterleaving (Stage 2). The
|
`YUYV` on UVC webcams). `lcameraBuff` classifies the layout and sizes channel
|
||||||
policy helper still accepts optional planar selection for future use.
|
placeholder buffers; OpenCL deinterleave and capture start are later stages.
|
||||||
|
|
||||||
Streaming, frame delivery, and per-frame colourspace work remain **out of scope**
|
Streaming, frame delivery, and per-frame colourspace work remain **out of scope**
|
||||||
for `lcameraDev`; `lcameraBuff` uses the configured session to allocate buffers
|
for `lcameraDev`; `lcameraBuff` uses the configured session for attach-time
|
||||||
and start capture on attach.
|
setup and will allocate capture buffers / start streaming in later stages.
|
||||||
|
|
||||||
## dlopen API
|
## dlopen API
|
||||||
|
|
||||||
@@ -298,6 +316,9 @@ struct LcameraDevGetOrCreateResult
|
|||||||
typedef sscl::co::ViralNonPostingInvoker<LcameraDevGetOrCreateResult>
|
typedef sscl::co::ViralNonPostingInvoker<LcameraDevGetOrCreateResult>
|
||||||
lcameraDev_getOrCreateDeviceCReqFn(const std::string& deviceSelector);
|
lcameraDev_getOrCreateDeviceCReqFn(const std::string& deviceSelector);
|
||||||
|
|
||||||
|
typedef sscl::co::ViralNonPostingInvoker<CameraIdentityRecord>
|
||||||
|
lcameraDev_resolveDeviceSelectorCReqFn(const std::string& deviceSelector);
|
||||||
|
|
||||||
typedef sscl::co::ViralNonPostingInvoker<void>
|
typedef sscl::co::ViralNonPostingInvoker<void>
|
||||||
lcameraDev_releaseDeviceCReqFn(
|
lcameraDev_releaseDeviceCReqFn(
|
||||||
const std::shared_ptr<CameraSession>& deviceSession);
|
const std::shared_ptr<CameraSession>& deviceSession);
|
||||||
@@ -308,6 +329,24 @@ Failures throw `std::exception`. `lcameraBuff` holds the returned
|
|||||||
session wraps the acquired `libcamera::Camera`; higher layers configure the mode
|
session wraps the acquired `libcamera::Camera`; higher layers configure the mode
|
||||||
then stream from that handle.
|
then stream from that handle.
|
||||||
|
|
||||||
|
### Selector resolution (resolve-only)
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
typedef sscl::co::ViralNonPostingInvoker<CameraIdentityRecord>
|
||||||
|
lcameraDev_resolveDeviceSelectorCReqFn(const std::string& deviceSelector);
|
||||||
|
```
|
||||||
|
|
||||||
|
Parses and resolves a `deviceSelector` against the live libcamera camera list
|
||||||
|
using the same narrowing rules as `getOrCreateDeviceCReq`, but does **not**
|
||||||
|
create a session, acquire a camera, or change session refcounts. Use this when
|
||||||
|
a consumer already holds session-scoped state keyed by `CameraIdentityRecord::id`
|
||||||
|
(for example `lcameraBuff` detach) and only needs the canonical resolved camera
|
||||||
|
identity from an input DAP line.
|
||||||
|
|
||||||
|
Internally both resolve-only and get-or-create paths share
|
||||||
|
`resolveDeviceSelectorAgainstRecords()` in `selectorResolve.cpp` and the live
|
||||||
|
camera snapshot helpers in `cameraManagerState.cpp`.
|
||||||
|
|
||||||
### Session mode configuration
|
### Session mode configuration
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
|
|||||||
Reference in New Issue
Block a user