e7b7a311f7
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>
155 lines
4.3 KiB
C++
155 lines
4.3 KiB
C++
#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
|