@@ -10,6 +10,7 @@
#include <map>
#include <memory>
#include <optional>
+#include <set>
#include <span>
#include <stdint.h>
#include <vector>
@@ -47,7 +48,7 @@ public:
std::string devicePath() const;
bool supportsEvents(v4l2_event_subscription &sub);
- int setFrameStartEnabled(bool enable);
+ int setEventsEnabled(v4l2_event_subscription &sub, bool enable);
Signal<const v4l2_event &> eventReady;
void updateControlInfo();
@@ -90,7 +91,7 @@ private:
UniqueFD fd_;
std::unique_ptr<EventNotifier> fdEventNotifier_;
- bool frameStartEnabled_;
+ std::set<std::tuple<uint32_t, uint32_t>> subscribedEvents_;
};
} /* namespace libcamera */
@@ -356,7 +356,10 @@ int CIO2Device::start()
return ret;
}
- ret = csi2_->setFrameStartEnabled(true);
+ v4l2_event_subscription sub{};
+ sub.type = V4L2_EVENT_FRAME_SYNC;
+
+ ret = csi2_->setEventsEnabled(sub, true);
if (ret) {
stop();
return ret;
@@ -367,9 +370,11 @@ int CIO2Device::start()
int CIO2Device::stop()
{
+ v4l2_event_subscription sub{};
int ret;
- csi2_->setFrameStartEnabled(false);
+ sub.type = V4L2_EVENT_FRAME_SYNC;
+ csi2_->setEventsEnabled(sub, false);
ret = output_->streamOff();
@@ -1393,7 +1393,10 @@ int PipelineHandlerMaliC55::start(Camera *camera, [[maybe_unused]] const Control
return ret;
}
- ret = isp_->setFrameStartEnabled(true);
+ v4l2_event_subscription sub{};
+ sub.type = V4L2_EVENT_FRAME_SYNC;
+
+ ret = isp_->setEventsEnabled(sub, true);
if (ret)
LOG(MaliC55, Error) << "Failed to enable frame start events";
@@ -1404,7 +1407,10 @@ void PipelineHandlerMaliC55::stopDevice(Camera *camera)
{
MaliC55CameraData *data = cameraData(camera);
- isp_->setFrameStartEnabled(false);
+ v4l2_event_subscription sub{};
+ sub.type = V4L2_EVENT_FRAME_SYNC;
+
+ isp_->setEventsEnabled(sub, false);
if (auto *mem = std::get_if<MaliC55CameraData::Memory>(&data->input_)) {
ivc_->streamOff();
@@ -1304,7 +1304,9 @@ int PipelineHandlerRkISP1::start(Camera *camera, [[maybe_unused]] const ControlL
return ret;
}
- isp_->setFrameStartEnabled(true);
+ v4l2_event_subscription sub{};
+ sub.type = V4L2_EVENT_FRAME_SYNC;
+ isp_->setEventsEnabled(sub, true);
activeCamera_ = camera;
@@ -1317,7 +1319,9 @@ void PipelineHandlerRkISP1::stopDevice(Camera *camera)
RkISP1CameraData *data = cameraData(camera);
int ret;
- isp_->setFrameStartEnabled(false);
+ v4l2_event_subscription sub{};
+ sub.type = V4L2_EVENT_FRAME_SYNC;
+ isp_->setEventsEnabled(sub, false);
data->ipa_->stop();
@@ -1653,7 +1657,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);
@@ -702,7 +702,9 @@ int PipelineHandlerBase::start(Camera *camera, const ControlList *controls)
data->state_ = CameraData::State::Idle;
/* Enable SOF event generation. */
- data->frontendDevice()->setFrameStartEnabled(true);
+ v4l2_event_subscription sub{};
+ sub.type = V4L2_EVENT_FRAME_SYNC;
+ data->frontendDevice()->setEventsEnabled(sub, true);
data->platformStart();
@@ -731,7 +733,9 @@ void PipelineHandlerBase::stopDevice(Camera *camera)
}
/* Disable SOF event generation. */
- data->frontendDevice()->setFrameStartEnabled(false);
+ v4l2_event_subscription sub{};
+ sub.type = V4L2_EVENT_FRAME_SYNC;
+ data->frontendDevice()->setEventsEnabled(sub, false);
data->clearIncompleteRequests();
@@ -1682,7 +1682,9 @@ int SimplePipelineHandler::start(Camera *camera, [[maybe_unused]] const ControlL
data->delayedCtrls_->reset();
if (frameStartEmitter) {
- ret = frameStartEmitter->setFrameStartEnabled(true);
+ v4l2_event_subscription sub{};
+ sub.type = V4L2_EVENT_FRAME_SYNC;
+ ret = frameStartEmitter->setEventsEnabled(sub, true);
if (ret) {
stop(camera);
return ret;
@@ -1726,7 +1728,9 @@ void SimplePipelineHandler::stopDevice(Camera *camera)
V4L2Subdevice *frameStartEmitter = data->frameStartEmitter_;
if (frameStartEmitter) {
- frameStartEmitter->setFrameStartEnabled(false);
+ v4l2_event_subscription sub{};
+ sub.type = V4L2_EVENT_FRAME_SYNC;
+ frameStartEmitter->setEventsEnabled(sub, false);
frameStartEmitter->eventReady.connect(data,
&SimpleCameraData::handleEvent);
}
@@ -57,8 +57,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)
{
}
@@ -489,30 +488,35 @@ bool V4L2Device::supportsEvents(v4l2_event_subscription &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(v4l2_event_subscription &sub, bool enable)
{
- if (frameStartEnabled_ == enable)
- return 0;
+ std::tuple<uint32_t, uint32_t> subTypeId(sub.type, sub.id);
- struct v4l2_event_subscription event{};
- event.type = V4L2_EVENT_FRAME_SYNC;
+ if (subscribedEvents_.contains(subTypeId))
+ return 0;
unsigned long request = enable ? VIDIOC_SUBSCRIBE_EVENT
: VIDIOC_UNSUBSCRIBE_EVENT;
- int ret = ioctl(request, &event);
+ int ret = ioctl(request, &sub);
if (enable && ret)
return ret;
fdEventNotifier_->setEnabled(enable);
- frameStartEnabled_ = enable;
+
+ if (enable)
+ subscribedEvents_.insert(subTypeId);
+ else
+ subscribedEvents_.erase(subTypeId);
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 subscription details are parametised. This will allow consumers to subscribe to any supported events. Signed-off-by: Daniel Scally <dan.scally@ideasonboard.com> --- Changes in v2: - use kernel uAPI directly instead of class V4L2Event and V4L2EventSubscription --- include/libcamera/internal/v4l2_device.h | 5 ++-- src/libcamera/pipeline/ipu3/cio2.cpp | 9 +++++-- src/libcamera/pipeline/mali-c55/mali-c55.cpp | 10 ++++++-- src/libcamera/pipeline/rkisp1/rkisp1.cpp | 10 +++++--- .../pipeline/rpi/common/pipeline_base.cpp | 8 +++++-- src/libcamera/pipeline/simple/simple.cpp | 8 +++++-- src/libcamera/v4l2_device.cpp | 28 ++++++++++++---------- 7 files changed, 53 insertions(+), 25 deletions(-)