mirror of
https://git.libcamera.org/libcamera/libcamera.git
synced 2025-07-14 16:09:51 +03:00
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>
This commit is contained in:
parent
226792a141
commit
16f3d2de50
2 changed files with 63 additions and 0 deletions
|
@ -20,7 +20,9 @@
|
||||||
#include <libcamera/base/class.h>
|
#include <libcamera/base/class.h>
|
||||||
#include <libcamera/base/log.h>
|
#include <libcamera/base/log.h>
|
||||||
#include <libcamera/base/signal.h>
|
#include <libcamera/base/signal.h>
|
||||||
|
#include <libcamera/base/timer.h>
|
||||||
#include <libcamera/base/unique_fd.h>
|
#include <libcamera/base/unique_fd.h>
|
||||||
|
#include <libcamera/base/utils.h>
|
||||||
|
|
||||||
#include <libcamera/color_space.h>
|
#include <libcamera/color_space.h>
|
||||||
#include <libcamera/framebuffer.h>
|
#include <libcamera/framebuffer.h>
|
||||||
|
@ -217,6 +219,9 @@ public:
|
||||||
int streamOn();
|
int streamOn();
|
||||||
int streamOff();
|
int streamOff();
|
||||||
|
|
||||||
|
void setDequeueTimeout(utils::Duration timeout);
|
||||||
|
Signal<> dequeueTimeout;
|
||||||
|
|
||||||
static std::unique_ptr<V4L2VideoDevice>
|
static std::unique_ptr<V4L2VideoDevice>
|
||||||
fromEntityName(const MediaDevice *media, const std::string &entity);
|
fromEntityName(const MediaDevice *media, const std::string &entity);
|
||||||
|
|
||||||
|
@ -253,6 +258,8 @@ private:
|
||||||
void bufferAvailable();
|
void bufferAvailable();
|
||||||
FrameBuffer *dequeueBuffer();
|
FrameBuffer *dequeueBuffer();
|
||||||
|
|
||||||
|
void watchdogExpired();
|
||||||
|
|
||||||
V4L2Capability caps_;
|
V4L2Capability caps_;
|
||||||
V4L2DeviceFormat format_;
|
V4L2DeviceFormat format_;
|
||||||
const PixelFormatInfo *formatInfo_;
|
const PixelFormatInfo *formatInfo_;
|
||||||
|
@ -266,6 +273,9 @@ private:
|
||||||
EventNotifier *fdBufferNotifier_;
|
EventNotifier *fdBufferNotifier_;
|
||||||
|
|
||||||
State state_;
|
State state_;
|
||||||
|
|
||||||
|
Timer watchdog_;
|
||||||
|
utils::Duration watchdogDuration_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class V4L2M2MDevice
|
class V4L2M2MDevice
|
||||||
|
|
|
@ -539,6 +539,7 @@ V4L2VideoDevice::V4L2VideoDevice(const std::string &deviceNode)
|
||||||
V4L2VideoDevice::V4L2VideoDevice(const MediaEntity *entity)
|
V4L2VideoDevice::V4L2VideoDevice(const MediaEntity *entity)
|
||||||
: V4L2VideoDevice(entity->deviceNode())
|
: V4L2VideoDevice(entity->deviceNode())
|
||||||
{
|
{
|
||||||
|
watchdog_.timeout.connect(this, &V4L2VideoDevice::watchdogExpired);
|
||||||
}
|
}
|
||||||
|
|
||||||
V4L2VideoDevice::~V4L2VideoDevice()
|
V4L2VideoDevice::~V4L2VideoDevice()
|
||||||
|
@ -1726,6 +1727,9 @@ FrameBuffer *V4L2VideoDevice::dequeueBuffer()
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (watchdogDuration_.count())
|
||||||
|
watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));
|
||||||
|
|
||||||
cache_->put(buf.index);
|
cache_->put(buf.index);
|
||||||
|
|
||||||
FrameBuffer *buffer = it->second;
|
FrameBuffer *buffer = it->second;
|
||||||
|
@ -1828,6 +1832,8 @@ int V4L2VideoDevice::streamOn()
|
||||||
}
|
}
|
||||||
|
|
||||||
state_ = State::Streaming;
|
state_ = State::Streaming;
|
||||||
|
if (watchdogDuration_.count())
|
||||||
|
watchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1852,6 +1858,9 @@ int V4L2VideoDevice::streamOff()
|
||||||
if (state_ != State::Streaming && queuedBuffers_.empty())
|
if (state_ != State::Streaming && queuedBuffers_.empty())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (watchdogDuration_.count())
|
||||||
|
watchdog_.stop();
|
||||||
|
|
||||||
ret = ioctl(VIDIOC_STREAMOFF, &bufferType_);
|
ret = ioctl(VIDIOC_STREAMOFF, &bufferType_);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
LOG(V4L2, Error)
|
LOG(V4L2, Error)
|
||||||
|
@ -1879,6 +1888,50 @@ int V4L2VideoDevice::streamOff()
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \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
|
* \brief Create a new video device instance from \a entity in media device
|
||||||
* \a media
|
* \a media
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue