Message ID | 20190117212703.24047-2-kieran.bingham@ideasonboard.com |
---|---|
State | Accepted |
Commit | e74f3eebb498634f438a005b2ad5b7f1778091e8 |
Headers | show |
Series |
|
Related | show |
Hi Kieran, Thanks for your persistence with this series :-) On 2019-01-17 21:27:02 +0000, Kieran Bingham wrote: > Provide a helper V4L2 device object capable of interacting with the > V4L2 Linux Kernel APIs. > > Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com> Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se> > --- > src/libcamera/include/v4l2_device.h | 60 +++++++++ > src/libcamera/meson.build | 2 + > src/libcamera/v4l2_device.cpp | 186 ++++++++++++++++++++++++++++ > 3 files changed, 248 insertions(+) > create mode 100644 src/libcamera/include/v4l2_device.h > create mode 100644 src/libcamera/v4l2_device.cpp > > diff --git a/src/libcamera/include/v4l2_device.h b/src/libcamera/include/v4l2_device.h > new file mode 100644 > index 000000000000..474c05b58cef > --- /dev/null > +++ b/src/libcamera/include/v4l2_device.h > @@ -0,0 +1,60 @@ > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > +/* > + * Copyright (C) 2019, Google Inc. > + * > + * v4l2_device.h - V4L2 Device > + */ > +#ifndef __LIBCAMERA_V4L2_DEVICE_H__ > +#define __LIBCAMERA_V4L2_DEVICE_H__ > + > +#include <string> > + > +#include <linux/videodev2.h> > + > +namespace libcamera { > + > +struct V4L2Capability final : v4l2_capability { > + const char *driver() const > + { > + return reinterpret_cast<const char *>(v4l2_capability::driver); > + } > + const char *card() const > + { > + return reinterpret_cast<const char *>(v4l2_capability::card); > + } > + const char *bus_info() const > + { > + return reinterpret_cast<const char *>(v4l2_capability::bus_info); > + } > + > + bool isCapture() const { return capabilities & V4L2_CAP_VIDEO_CAPTURE; } > + bool isOutput() const { return capabilities & V4L2_CAP_VIDEO_OUTPUT; } > + bool hasStreaming() const { return capabilities & V4L2_CAP_STREAMING; } > +}; > + > +class V4L2Device > +{ > +public: > + V4L2Device(const std::string &devnode); > + V4L2Device(const V4L2Device &) = delete; > + ~V4L2Device(); > + > + void operator=(const V4L2Device &) = delete; > + > + int open(); > + bool isOpen() const; > + void close(); > + > + const char *driverName() const { return caps_.driver(); } > + const char *deviceName() const { return caps_.card(); } > + const char *busName() const { return caps_.bus_info(); } > + > +private: > + std::string devnode_; > + int fd_; > + V4L2Capability caps_; > +}; > + > +} /* namespace libcamera */ > + > +#endif /* __LIBCAMERA_V4L2_DEVICE_H__ */ > diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build > index abf9a71d4172..f9f25c0ecf15 100644 > --- a/src/libcamera/meson.build > +++ b/src/libcamera/meson.build > @@ -11,6 +11,7 @@ libcamera_sources = files([ > 'pipeline_handler.cpp', > 'signal.cpp', > 'timer.cpp', > + 'v4l2_device.cpp', > ]) > > libcamera_headers = files([ > @@ -21,6 +22,7 @@ libcamera_headers = files([ > 'include/media_object.h', > 'include/pipeline_handler.h', > 'include/utils.h', > + 'include/v4l2_device.h', > ]) > > libcamera_internal_includes = include_directories('include') > diff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp > new file mode 100644 > index 000000000000..54b53de37510 > --- /dev/null > +++ b/src/libcamera/v4l2_device.cpp > @@ -0,0 +1,186 @@ > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > +/* > + * Copyright (C) 2019, Google Inc. > + * > + * v4l2_device.cpp - V4L2 Device > + */ > + > +#include <fcntl.h> > +#include <string.h> > +#include <sys/ioctl.h> > +#include <sys/mman.h> > +#include <unistd.h> > + > +#include "log.h" > +#include "v4l2_device.h" > + > +/** > + * \file v4l2_device.h > + * \brief V4L2 Device API > + */ > +namespace libcamera { > + > +/** > + * \struct V4L2Capability > + * \brief struct v4l2_capability object wrapper and helpers > + * > + * The V4L2Capability structure manages the information returned by the > + * VIDIOC_QUERYCAP ioctl. > + */ > + > +/** > + * \fn const char *V4L2Capability::driver() > + * \brief Retrieve the driver module name > + * \return The string containing the name of the driver module > + */ > + > +/** > + * \fn const char *V4L2Capability::card() > + * \brief Retrieve the device card name > + * \return The string containing the device name > + */ > + > +/** > + * \fn const char *V4L2Capability::bus_info() > + * \brief Retrieve the location of the device in the system > + * \return The string containing the device location > + */ > + > +/** > + * \fn bool V4L2Capability::isCapture() > + * \brief Identify if the device is capable of capturing video > + * \return True if the device can capture video frames > + */ > + > +/** > + * \fn bool V4L2Capability::isOutput() > + * \brief Identify if the device is capable of outputting video > + * \return True if the device can output video frames > + */ > + > +/** > + * \fn bool V4L2Capability::hasStreaming() > + * \brief Determine if the device can perform Streaming I/O > + * \return True if the device provides Streaming I/O IOCTLs > + */ > + > +/** > + * \class V4L2Device > + * \brief V4L2Device object and API > + * > + * The V4L2 Device API class models an instance of a V4L2 device node. > + * It is constructed with the path to a V4L2 video device node. The device node > + * is only opened upon a call to open() which must be checked for success. > + * > + * The device capabilities are validated when the device is opened and the > + * device is rejected if it is not a suitable V4L2 capture or output device, or > + * if the device does not support streaming I/O. > + * > + * No API call other than open(), isOpen() and close() shall be called on an > + * unopened device instance. > + * > + * Upon destruction any device left open will be closed, and any resources > + * released. > + */ > + > +/** > + * \brief Construct a V4L2Device > + * \param devnode The file-system path to the video device node > + */ > +V4L2Device::V4L2Device(const std::string &devnode) > + : devnode_(devnode), fd_(-1) > +{ > +} > + > +V4L2Device::~V4L2Device() > +{ > + close(); > +} > + > +/** > + * \brief Open a V4L2 device and query its capabilities > + * \return 0 on success, or a negative error code otherwise > + */ > +int V4L2Device::open() > +{ > + int ret; > + > + if (isOpen()) { > + LOG(Error) << "Device already open"; > + return -EBUSY; > + } > + > + ret = ::open(devnode_.c_str(), O_RDWR); > + if (ret < 0) { > + ret = -errno; > + LOG(Error) << "Failed to open V4L2 device '" << devnode_ > + << "': " << strerror(-ret); > + return ret; > + } > + fd_ = ret; > + > + ret = ioctl(fd_, VIDIOC_QUERYCAP, &caps_); > + if (ret < 0) { > + ret = -errno; > + LOG(Error) << "Failed to query device capabilities: " > + << strerror(-ret); > + return ret; > + } > + > + LOG(Debug) << "Opened '" << devnode_ << "' " > + << caps_.bus_info() << ": " << caps_.driver() > + << ": " << caps_.card(); > + > + if (!caps_.isCapture() && !caps_.isOutput()) { > + LOG(Debug) << "Device is not a supported type"; > + return -EINVAL; > + } > + > + if (!caps_.hasStreaming()) { > + LOG(Error) << "Device does not support streaming I/O"; > + return -EINVAL; > + } > + > + return 0; > +} > + > +/** > + * \brief Check if device is successfully opened > + * \return True if the device is open, false otherwise > + */ > +bool V4L2Device::isOpen() const > +{ > + return fd_ != -1; > +} > + > +/** > + * \brief Close the device, releasing any resources acquired by open() > + */ > +void V4L2Device::close() > +{ > + if (fd_ < 0) > + return; > + > + ::close(fd_); > + fd_ = -1; > +} > + > +/** > + * \fn const char *V4L2Device::driverName() > + * \brief Retrieve the name of the V4L2 device driver > + * \return The string containing the driver name > + */ > + > +/** > + * \fn const char *V4L2Device::deviceName() > + * \brief Retrieve the name of the V4L2 device > + * \return The string containing the device name > + */ > + > +/** > + * \fn const char *V4L2Device::busName() > + * \brief Retrieve the location of the device in the system > + * \return The string containing the device location > + */ > + > +} /* namespace libcamera */ > -- > 2.17.1 > > _______________________________________________ > libcamera-devel mailing list > libcamera-devel@lists.libcamera.org > https://lists.libcamera.org/listinfo/libcamera-devel
diff --git a/src/libcamera/include/v4l2_device.h b/src/libcamera/include/v4l2_device.h new file mode 100644 index 000000000000..474c05b58cef --- /dev/null +++ b/src/libcamera/include/v4l2_device.h @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * v4l2_device.h - V4L2 Device + */ +#ifndef __LIBCAMERA_V4L2_DEVICE_H__ +#define __LIBCAMERA_V4L2_DEVICE_H__ + +#include <string> + +#include <linux/videodev2.h> + +namespace libcamera { + +struct V4L2Capability final : v4l2_capability { + const char *driver() const + { + return reinterpret_cast<const char *>(v4l2_capability::driver); + } + const char *card() const + { + return reinterpret_cast<const char *>(v4l2_capability::card); + } + const char *bus_info() const + { + return reinterpret_cast<const char *>(v4l2_capability::bus_info); + } + + bool isCapture() const { return capabilities & V4L2_CAP_VIDEO_CAPTURE; } + bool isOutput() const { return capabilities & V4L2_CAP_VIDEO_OUTPUT; } + bool hasStreaming() const { return capabilities & V4L2_CAP_STREAMING; } +}; + +class V4L2Device +{ +public: + V4L2Device(const std::string &devnode); + V4L2Device(const V4L2Device &) = delete; + ~V4L2Device(); + + void operator=(const V4L2Device &) = delete; + + int open(); + bool isOpen() const; + void close(); + + const char *driverName() const { return caps_.driver(); } + const char *deviceName() const { return caps_.card(); } + const char *busName() const { return caps_.bus_info(); } + +private: + std::string devnode_; + int fd_; + V4L2Capability caps_; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_V4L2_DEVICE_H__ */ diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index abf9a71d4172..f9f25c0ecf15 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -11,6 +11,7 @@ libcamera_sources = files([ 'pipeline_handler.cpp', 'signal.cpp', 'timer.cpp', + 'v4l2_device.cpp', ]) libcamera_headers = files([ @@ -21,6 +22,7 @@ libcamera_headers = files([ 'include/media_object.h', 'include/pipeline_handler.h', 'include/utils.h', + 'include/v4l2_device.h', ]) libcamera_internal_includes = include_directories('include') diff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp new file mode 100644 index 000000000000..54b53de37510 --- /dev/null +++ b/src/libcamera/v4l2_device.cpp @@ -0,0 +1,186 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * v4l2_device.cpp - V4L2 Device + */ + +#include <fcntl.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <unistd.h> + +#include "log.h" +#include "v4l2_device.h" + +/** + * \file v4l2_device.h + * \brief V4L2 Device API + */ +namespace libcamera { + +/** + * \struct V4L2Capability + * \brief struct v4l2_capability object wrapper and helpers + * + * The V4L2Capability structure manages the information returned by the + * VIDIOC_QUERYCAP ioctl. + */ + +/** + * \fn const char *V4L2Capability::driver() + * \brief Retrieve the driver module name + * \return The string containing the name of the driver module + */ + +/** + * \fn const char *V4L2Capability::card() + * \brief Retrieve the device card name + * \return The string containing the device name + */ + +/** + * \fn const char *V4L2Capability::bus_info() + * \brief Retrieve the location of the device in the system + * \return The string containing the device location + */ + +/** + * \fn bool V4L2Capability::isCapture() + * \brief Identify if the device is capable of capturing video + * \return True if the device can capture video frames + */ + +/** + * \fn bool V4L2Capability::isOutput() + * \brief Identify if the device is capable of outputting video + * \return True if the device can output video frames + */ + +/** + * \fn bool V4L2Capability::hasStreaming() + * \brief Determine if the device can perform Streaming I/O + * \return True if the device provides Streaming I/O IOCTLs + */ + +/** + * \class V4L2Device + * \brief V4L2Device object and API + * + * The V4L2 Device API class models an instance of a V4L2 device node. + * It is constructed with the path to a V4L2 video device node. The device node + * is only opened upon a call to open() which must be checked for success. + * + * The device capabilities are validated when the device is opened and the + * device is rejected if it is not a suitable V4L2 capture or output device, or + * if the device does not support streaming I/O. + * + * No API call other than open(), isOpen() and close() shall be called on an + * unopened device instance. + * + * Upon destruction any device left open will be closed, and any resources + * released. + */ + +/** + * \brief Construct a V4L2Device + * \param devnode The file-system path to the video device node + */ +V4L2Device::V4L2Device(const std::string &devnode) + : devnode_(devnode), fd_(-1) +{ +} + +V4L2Device::~V4L2Device() +{ + close(); +} + +/** + * \brief Open a V4L2 device and query its capabilities + * \return 0 on success, or a negative error code otherwise + */ +int V4L2Device::open() +{ + int ret; + + if (isOpen()) { + LOG(Error) << "Device already open"; + return -EBUSY; + } + + ret = ::open(devnode_.c_str(), O_RDWR); + if (ret < 0) { + ret = -errno; + LOG(Error) << "Failed to open V4L2 device '" << devnode_ + << "': " << strerror(-ret); + return ret; + } + fd_ = ret; + + ret = ioctl(fd_, VIDIOC_QUERYCAP, &caps_); + if (ret < 0) { + ret = -errno; + LOG(Error) << "Failed to query device capabilities: " + << strerror(-ret); + return ret; + } + + LOG(Debug) << "Opened '" << devnode_ << "' " + << caps_.bus_info() << ": " << caps_.driver() + << ": " << caps_.card(); + + if (!caps_.isCapture() && !caps_.isOutput()) { + LOG(Debug) << "Device is not a supported type"; + return -EINVAL; + } + + if (!caps_.hasStreaming()) { + LOG(Error) << "Device does not support streaming I/O"; + return -EINVAL; + } + + return 0; +} + +/** + * \brief Check if device is successfully opened + * \return True if the device is open, false otherwise + */ +bool V4L2Device::isOpen() const +{ + return fd_ != -1; +} + +/** + * \brief Close the device, releasing any resources acquired by open() + */ +void V4L2Device::close() +{ + if (fd_ < 0) + return; + + ::close(fd_); + fd_ = -1; +} + +/** + * \fn const char *V4L2Device::driverName() + * \brief Retrieve the name of the V4L2 device driver + * \return The string containing the driver name + */ + +/** + * \fn const char *V4L2Device::deviceName() + * \brief Retrieve the name of the V4L2 device + * \return The string containing the device name + */ + +/** + * \fn const char *V4L2Device::busName() + * \brief Retrieve the location of the device in the system + * \return The string containing the device location + */ + +} /* namespace libcamera */
Provide a helper V4L2 device object capable of interacting with the V4L2 Linux Kernel APIs. Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com> --- src/libcamera/include/v4l2_device.h | 60 +++++++++ src/libcamera/meson.build | 2 + src/libcamera/v4l2_device.cpp | 186 ++++++++++++++++++++++++++++ 3 files changed, 248 insertions(+) create mode 100644 src/libcamera/include/v4l2_device.h create mode 100644 src/libcamera/v4l2_device.cpp