libcamera: v4l2_device: Move start of frame detection to V4L2Device
The V4L2_EVENT_FRAME_SYNC event may occur on both V4L2 video-devices (V4L2VideoDevice) and sub-devices (V4L2Subdevice). Move the start of frame detection to the common base class of the two, V4L2Device. There is no functional change. Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
This commit is contained in:
parent
68d2c41835
commit
3d624b745b
4 changed files with 87 additions and 84 deletions
|
@ -13,11 +13,15 @@
|
||||||
|
|
||||||
#include <linux/videodev2.h>
|
#include <linux/videodev2.h>
|
||||||
|
|
||||||
|
#include <libcamera/signal.h>
|
||||||
|
|
||||||
#include "libcamera/internal/log.h"
|
#include "libcamera/internal/log.h"
|
||||||
#include "libcamera/internal/v4l2_controls.h"
|
#include "libcamera/internal/v4l2_controls.h"
|
||||||
|
|
||||||
namespace libcamera {
|
namespace libcamera {
|
||||||
|
|
||||||
|
class EventNotifier;
|
||||||
|
|
||||||
class V4L2Device : protected Loggable
|
class V4L2Device : protected Loggable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -34,6 +38,9 @@ public:
|
||||||
const std::string &deviceNode() const { return deviceNode_; }
|
const std::string &deviceNode() const { return deviceNode_; }
|
||||||
std::string devicePath() const;
|
std::string devicePath() const;
|
||||||
|
|
||||||
|
int setFrameStartEnabled(bool enable);
|
||||||
|
Signal<uint32_t> frameStart;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
V4L2Device(const std::string &deviceNode);
|
V4L2Device(const std::string &deviceNode);
|
||||||
~V4L2Device();
|
~V4L2Device();
|
||||||
|
@ -51,11 +58,16 @@ private:
|
||||||
const struct v4l2_ext_control *v4l2Ctrls,
|
const struct v4l2_ext_control *v4l2Ctrls,
|
||||||
unsigned int count);
|
unsigned int count);
|
||||||
|
|
||||||
|
void eventAvailable(EventNotifier *notifier);
|
||||||
|
|
||||||
std::map<unsigned int, struct v4l2_query_ext_ctrl> controlInfo_;
|
std::map<unsigned int, struct v4l2_query_ext_ctrl> controlInfo_;
|
||||||
std::vector<std::unique_ptr<V4L2ControlId>> controlIds_;
|
std::vector<std::unique_ptr<V4L2ControlId>> controlIds_;
|
||||||
ControlInfoMap controls_;
|
ControlInfoMap controls_;
|
||||||
std::string deviceNode_;
|
std::string deviceNode_;
|
||||||
int fd_;
|
int fd_;
|
||||||
|
|
||||||
|
EventNotifier *fdEventNotifier_;
|
||||||
|
bool frameStartEnabled_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} /* namespace libcamera */
|
} /* namespace libcamera */
|
||||||
|
|
|
@ -207,9 +207,6 @@ public:
|
||||||
int queueBuffer(FrameBuffer *buffer);
|
int queueBuffer(FrameBuffer *buffer);
|
||||||
Signal<FrameBuffer *> bufferReady;
|
Signal<FrameBuffer *> bufferReady;
|
||||||
|
|
||||||
int setFrameStartEnabled(bool enable);
|
|
||||||
Signal<uint32_t> frameStart;
|
|
||||||
|
|
||||||
int streamOn();
|
int streamOn();
|
||||||
int streamOff();
|
int streamOff();
|
||||||
|
|
||||||
|
@ -243,8 +240,6 @@ private:
|
||||||
void bufferAvailable(EventNotifier *notifier);
|
void bufferAvailable(EventNotifier *notifier);
|
||||||
FrameBuffer *dequeueBuffer();
|
FrameBuffer *dequeueBuffer();
|
||||||
|
|
||||||
void eventAvailable(EventNotifier *notifier);
|
|
||||||
|
|
||||||
V4L2Capability caps_;
|
V4L2Capability caps_;
|
||||||
|
|
||||||
enum v4l2_buf_type bufferType_;
|
enum v4l2_buf_type bufferType_;
|
||||||
|
@ -254,9 +249,6 @@ private:
|
||||||
std::map<unsigned int, FrameBuffer *> queuedBuffers_;
|
std::map<unsigned int, FrameBuffer *> queuedBuffers_;
|
||||||
|
|
||||||
EventNotifier *fdBufferNotifier_;
|
EventNotifier *fdBufferNotifier_;
|
||||||
EventNotifier *fdEventNotifier_;
|
|
||||||
|
|
||||||
bool frameStartEnabled_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class V4L2M2MDevice
|
class V4L2M2MDevice
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <libcamera/event_notifier.h>
|
||||||
|
|
||||||
#include "libcamera/internal/log.h"
|
#include "libcamera/internal/log.h"
|
||||||
#include "libcamera/internal/sysfs.h"
|
#include "libcamera/internal/sysfs.h"
|
||||||
#include "libcamera/internal/utils.h"
|
#include "libcamera/internal/utils.h"
|
||||||
|
@ -52,7 +54,8 @@ LOG_DEFINE_CATEGORY(V4L2)
|
||||||
* at open() time, and the \a logTag to prefix log messages with.
|
* at open() time, and the \a logTag to prefix log messages with.
|
||||||
*/
|
*/
|
||||||
V4L2Device::V4L2Device(const std::string &deviceNode)
|
V4L2Device::V4L2Device(const std::string &deviceNode)
|
||||||
: deviceNode_(deviceNode), fd_(-1)
|
: deviceNode_(deviceNode), fd_(-1), fdEventNotifier_(nullptr),
|
||||||
|
frameStartEnabled_(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +90,7 @@ int V4L2Device::open(unsigned int flags)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
fd_ = ret;
|
setFd(ret);
|
||||||
|
|
||||||
listControls();
|
listControls();
|
||||||
|
|
||||||
|
@ -117,6 +120,10 @@ int V4L2Device::setFd(int fd)
|
||||||
|
|
||||||
fd_ = fd;
|
fd_ = fd;
|
||||||
|
|
||||||
|
fdEventNotifier_ = new EventNotifier(fd_, EventNotifier::Exception);
|
||||||
|
fdEventNotifier_->activated.connect(this, &V4L2Device::eventAvailable);
|
||||||
|
fdEventNotifier_->setEnabled(false);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,6 +137,8 @@ void V4L2Device::close()
|
||||||
if (!isOpen())
|
if (!isOpen())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
delete fdEventNotifier_;
|
||||||
|
|
||||||
if (::close(fd_) < 0)
|
if (::close(fd_) < 0)
|
||||||
LOG(V4L2, Error) << "Failed to close V4L2 device: "
|
LOG(V4L2, Error) << "Failed to close V4L2 device: "
|
||||||
<< strerror(errno);
|
<< strerror(errno);
|
||||||
|
@ -395,6 +404,40 @@ std::string V4L2Device::devicePath() const
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Enable or disable frame start event notification
|
||||||
|
* \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.
|
||||||
|
*
|
||||||
|
* \return 0 on success, a negative error code otherwise
|
||||||
|
*/
|
||||||
|
int V4L2Device::setFrameStartEnabled(bool enable)
|
||||||
|
{
|
||||||
|
if (frameStartEnabled_ == enable)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
struct v4l2_event_subscription event{};
|
||||||
|
event.type = V4L2_EVENT_FRAME_SYNC;
|
||||||
|
|
||||||
|
unsigned long request = enable ? VIDIOC_SUBSCRIBE_EVENT
|
||||||
|
: VIDIOC_UNSUBSCRIBE_EVENT;
|
||||||
|
int ret = ioctl(request, &event);
|
||||||
|
if (enable && ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
fdEventNotifier_->setEnabled(enable);
|
||||||
|
frameStartEnabled_ = enable;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \var V4L2Device::frameStart
|
||||||
|
* \brief A Signal emitted when capture of a frame has started
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Perform an IOCTL system call on the device node
|
* \brief Perform an IOCTL system call on the device node
|
||||||
* \param[in] request The IOCTL request code
|
* \param[in] request The IOCTL request code
|
||||||
|
@ -518,4 +561,33 @@ void V4L2Device::updateControls(ControlList *ctrls,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Slot to handle V4L2 events from the V4L2 device
|
||||||
|
* \param[in] notifier The event notifier
|
||||||
|
*
|
||||||
|
* When this slot is called, a V4L2 event is available to be dequeued from the
|
||||||
|
* device.
|
||||||
|
*/
|
||||||
|
void V4L2Device::eventAvailable([[maybe_unused]] EventNotifier *notifier)
|
||||||
|
{
|
||||||
|
struct v4l2_event event{};
|
||||||
|
int ret = ioctl(VIDIOC_DQEVENT, &event);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG(V4L2, Error)
|
||||||
|
<< "Failed to dequeue event, disabling event notifier";
|
||||||
|
fdEventNotifier_->setEnabled(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.type != V4L2_EVENT_FRAME_SYNC) {
|
||||||
|
LOG(V4L2, Error)
|
||||||
|
<< "Spurious event (" << event.type
|
||||||
|
<< "), disabling event notifier";
|
||||||
|
fdEventNotifier_->setEnabled(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
frameStart.emit(event.u.frame_sync.frame_sequence);
|
||||||
|
}
|
||||||
|
|
||||||
} /* namespace libcamera */
|
} /* namespace libcamera */
|
||||||
|
|
|
@ -481,8 +481,7 @@ const std::string V4L2DeviceFormat::toString() const
|
||||||
* \param[in] deviceNode The file-system path to the video device node
|
* \param[in] deviceNode The file-system path to the video device node
|
||||||
*/
|
*/
|
||||||
V4L2VideoDevice::V4L2VideoDevice(const std::string &deviceNode)
|
V4L2VideoDevice::V4L2VideoDevice(const std::string &deviceNode)
|
||||||
: V4L2Device(deviceNode), cache_(nullptr), fdBufferNotifier_(nullptr),
|
: V4L2Device(deviceNode), cache_(nullptr), fdBufferNotifier_(nullptr)
|
||||||
fdEventNotifier_(nullptr), frameStartEnabled_(false)
|
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* We default to an MMAP based CAPTURE video device, however this will
|
* We default to an MMAP based CAPTURE video device, however this will
|
||||||
|
@ -575,10 +574,6 @@ int V4L2VideoDevice::open()
|
||||||
fdBufferNotifier_->activated.connect(this, &V4L2VideoDevice::bufferAvailable);
|
fdBufferNotifier_->activated.connect(this, &V4L2VideoDevice::bufferAvailable);
|
||||||
fdBufferNotifier_->setEnabled(false);
|
fdBufferNotifier_->setEnabled(false);
|
||||||
|
|
||||||
fdEventNotifier_ = new EventNotifier(fd(), EventNotifier::Exception);
|
|
||||||
fdEventNotifier_->activated.connect(this, &V4L2VideoDevice::eventAvailable);
|
|
||||||
fdEventNotifier_->setEnabled(false);
|
|
||||||
|
|
||||||
LOG(V4L2, Debug)
|
LOG(V4L2, Debug)
|
||||||
<< "Opened device " << caps_.bus_info() << ": "
|
<< "Opened device " << caps_.bus_info() << ": "
|
||||||
<< caps_.driver() << ": " << caps_.card();
|
<< caps_.driver() << ": " << caps_.card();
|
||||||
|
@ -668,10 +663,6 @@ int V4L2VideoDevice::open(int handle, enum v4l2_buf_type type)
|
||||||
fdBufferNotifier_->activated.connect(this, &V4L2VideoDevice::bufferAvailable);
|
fdBufferNotifier_->activated.connect(this, &V4L2VideoDevice::bufferAvailable);
|
||||||
fdBufferNotifier_->setEnabled(false);
|
fdBufferNotifier_->setEnabled(false);
|
||||||
|
|
||||||
fdEventNotifier_ = new EventNotifier(fd(), EventNotifier::Exception);
|
|
||||||
fdEventNotifier_->activated.connect(this, &V4L2VideoDevice::eventAvailable);
|
|
||||||
fdEventNotifier_->setEnabled(false);
|
|
||||||
|
|
||||||
LOG(V4L2, Debug)
|
LOG(V4L2, Debug)
|
||||||
<< "Opened device " << caps_.bus_info() << ": "
|
<< "Opened device " << caps_.bus_info() << ": "
|
||||||
<< caps_.driver() << ": " << caps_.card();
|
<< caps_.driver() << ": " << caps_.card();
|
||||||
|
@ -689,7 +680,6 @@ void V4L2VideoDevice::close()
|
||||||
|
|
||||||
releaseBuffers();
|
releaseBuffers();
|
||||||
delete fdBufferNotifier_;
|
delete fdBufferNotifier_;
|
||||||
delete fdEventNotifier_;
|
|
||||||
|
|
||||||
V4L2Device::close();
|
V4L2Device::close();
|
||||||
}
|
}
|
||||||
|
@ -1544,74 +1534,11 @@ FrameBuffer *V4L2VideoDevice::dequeueBuffer()
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Slot to handle V4L2 events from the V4L2 video device
|
|
||||||
* \param[in] notifier The event notifier
|
|
||||||
*
|
|
||||||
* When this slot is called, a V4L2 event is available to be dequeued from the
|
|
||||||
* device.
|
|
||||||
*/
|
|
||||||
void V4L2VideoDevice::eventAvailable([[maybe_unused]] EventNotifier *notifier)
|
|
||||||
{
|
|
||||||
struct v4l2_event event{};
|
|
||||||
int ret = ioctl(VIDIOC_DQEVENT, &event);
|
|
||||||
if (ret < 0) {
|
|
||||||
LOG(V4L2, Error)
|
|
||||||
<< "Failed to dequeue event, disabling event notifier";
|
|
||||||
fdEventNotifier_->setEnabled(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.type != V4L2_EVENT_FRAME_SYNC) {
|
|
||||||
LOG(V4L2, Error)
|
|
||||||
<< "Spurious event (" << event.type
|
|
||||||
<< "), disabling event notifier";
|
|
||||||
fdEventNotifier_->setEnabled(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
frameStart.emit(event.u.frame_sync.frame_sequence);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \var V4L2VideoDevice::bufferReady
|
* \var V4L2VideoDevice::bufferReady
|
||||||
* \brief A Signal emitted when a framebuffer completes
|
* \brief A Signal emitted when a framebuffer completes
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Enable or disable frame start event notification
|
|
||||||
* \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.
|
|
||||||
*
|
|
||||||
* \return 0 on success, a negative error code otherwise
|
|
||||||
*/
|
|
||||||
int V4L2VideoDevice::setFrameStartEnabled(bool enable)
|
|
||||||
{
|
|
||||||
if (frameStartEnabled_ == enable)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
struct v4l2_event_subscription event{};
|
|
||||||
event.type = V4L2_EVENT_FRAME_SYNC;
|
|
||||||
|
|
||||||
unsigned long request = enable ? VIDIOC_SUBSCRIBE_EVENT
|
|
||||||
: VIDIOC_UNSUBSCRIBE_EVENT;
|
|
||||||
int ret = ioctl(request, &event);
|
|
||||||
if (enable && ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
fdEventNotifier_->setEnabled(enable);
|
|
||||||
frameStartEnabled_ = enable;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \var V4L2VideoDevice::frameStart
|
|
||||||
* \brief A Signal emitted when capture of a frame has started
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Start the video stream
|
* \brief Start the video stream
|
||||||
* \return 0 on success or a negative error code otherwise
|
* \return 0 on success or a negative error code otherwise
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue