summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNaushir Patuck <naush@raspberrypi.com>2022-04-06 13:35:52 +0100
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2022-04-06 15:44:32 +0300
commit16f3d2de50ffa35295240e247d8cc4cffabf1a53 (patch)
tree846a0a74e66389f4528e976bee0ea4ca76fecff2
parent226792a1411bd485e087bf40e241611966099b52 (diff)
libcamera: v4l2_videodevice: Add a dequeue timer
Add a timer that gets reset on every buffer dequeue event. If the timeout expires, optionally call a slot in the pipeline handler to handle this condition. This may be useful in detecting and handling stalls in either the hardware or device driver. Signed-off-by: Naushir Patuck <naush@raspberrypi.com> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
-rw-r--r--include/libcamera/internal/v4l2_videodevice.h10
-rw-r--r--src/libcamera/v4l2_videodevice.cpp53
2 files changed, 63 insertions, 0 deletions
diff --git a/include/libcamera/internal/v4l2_videodevice.h b/include/libcamera/internal/v4l2_videodevice.h
index cfeae7bd..9c9493cc 100644
--- a/include/libcamera/internal/v4l2_videodevice.h
+++ b/include/libcamera/internal/v4l2_videodevice.h
@@ -20,7 +20,9 @@
#include <libcamera/base/class.h>
#include <libcamera/base/log.h>
#include <libcamera/base/signal.h>
+#include <libcamera/base/timer.h>
#include <libcamera/base/unique_fd.h>
+#include <libcamera/base/utils.h>
#include <libcamera/color_space.h>
#include <libcamera/framebuffer.h>
@@ -217,6 +219,9 @@ public:
int streamOn();
int streamOff();
+ void setDequeueTimeout(utils::Duration timeout);
+ Signal<> dequeueTimeout;
+
static std::unique_ptr<V4L2VideoDevice>
fromEntityName(const MediaDevice *media, const std::string &entity);
@@ -253,6 +258,8 @@ private:
void bufferAvailable();
FrameBuffer *dequeueBuffer();
+ void watchdogExpired();
+
V4L2Capability caps_;
V4L2DeviceFormat format_;
const PixelFormatInfo *formatInfo_;
@@ -266,6 +273,9 @@ private:
EventNotifier *fdBufferNotifier_;
State state_;
+
+ Timer watchdog_;
+ utils::Duration watchdogDuration_;
};
class V4L2M2MDevice
diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp
index 0830be80..c3a1b6c4 100644
--- a/src/libcamera/v4l2_videodevice.cpp
+++ b/src/libcamera/v4l2_videodevice.cpp
@@ -539,6 +539,7 @@ V4L2VideoDevice::V4L2VideoDevice(const std::string &deviceNode)
V4L2VideoDevice::V4L2VideoDevice(const MediaEntity *entity)
: V4L2VideoDevice(entity->deviceNode())
{
+ watchdog_.timeout.connect(this, &V4L2VideoDevice::watchdogExpired);
}
V4L2VideoDevice::~V4L2VideoDevice()
@@ -1726,6 +1727,9 @@ FrameBuffer *V4L2VideoDevice::dequeueBuffer()
return nullptr;
}
+ if (watchdogDuration_.count())
+ watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));
+
cache_->put(buf.index);
FrameBuffer *buffer = it->second;
@@ -1828,6 +1832,8 @@ int V4L2VideoDevice::streamOn()
}
state_ = State::Streaming;
+ if (watchdogDuration_.count())
+ watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));
return 0;
}
@@ -1852,6 +1858,9 @@ int V4L2VideoDevice::streamOff()
if (state_ != State::Streaming && queuedBuffers_.empty())
return 0;
+ if (watchdogDuration_.count())
+ watchdog_.stop();
+
ret = ioctl(VIDIOC_STREAMOFF, &bufferType_);
if (ret < 0) {
LOG(V4L2, Error)
@@ -1880,6 +1889,50 @@ int V4L2VideoDevice::streamOff()
}
/**
+ * \brief Set the dequeue timeout value
+ * \param[in] timeout The timeout value to be used
+ *
+ * Sets a timeout value, given by \a timeout, that will be used by a watchdog
+ * timer to ensure buffer dequeue events are periodically occurring when the
+ * device is streaming. The watchdog timer is only active when the device is
+ * streaming, so it is not necessary to disable it when the device stops
+ * streaming. The timeout value can be safely updated at any time.
+ *
+ * If the timer expires, the \ref V4L2VideoDevice::dequeueTimeout signal is
+ * emitted. This can typically be used by pipeline handlers to be notified of
+ * stalled devices.
+ *
+ * Set \a timeout to 0 to disable the watchdog timer.
+ */
+void V4L2VideoDevice::setDequeueTimeout(utils::Duration timeout)
+{
+ watchdogDuration_ = timeout;
+
+ watchdog_.stop();
+ if (watchdogDuration_.count() && state_ == State::Streaming)
+ watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(timeout));
+}
+
+/**
+ * \var V4L2VideoDevice::dequeueTimeout
+ * \brief A Signal emitted when the dequeue watchdog timer expires
+ */
+
+/**
+ * \brief Slot to handle an expired dequeue timer
+ *
+ * When this slot is called, the time between successive dequeue events is over
+ * the required timeout. Emit the \ref V4L2VideoDevice::dequeueTimeout signal.
+ */
+void V4L2VideoDevice::watchdogExpired()
+{
+ LOG(V4L2, Warning)
+ << "Dequeue timer of " << watchdogDuration_ << " has expired!";
+
+ dequeueTimeout.emit();
+}
+
+/**
* \brief Create a new video device instance from \a entity in media device
* \a media
* \param[in] media The media device where the entity is registered