@@ -10,6 +10,7 @@
#include <map>
#include <memory>
#include <optional>
+#include <set>
#include <span>
#include <stdint.h>
#include <vector>
@@ -48,7 +49,7 @@ public:
std::string devicePath() const;
bool supportsEvents(V4L2EventSubscription &sub);
- int setFrameStartEnabled(bool enable);
+ int setEventsEnabled(V4L2EventSubscription &sub, bool enable);
Signal<std::shared_ptr<V4L2Event>> eventReady;
void updateControlInfo();
@@ -91,7 +92,7 @@ private:
UniqueFD fd_;
std::unique_ptr<EventNotifier> fdEventNotifier_;
- bool frameStartEnabled_;
+ std::set<V4L2EventSubscription> subscribedEvents_;
};
} /* namespace libcamera */
@@ -356,7 +356,8 @@ int CIO2Device::start()
return ret;
}
- ret = csi2_->setFrameStartEnabled(true);
+ V4L2EventSubscription sub(V4L2Event::Type::FrameSync);
+ ret = csi2_->setEventsEnabled(sub, true);
if (ret) {
stop();
return ret;
@@ -369,7 +370,8 @@ int CIO2Device::stop()
{
int ret;
- csi2_->setFrameStartEnabled(false);
+ V4L2EventSubscription sub(V4L2Event::Type::FrameSync);
+ csi2_->setEventsEnabled(sub, false);
ret = output_->streamOff();
@@ -1393,7 +1393,8 @@ int PipelineHandlerMaliC55::start(Camera *camera, [[maybe_unused]] const Control
return ret;
}
- ret = isp_->setFrameStartEnabled(true);
+ V4L2EventSubscription sub(V4L2Event::Type::FrameSync);
+ ret = isp_->setEventsEnabled(sub, true);
if (ret)
LOG(MaliC55, Error) << "Failed to enable frame start events";
@@ -1404,7 +1405,8 @@ void PipelineHandlerMaliC55::stopDevice(Camera *camera)
{
MaliC55CameraData *data = cameraData(camera);
- isp_->setFrameStartEnabled(false);
+ V4L2EventSubscription sub(V4L2Event::Type::FrameSync);
+ isp_->setEventsEnabled(sub, false);
if (auto *mem = std::get_if<MaliC55CameraData::Memory>(&data->input_)) {
ivc_->streamOff();
@@ -1305,7 +1305,8 @@ int PipelineHandlerRkISP1::start(Camera *camera, [[maybe_unused]] const ControlL
return ret;
}
- isp_->setFrameStartEnabled(true);
+ V4L2EventSubscription sub(V4L2Event::Type::FrameSync);
+ isp_->setEventsEnabled(sub, true);
activeCamera_ = camera;
@@ -1318,7 +1319,8 @@ void PipelineHandlerRkISP1::stopDevice(Camera *camera)
RkISP1CameraData *data = cameraData(camera);
int ret;
- isp_->setFrameStartEnabled(false);
+ V4L2EventSubscription sub(V4L2Event::Type::FrameSync);
+ isp_->setEventsEnabled(sub, false);
data->ipa_->stop();
@@ -1654,7 +1656,7 @@ void PipelineHandlerRkISP1::imageBufferReady(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::FrameSync signal.
*/
request->_d()->metadata().set(controls::SensorTimestamp,
metadata.timestamp);
@@ -703,7 +703,8 @@ int PipelineHandlerBase::start(Camera *camera, const ControlList *controls)
data->state_ = CameraData::State::Idle;
/* Enable SOF event generation. */
- data->frontendDevice()->setFrameStartEnabled(true);
+ V4L2EventSubscription sub(V4L2Event::Type::FrameSync);
+ data->frontendDevice()->setEventsEnabled(sub, true);
data->platformStart();
@@ -732,7 +733,8 @@ void PipelineHandlerBase::stopDevice(Camera *camera)
}
/* Disable SOF event generation. */
- data->frontendDevice()->setFrameStartEnabled(false);
+ V4L2EventSubscription sub(V4L2Event::Type::FrameSync);
+ data->frontendDevice()->setEventsEnabled(sub, false);
data->clearIncompleteRequests();
@@ -1679,7 +1679,8 @@ int SimplePipelineHandler::start(Camera *camera, [[maybe_unused]] const ControlL
data->delayedCtrls_->reset();
if (frameStartEmitter) {
- ret = frameStartEmitter->setFrameStartEnabled(true);
+ V4L2EventSubscription sub(V4L2Event::Type::FrameSync);
+ ret = frameStartEmitter->setEventsEnabled(sub, true);
if (ret) {
stop(camera);
return ret;
@@ -1723,7 +1724,8 @@ void SimplePipelineHandler::stopDevice(Camera *camera)
V4L2Subdevice *frameStartEmitter = data->frameStartEmitter_;
if (frameStartEmitter) {
- frameStartEmitter->setFrameStartEnabled(false);
+ V4L2EventSubscription sub(V4L2Event::Type::FrameSync);
+ frameStartEmitter->setEventsEnabled(sub, false);
frameStartEmitter->eventReady.connect(data,
&SimpleCameraData::handleEvent);
}
@@ -58,8 +58,7 @@ LOG_DEFINE_CATEGORY(V4L2)
* at open() time, and the \a logTag to prefix log messages with.
*/
V4L2Device::V4L2Device(const std::string &deviceNode)
- : deviceNode_(deviceNode), fdEventNotifier_(nullptr),
- frameStartEnabled_(false)
+ : deviceNode_(deviceNode), fdEventNotifier_(nullptr)
{
}
@@ -499,21 +498,32 @@ bool V4L2Device::supportsEvents(V4L2EventSubscription &sub)
}
/**
- * \brief Enable or disable frame start event notification
+ * \brief Enable or event notifications
+ * \param[in] sub Details of the event to subscribe to
* \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 eventReady signal.
+ * This function enables or disables generation of events for a particular
+ * subscriptions. Once enabled, the events are signalled through the eventReady
+ * signal.
*
* \return 0 on success, a negative error code otherwise
*/
-int V4L2Device::setFrameStartEnabled(bool enable)
+int V4L2Device::setEventsEnabled(V4L2EventSubscription &sub, bool enable)
{
- if (frameStartEnabled_ == enable)
+ if (sub.type() >= V4L2Event::Type::NumberOfEventTypes)
+ return -EINVAL;
+
+ if (subscribedEvents_.find(sub) != subscribedEvents_.end())
return 0;
struct v4l2_event_subscription event{};
- event.type = V4L2_EVENT_FRAME_SYNC;
+
+ auto v4l2EventType = V4L2Event::typeToV4L2(sub.type());
+ if (!v4l2EventType)
+ return -EINVAL;
+
+ event.type = *v4l2EventType;
+ event.id = sub.id();
unsigned long request = enable ? VIDIOC_SUBSCRIBE_EVENT
: VIDIOC_UNSUBSCRIBE_EVENT;
@@ -522,7 +532,11 @@ int V4L2Device::setFrameStartEnabled(bool enable)
return ret;
fdEventNotifier_->setEnabled(enable);
- frameStartEnabled_ = enable;
+
+ if (enable)
+ subscribedEvents_.insert(sub);
+ else
+ subscribedEvents_.erase(sub);
return ret;
}
The current implementation of V4L2Device::setFrameStartEnabled hard codes V4L2_EVENT_FRAME_SYNC as it passes the subscription to the kernel. Re-work the function such that the subcription details are parametised. This will allow consumers to suscribe to any supported events. Signed-off-by: Daniel Scally <dan.scally@ideasonboard.com> --- include/libcamera/internal/v4l2_device.h | 5 ++-- src/libcamera/pipeline/ipu3/cio2.cpp | 6 ++-- src/libcamera/pipeline/mali-c55/mali-c55.cpp | 6 ++-- src/libcamera/pipeline/rkisp1/rkisp1.cpp | 8 ++++-- .../pipeline/rpi/common/pipeline_base.cpp | 6 ++-- src/libcamera/pipeline/simple/simple.cpp | 6 ++-- src/libcamera/v4l2_device.cpp | 32 ++++++++++++++++------ 7 files changed, 47 insertions(+), 22 deletions(-)