Add lcameraBuff Stage 2 plugin with YUV attach and unit tests.
Introduce params parsing, pixel/format decisions, capture layout, shared YuvStimProducer per camera, and channel stimulus buffers with attach flow. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,154 @@
|
||||
#include <yuvStimProducer.h>
|
||||
#include <yuvChannelStimulusBuffer.h>
|
||||
#include <lcameraBuffInternal.h>
|
||||
#include <config.h>
|
||||
#include <stdexcept>
|
||||
#define CL_TARGET_OPENCL_VERSION 120
|
||||
#include <CL/cl.h>
|
||||
#include <spinscale/syncCancelerForAsyncWork.h>
|
||||
|
||||
namespace smo {
|
||||
namespace stim_buff {
|
||||
namespace lcamera_buff {
|
||||
|
||||
YuvStimProducer::YuvStimProducer(
|
||||
const std::shared_ptr<device::DeviceAttachmentSpec>& deviceAttachmentSpec,
|
||||
boost::asio::io_context& ioContext,
|
||||
const std::shared_ptr<lcamera_dev::CameraSession>& _deviceSession,
|
||||
const lcamera_dev::CameraIdentityRecord& resolvedIdentity,
|
||||
const LcameraBuffParsedParams& _parsedParams,
|
||||
const lcamera_dev::LcameraDevConfiguredCameraMode& _configuredMode)
|
||||
: StimulusProducer(deviceAttachmentSpec, ioContext),
|
||||
deviceSession(_deviceSession),
|
||||
resolvedCameraId(resolvedIdentity.id),
|
||||
parsedParams(_parsedParams),
|
||||
configuredMode(_configuredMode),
|
||||
layoutPath(classifyYuvCaptureLayoutPath(_configuredMode)),
|
||||
chromaSubsampling(classifyYuvChromaSubsampling(_configuredMode)),
|
||||
channelBackingPlan(getChannelBackingPlanForLayoutPath(layoutPath))
|
||||
{}
|
||||
|
||||
bool YuvStimProducer::supportsQualeIfaceApi(const std::string& qualeIfaceApi)
|
||||
{
|
||||
return qualeIfaceApi == "colour-yuv-y"
|
||||
|| qualeIfaceApi == "colour-yuv-u"
|
||||
|| qualeIfaceApi == "colour-yuv-v";
|
||||
}
|
||||
|
||||
bool YuvStimProducer::exportsQualeIfaceApi(
|
||||
const std::string& qualeIfaceApi) const
|
||||
{
|
||||
return supportsQualeIfaceApi(qualeIfaceApi);
|
||||
}
|
||||
|
||||
std::shared_ptr<StimulusBuffer> YuvStimProducer::getOrCreateAttachedStimulusBuffer(
|
||||
const std::shared_ptr<device::DeviceAttachmentSpec>& attachSpec)
|
||||
{
|
||||
if (!lcameraBuffSmoHooksPtr)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"lcameraBuff: SMO hooks not initialized");
|
||||
}
|
||||
|
||||
if (!supportsQualeIfaceApi(attachSpec->qualeIfaceApi))
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"lcameraBuff: unsupported qualeIfaceApi '"
|
||||
+ attachSpec->qualeIfaceApi + "'");
|
||||
}
|
||||
|
||||
const LcameraBuffParsedParams attachParsedParams =
|
||||
parseLcameraBuffParams(*attachSpec);
|
||||
|
||||
if (!lcameraBuffParamsEqual(attachParsedParams, parsedParams))
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"lcameraBuff: conflicting stimbuff-api params across Y/U/V "
|
||||
"attachments for camera '" + resolvedCameraId + "'");
|
||||
}
|
||||
|
||||
auto existingBuffer = getAttachedStimulusBuffer(attachSpec);
|
||||
if (existingBuffer) {
|
||||
return existingBuffer;
|
||||
}
|
||||
|
||||
/* One YuvStimProducer == one libcamera session. A second DAP line may use
|
||||
* a different deviceSelector yet resolve to this same session; it must not
|
||||
* attach the same qualeIface API twice.
|
||||
*/
|
||||
if (hasBufferWithQualeIfaceApi(attachSpec->qualeIfaceApi))
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"lcameraBuff: qualeIface '" + attachSpec->qualeIfaceApi
|
||||
+ "' is already attached for camera session '"
|
||||
+ resolvedCameraId + "'; each producer allows one buffer per "
|
||||
"qualeIface API");
|
||||
}
|
||||
|
||||
const YuvChannelKind channelKind =
|
||||
YuvChannelStimulusBuffer::yuvChannelKindFromQualeIfaceApi(
|
||||
attachSpec->qualeIfaceApi);
|
||||
|
||||
const size_t channelByteSize = computeDeinterleavedChannelByteSize(
|
||||
channelKind,
|
||||
configuredMode.width,
|
||||
configuredMode.height,
|
||||
chromaSubsampling);
|
||||
|
||||
auto channelBuffer = std::make_shared<YuvChannelStimulusBuffer>(
|
||||
*this,
|
||||
attachSpec,
|
||||
CONFIG_STIMBUFF_FRAME_PERIOD_MS,
|
||||
channelKind,
|
||||
channelByteSize,
|
||||
*lcameraBuffSmoHooksPtr,
|
||||
CL_MEM_READ_WRITE);
|
||||
|
||||
if (!addAttachedStimulusBufferIfNotExists(channelBuffer))
|
||||
{
|
||||
if (hasBufferWithQualeIfaceApi(attachSpec->qualeIfaceApi))
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"lcameraBuff: qualeIface '"
|
||||
+ attachSpec->qualeIfaceApi
|
||||
+ "' is already attached for camera session '"
|
||||
+ resolvedCameraId + "'");
|
||||
}
|
||||
|
||||
throw std::runtime_error(
|
||||
"lcameraBuff: duplicate stimbuff attachment for "
|
||||
+ attachSpec->stringify());
|
||||
}
|
||||
|
||||
return channelBuffer;
|
||||
}
|
||||
|
||||
void YuvStimProducer::destroyAttachedStimulusBuffer(
|
||||
const std::shared_ptr<StimulusBuffer>& buffer)
|
||||
{
|
||||
StimulusProducer::destroyAttachedStimulusBuffer(buffer);
|
||||
}
|
||||
|
||||
void YuvStimProducer::start()
|
||||
{
|
||||
// Stage 2: setup-only attach; capture daemon deferred to Stage 8.
|
||||
}
|
||||
|
||||
void YuvStimProducer::stop()
|
||||
{
|
||||
// Stage 2: setup-only attach; capture daemon deferred to Stage 8.
|
||||
}
|
||||
|
||||
sscl::co::ViralNonPostingInvoker<void>
|
||||
YuvStimProducer::stimFrameProductionTimesliceCInd(
|
||||
sscl::SyncCancelerForAsyncWork& canceler)
|
||||
{
|
||||
(void)canceler;
|
||||
throw std::logic_error(
|
||||
"lcameraBuff: capture daemon not implemented in Stage 2");
|
||||
co_return;
|
||||
}
|
||||
|
||||
} // namespace lcamera_buff
|
||||
} // namespace stim_buff
|
||||
} // namespace smo
|
||||
Reference in New Issue
Block a user