@@ -49,7 +49,7 @@ public:
bool supportsEvents(V4L2EventSubscription &sub);
int setFrameStartEnabled(bool enable);
- Signal<uint32_t> frameStart;
+ Signal<std::shared_ptr<V4L2Event>> eventReady;
void updateControlInfo();
@@ -13,6 +13,7 @@
#include <libcamera/base/signal.h>
+#include "libcamera/internal/v4l2_event.h"
#include "libcamera/internal/v4l2_subdevice.h"
#include "libcamera/internal/v4l2_videodevice.h"
@@ -58,7 +59,7 @@ public:
FrameBuffer *queueBuffer(FrameBuffer *rawBuffer);
void tryReturnBuffer(FrameBuffer *buffer);
Signal<FrameBuffer *> &bufferReady() { return output_->bufferReady; }
- Signal<uint32_t> &frameStart() { return csi2_->frameStart; }
+ Signal<std::shared_ptr<V4L2Event>> &eventReady() { return csi2_->eventReady; }
Signal<> bufferAvailable;
@@ -63,7 +63,7 @@ public:
void statBufferReady(FrameBuffer *buffer);
void queuePendingRequests();
void cancelPendingRequests();
- void frameStart(uint32_t sequence);
+ void handleEvent(std::shared_ptr<V4L2Event> event);
CIO2Device cio2_;
ImgUDevice *imgu_;
@@ -1089,8 +1089,8 @@ int PipelineHandlerIPU3::registerCameras()
data->delayedCtrls_ =
std::make_unique<DelayedControls>(cio2->sensor()->device(),
params);
- data->cio2_.frameStart().connect(data.get(),
- &IPU3CameraData::frameStart);
+ data->cio2_.eventReady().connect(data.get(),
+ &IPU3CameraData::handleEvent);
/* Convert the sensor rotation to a transformation */
const auto &rotation = data->properties_.get(properties::Rotation);
@@ -1313,7 +1313,7 @@ void IPU3CameraData::cio2BufferReady(FrameBuffer *buffer)
* Record the sensor's timestamp in the request metadata.
*
* \todo The sensor timestamp should be better estimated by connecting
- * to the V4L2Device::frameStart signal.
+ * to the V4L2Device::eventReady signal for FrameSync events.
*/
request->_d()->metadata().set(controls::SensorTimestamp,
buffer->metadata().timestamp);
@@ -1382,9 +1382,14 @@ void IPU3CameraData::statBufferReady(FrameBuffer *buffer)
* TestPatternMode one. Other controls are handled through the delayed
* controls class.
*/
-void IPU3CameraData::frameStart(uint32_t sequence)
+
+void IPU3CameraData::handleEvent(std::shared_ptr<V4L2Event> event)
{
- delayedCtrls_->applyControls(sequence);
+ if (event->type() != V4L2Event::Type::FrameSync)
+ return;
+
+ auto frameSyncEvent = static_cast<V4L2FrameSyncEvent *>(event.get());
+ delayedCtrls_->applyControls(frameSyncEvent->sequence());
if (processingRequests_.empty())
return;
@@ -42,6 +42,7 @@
#include "libcamera/internal/media_device.h"
#include "libcamera/internal/pipeline_handler.h"
#include "libcamera/internal/request.h"
+#include "libcamera/internal/v4l2_event.h"
#include "libcamera/internal/v4l2_subdevice.h"
#include "libcamera/internal/v4l2_videodevice.h"
@@ -198,6 +199,8 @@ public:
PixelFormat adjustRawFormat(const PixelFormat &pixFmt) const;
Size adjustRawSizes(const PixelFormat &pixFmt, const Size &rawSize) const;
+ void handleEvent(std::shared_ptr<V4L2Event> event);
+
Stream frStream_;
Stream dsStream_;
@@ -451,6 +454,15 @@ Size MaliC55CameraData::adjustRawSizes(const PixelFormat &rawFmt, const Size &si
return bestSize;
}
+void MaliC55CameraData::handleEvent(std::shared_ptr<V4L2Event> event)
+{
+ if (event->type() != V4L2Event::Type::FrameSync)
+ return;
+
+ auto frameSyncEvent = static_cast<V4L2FrameSyncEvent *>(event.get());
+ delayedCtrls_->applyControls(frameSyncEvent->sequence());
+}
+
int MaliC55CameraData::loadIPA()
{
int ret;
@@ -1849,8 +1861,7 @@ bool PipelineHandlerMaliC55::registerSensorCamera(MediaLink *ispLink)
V4L2Subdevice *sensorSubdev = in->sensor_->device();
data->delayedCtrls_ = std::make_unique<DelayedControls>(sensorSubdev,
params);
- isp_->frameStart.connect(data->delayedCtrls_.get(),
- &DelayedControls::applyControls);
+ isp_->eventReady.connect(data.get(), &MaliC55CameraData::handleEvent);
/* \todo Init properties. */
@@ -1913,8 +1924,7 @@ bool PipelineHandlerMaliC55::registerMemoryInputCamera(MediaLink *link)
data->delayedCtrls_ =
std::make_unique<DelayedControls>(sensor->device(), params);
- isp_->frameStart.connect(data->delayedCtrls_.get(),
- &DelayedControls::applyControls);
+ isp_->eventReady.connect(data.get(), &MaliC55CameraData::handleEvent);
ivc_->bufferReady.connect(mem->cru_.get(), &RZG2LCRU::returnBuffer);
@@ -44,6 +44,7 @@
#include "libcamera/internal/media_pipeline.h"
#include "libcamera/internal/pipeline_handler.h"
#include "libcamera/internal/request.h"
+#include "libcamera/internal/v4l2_event.h"
#include "libcamera/internal/v4l2_subdevice.h"
#include "libcamera/internal/v4l2_videodevice.h"
#include "libcamera/internal/yaml_parser.h"
@@ -106,6 +107,8 @@ public:
const PipelineHandlerRkISP1 *pipe() const;
int loadIPA(unsigned int hwRevision, uint32_t supportedBlocks);
+ void handleEvent(std::shared_ptr<V4L2Event> event);
+
Stream mainPathStream_;
Stream selfPathStream_;
std::unique_ptr<CameraSensor> sensor_;
@@ -430,6 +433,15 @@ int RkISP1CameraData::loadIPA(unsigned int hwRevision, uint32_t supportedBlocks)
return 0;
}
+void RkISP1CameraData::handleEvent(std::shared_ptr<V4L2Event> event)
+{
+ if (event->type() != V4L2Event::Type::FrameSync)
+ return;
+
+ auto frameSyncEvent = static_cast<V4L2FrameSyncEvent *>(event.get());
+ delayedCtrls_->applyControls(frameSyncEvent->sequence());
+}
+
int RkISP1CameraData::loadTuningFile(const std::string &path)
{
int ret;
@@ -1472,8 +1484,7 @@ int PipelineHandlerRkISP1::createCamera(MediaEntity *sensor)
data->delayedCtrls_ =
std::make_unique<DelayedControls>(data->sensor_->device(),
params);
- isp_->frameStart.connect(data->delayedCtrls_.get(),
- &DelayedControls::applyControls);
+ isp_->eventReady.connect(data.get(), &RkISP1CameraData::handleEvent);
uint32_t supportedBlocks = kDefaultExtParamsBlocks;
@@ -20,6 +20,7 @@
#include <libcamera/property_ids.h>
#include "libcamera/internal/camera_lens.h"
+#include "libcamera/internal/v4l2_event.h"
#include "libcamera/internal/v4l2_subdevice.h"
#include "libcamera/internal/yaml_parser.h"
@@ -873,7 +874,7 @@ int PipelineHandlerBase::registerCamera(std::unique_ptr<RPi::CameraData> &camera
/* Setup the general IPA signal handlers. */
data->frontendDevice()->dequeueTimeout.connect(data, &RPi::CameraData::cameraTimeout);
- data->frontendDevice()->frameStart.connect(data, &RPi::CameraData::frameStarted);
+ data->frontendDevice()->eventReady.connect(data, &RPi::CameraData::handleEvent);
data->ipa_->setDelayedControls.connect(data, &CameraData::setDelayedControls);
data->ipa_->setLensControls.connect(data, &CameraData::setLensControls);
data->ipa_->metadataReady.connect(data, &CameraData::metadataReady);
@@ -1392,12 +1393,17 @@ void CameraData::cameraTimeout()
clearIncompleteRequests();
}
-void CameraData::frameStarted(uint32_t sequence)
+void CameraData::handleEvent(std::shared_ptr<V4L2Event> event)
{
- LOG(RPI, Debug) << "Frame start " << sequence;
+ if (event->type() != V4L2Event::Type::FrameSync)
+ return;
+
+ auto frameSyncEvent = static_cast<V4L2FrameSyncEvent *>(event.get());
+
+ LOG(RPI, Debug) << "Frame start " << frameSyncEvent->sequence();
/* Write any controls for the next frame as soon as we can. */
- delayedCtrls_->applyControls(sequence);
+ delayedCtrls_->applyControls(frameSyncEvent->sequence());
}
void CameraData::clearIncompleteRequests()
@@ -25,6 +25,7 @@
#include "libcamera/internal/media_object.h"
#include "libcamera/internal/pipeline_handler.h"
#include "libcamera/internal/request.h"
+#include "libcamera/internal/v4l2_event.h"
#include "libcamera/internal/v4l2_videodevice.h"
#include "libcamera/internal/value_node.h"
@@ -86,7 +87,7 @@ public:
virtual void platformSetIspCrop(unsigned int index, const Rectangle &ispCrop) = 0;
void cameraTimeout();
- void frameStarted(uint32_t sequence);
+ void handleEvent(std::shared_ptr<V4L2Event> event);
void clearIncompleteRequests();
void handleStreamBuffer(FrameBuffer *buffer, Stream *stream);
@@ -299,6 +299,8 @@ public:
return stream - &streams_.front();
}
+ void handleEvent(std::shared_ptr<V4L2Event> event);
+
struct Entity {
/* The media entity, always valid. */
MediaEntity *entity;
@@ -985,6 +987,15 @@ void SimpleCameraData::clearIncompleteRequests()
}
}
+void SimpleCameraData::handleEvent(std::shared_ptr<V4L2Event> event)
+{
+ if (event->type() != V4L2Event::Type::FrameSync)
+ return;
+
+ auto frameSyncEvent = static_cast<V4L2FrameSyncEvent *>(event.get());
+ delayedCtrls_->applyControls(frameSyncEvent->sequence());
+}
+
void SimpleCameraData::tryCompleteRequest(Request *request)
{
if (request->hasPendingBuffers())
@@ -1673,8 +1684,8 @@ int SimplePipelineHandler::start(Camera *camera, [[maybe_unused]] const ControlL
stop(camera);
return ret;
}
- frameStartEmitter->frameStart.connect(data->delayedCtrls_.get(),
- &DelayedControls::applyControls);
+ frameStartEmitter->eventReady.connect(data,
+ &SimpleCameraData::handleEvent);
}
ret = video->streamOn();
@@ -1713,8 +1724,8 @@ void SimplePipelineHandler::stopDevice(Camera *camera)
if (frameStartEmitter) {
frameStartEmitter->setFrameStartEnabled(false);
- frameStartEmitter->frameStart.disconnect(data->delayedCtrls_.get(),
- &DelayedControls::applyControls);
+ frameStartEmitter->eventReady.connect(data,
+ &SimpleCameraData::handleEvent);
}
if (data->useConversion_) {
@@ -503,7 +503,7 @@ bool V4L2Device::supportsEvents(V4L2EventSubscription &sub)
* \param[in] enable True to enable frame start events, false to disable them
*
* This function enables or disables generation of frame start events. Once
- * enabled, the events are signalled through the frameStart signal.
+ * enabled, the events are signalled through the eventReady signal.
*
* \return 0 on success, a negative error code otherwise
*/
@@ -528,8 +528,8 @@ int V4L2Device::setFrameStartEnabled(bool enable)
}
/**
- * \var V4L2Device::frameStart
- * \brief A Signal emitted when capture of a frame has started
+ * \var V4L2Device::eventReady
+ * \brief A Signal emitted when a V4L2 event is received
*/
/**
@@ -867,15 +867,15 @@ void V4L2Device::eventAvailable()
return;
}
- if (event.type != V4L2_EVENT_FRAME_SYNC) {
+ auto v4l2Event = V4L2Event::createEvent(&event);
+ if (!v4l2Event) {
LOG(V4L2, Error)
- << "Spurious event (" << event.type
- << "), disabling event notifier";
+ << "Invalid V4L2 Event type, disabling event notifier";
fdEventNotifier_->setEnabled(false);
return;
}
- frameStart.emit(event.u.frame_sync.frame_sequence);
+ eventReady.emit(v4l2Event);
}
static const std::map<uint32_t, ColorSpace> v4l2ToColorSpace = {
Currently V4L2Device emits a signal for the V4L2_EVENT_FRAME_SYNC event, with a Signal signature that is specific to it. Replace this with a generic Signal<V4L2Event> and leave the Slots to decide how to handle the event. This will allow us to easily extend handling to other events in the future. Update the existing slots to handle the new Signal<V4L2Event>. Signed-off-by: Daniel Scally <dan.scally@ideasonboard.com> --- With this change, in V4L2Device::eventAvailable() I am creating a std::shared_ptr<V4L2Event> and emitting the signal to the handler for it. I *think* this is ok and that once eventAvailable() and the Slot handler have returned it is cleaned up, but I thought I'd mention it incase I'm wrong. --- include/libcamera/internal/v4l2_device.h | 2 +- src/libcamera/pipeline/ipu3/cio2.h | 3 ++- src/libcamera/pipeline/ipu3/ipu3.cpp | 17 +++++++++++------ src/libcamera/pipeline/mali-c55/mali-c55.cpp | 18 ++++++++++++++---- src/libcamera/pipeline/rkisp1/rkisp1.cpp | 15 +++++++++++++-- src/libcamera/pipeline/rpi/common/pipeline_base.cpp | 14 ++++++++++---- src/libcamera/pipeline/rpi/common/pipeline_base.h | 3 ++- src/libcamera/pipeline/simple/simple.cpp | 19 +++++++++++++++---- src/libcamera/v4l2_device.cpp | 14 +++++++------- 9 files changed, 75 insertions(+), 30 deletions(-)