diff options
author | Niklas Söderlund <niklas.soderlund@ragnatech.se> | 2019-05-01 01:36:36 +0200 |
---|---|---|
committer | Niklas Söderlund <niklas.soderlund@ragnatech.se> | 2019-06-19 11:54:30 +0200 |
commit | 87e46f7f594ec9e1e4873df43807e66fc407c6a9 (patch) | |
tree | d81c801553662926e0b05637a599bd905c52f993 | |
parent | ce02ea29cda94f065d857ae00101e2fef5467a40 (diff) |
libcamera: v4l2_device: Add enumeration of pixelformats and frame sizes
Add methods to enumerate pixelformats and frame sizes from a V4L2
device. The interface is similar to how V4L2Subdevice enumerates mbus
codes and frame sizes.
Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
-rw-r--r-- | src/libcamera/include/v4l2_device.h | 5 | ||||
-rw-r--r-- | src/libcamera/v4l2_device.cpp | 114 |
2 files changed, 119 insertions, 0 deletions
diff --git a/src/libcamera/include/v4l2_device.h b/src/libcamera/include/v4l2_device.h index bdecc087..1a67850a 100644 --- a/src/libcamera/include/v4l2_device.h +++ b/src/libcamera/include/v4l2_device.h @@ -16,6 +16,7 @@ #include <libcamera/geometry.h> #include <libcamera/signal.h> +#include "formats.h" #include "log.h" namespace libcamera { @@ -132,6 +133,7 @@ public: int getFormat(V4L2DeviceFormat *format); int setFormat(V4L2DeviceFormat *format); + ImageFormats formats(); int exportBuffers(BufferPool *pool); int importBuffers(BufferPool *pool); @@ -163,6 +165,9 @@ private: int createPlane(Buffer *buffer, unsigned int plane, unsigned int length); + std::vector<unsigned int> enumPixelformats(); + std::vector<SizeRange> enumSizes(unsigned int pixelFormat); + Buffer *dequeueBuffer(); void bufferAvailable(EventNotifier *notifier); diff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp index 0821bd75..e14fc610 100644 --- a/src/libcamera/v4l2_device.cpp +++ b/src/libcamera/v4l2_device.cpp @@ -634,6 +634,33 @@ int V4L2Device::setFormatSingleplane(V4L2DeviceFormat *format) return 0; } +/** + * \brief Enumerate all pixel formats and frame sizes + * + * Enumerate all pixel formats and frame sizes supported by the video device. + * + * \return A list of the supported device formats + */ +ImageFormats V4L2Device::formats() +{ + ImageFormats formats; + + for (unsigned int pixelformat : enumPixelformats()) { + std::vector<SizeRange> sizes = enumSizes(pixelformat); + if (sizes.empty()) + return {}; + + if (formats.addFormat(pixelformat, sizes)) { + LOG(V4L2, Error) + << "Could not add sizes for pixel format " + << pixelformat; + return {}; + } + } + + return formats; +} + int V4L2Device::requestBuffers(unsigned int count) { struct v4l2_requestbuffers rb = {}; @@ -763,6 +790,93 @@ int V4L2Device::createPlane(Buffer *buffer, unsigned int planeIndex, return 0; } +std::vector<unsigned int> V4L2Device::enumPixelformats() +{ + std::vector<unsigned int> formats; + int ret; + + for (unsigned int index = 0; ; index++) { + struct v4l2_fmtdesc pixelformatEnum = {}; + pixelformatEnum.index = index; + pixelformatEnum.type = bufferType_; + + ret = ioctl(fd_, VIDIOC_ENUM_FMT, &pixelformatEnum); + if (ret) + break; + + formats.push_back(pixelformatEnum.pixelformat); + } + + if (ret && errno != EINVAL) { + ret = -errno; + LOG(V4L2, Error) + << "Unable to enumerate pixel formats: " + << strerror(-ret); + return {}; + } + + return formats; +} + +std::vector<SizeRange> V4L2Device::enumSizes(unsigned int pixelFormat) +{ + std::vector<SizeRange> sizes; + int ret; + + for (unsigned int index = 0;; index++) { + struct v4l2_frmsizeenum frameSize = {}; + frameSize.index = index; + frameSize.pixel_format = pixelFormat; + + ret = ioctl(fd_, VIDIOC_ENUM_FRAMESIZES, &frameSize); + if (ret) + break; + + if (index != 0 && + frameSize.type != V4L2_FRMSIZE_TYPE_DISCRETE) { + LOG(V4L2, Error) + << "Non-zero index for non discrete type"; + return {}; + } + + switch (frameSize.type) { + case V4L2_FRMSIZE_TYPE_DISCRETE: + sizes.emplace_back(frameSize.discrete.width, + frameSize.discrete.height); + break; + case V4L2_FRMSIZE_TYPE_CONTINUOUS: + sizes.emplace_back(frameSize.stepwise.min_width, + frameSize.stepwise.min_height, + frameSize.stepwise.max_width, + frameSize.stepwise.max_height); + break; + case V4L2_FRMSIZE_TYPE_STEPWISE: + sizes.emplace_back(frameSize.stepwise.min_width, + frameSize.stepwise.min_height, + frameSize.stepwise.max_width, + frameSize.stepwise.max_height, + frameSize.stepwise.step_width, + frameSize.stepwise.step_height); + break; + default: + LOG(V4L2, Error) + << "Unknown VIDIOC_ENUM_FRAMESIZES type " + << frameSize.type; + return {}; + } + } + + if (ret && errno != EINVAL) { + ret = -errno; + LOG(V4L2, Error) + << "Unable to enumerate frame sizes: " + << strerror(-ret); + return {}; + } + + return sizes; +} + /** * \brief Import the externally allocated \a pool of buffers * \param[in] pool BufferPool of buffers to import |