[libcamera-devel] [RFC 2/3] libcamera: v4l2_device: Add methods to get/set format

Jacopo Mondi jacopo at jmondi.org
Sat Jan 26 16:13:17 CET 2019


Add methods to set and get the image format programmed on a V4L2Device
for both the single and multi planar use case.

Signed-off-by: Jacopo Mondi <jacopo at jmondi.org>
---
 src/libcamera/include/v4l2_device.h |  13 +++
 src/libcamera/v4l2_device.cpp       | 131 ++++++++++++++++++++++++++++
 2 files changed, 144 insertions(+)

diff --git a/src/libcamera/include/v4l2_device.h b/src/libcamera/include/v4l2_device.h
index ee0c4eb..01dbf45 100644
--- a/src/libcamera/include/v4l2_device.h
+++ b/src/libcamera/include/v4l2_device.h
@@ -14,6 +14,7 @@
 
 #include <libcamera/buffer.h>
 #include <libcamera/event_notifier.h>
+#include <libcamera/stream.h>
 
 namespace libcamera {
 
@@ -81,6 +82,9 @@ public:
 	int requestBuffers(unsigned int qty = 8);
 	int requestBuffers(unsigned int qty, std::vector<FrameBuffer *> &buffers);
 
+	int format(StreamConfiguration *config);
+	int setFormat(StreamConfiguration *config);
+
 	int queueBuffer(FrameBuffer *frame);
 	FrameBuffer *dequeueBuffer();
 
@@ -93,6 +97,7 @@ private:
 	std::string deviceNode_;
 	int fd_;
 	V4L2Capability caps_;
+	unsigned int buftype_;
 
 	enum v4l2_memory memoryType_;
 	enum v4l2_buf_type bufferType_;
@@ -101,6 +106,14 @@ private:
 	void bufferAvailable(EventNotifier *notifier);
 
 	EventNotifier *fdEvent_;
+
+	unsigned int getPlanesFromFormat(unsigned int pixfmt);
+	unsigned int getBppFromFormat(unsigned int pixfmt);
+	int getFormatSingleplane(StreamConfiguration *config);
+	int setFormatSingleplane(StreamConfiguration *config);
+
+	int getFormatMultiplane(StreamConfiguration *config);
+	int setFormatMultiplane(StreamConfiguration *config);
 };
 
 } /* namespace libcamera */
diff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp
index 4d39c85..d16691d 100644
--- a/src/libcamera/v4l2_device.cpp
+++ b/src/libcamera/v4l2_device.cpp
@@ -203,6 +203,15 @@ int V4L2Device::open()
 		return -EINVAL;
 	}
 
+	if (caps_.isCapture())
+		buftype_ = caps_.isMultiplanar() ?
+			   V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
+			   V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	else
+		buftype_ = caps_.isMultiplanar() ?
+			   V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE :
+			   V4L2_BUF_TYPE_VIDEO_OUTPUT;
+
 	return 0;
 }
 
@@ -314,6 +323,26 @@ int V4L2Device::requestBuffers(unsigned int qty, std::vector<FrameBuffer *> &buf
 	return 0;
 }
 
+/**
+ * \brief Retrieve the image format set on the V4L2 device
+ * \return 0 for success, a negative error code otherwise
+ */
+int V4L2Device::format(StreamConfiguration *config)
+{
+	return caps_.isMultiplanar() ? getFormatMultiplane(config) :
+				       getFormatSingleplane(config);
+}
+
+/**
+ * \brief Program an image format on the V4L2 device
+ * \return 0 for success, a negative error code otherwise
+ */
+int V4L2Device::setFormat(StreamConfiguration *config)
+{
+	return caps_.isMultiplanar() ? setFormatMultiplane(config) :
+				       setFormatSingleplane(config);
+}
+
 int V4L2Device::queueBuffer(FrameBuffer *frame)
 {
 	struct v4l2_buffer buf = {};
@@ -422,6 +451,108 @@ int V4L2Device::streamOff()
 	}
 
 	delete fdEvent_;
+}
+
+/* TODO: this is a simple stub at the moment. */
+unsigned int V4L2Device::getPlanesFromFormat(unsigned int pixfmt)
+{
+	return 1;
+}
+
+/* TODO: this is a simple stub at the moment. */
+unsigned int V4L2Device::getBppFromFormat(unsigned int pixfmt)
+{
+	return 16;
+}
+
+int V4L2Device::getFormatSingleplane(StreamConfiguration *config)
+{
+	struct v4l2_format v4l2Fmt;
+	struct v4l2_pix_format *pix = &v4l2Fmt.fmt.pix;
+	int ret;
+
+	ret = ioctl(fd_, VIDIOC_S_FMT, &v4l2Fmt);
+	if (ret) {
+		ret = -errno;
+		LOG(Error) << "Unable to get format: " << strerror(-ret);
+		return ret;
+	}
+
+	config->setWidth(pix->width);
+	config->setHeight(pix->height);
+	config->setPixelFormat(pix->pixelformat);
+
+	return 0;
+}
+
+int V4L2Device::setFormatSingleplane(StreamConfiguration *config)
+{
+	struct v4l2_format v4l2Fmt;
+	struct v4l2_pix_format *pix = &v4l2Fmt.fmt.pix;
+	int ret;
+
+	v4l2Fmt.type = buftype_;
+	pix->width = config->width();
+	pix->height = config->height();
+
+	pix->width = config->width();
+	pix->height = config->height();
+	pix->pixelformat = config->pixelformat();
+
+	ret = ioctl(fd_, VIDIOC_S_FMT, &v4l2Fmt);
+	if (ret) {
+		ret = -errno;
+		LOG(Error) << "Unable to set format: " << strerror(-ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+int V4L2Device::getFormatMultiplane(StreamConfiguration *config)
+{
+	struct v4l2_format v4l2Fmt;
+	struct v4l2_pix_format_mplane *pix = &v4l2Fmt.fmt.pix_mp;
+	int ret;
+
+	ret = ioctl(fd_, VIDIOC_G_FMT, &v4l2Fmt);
+	if (ret) {
+		ret = -errno;
+		LOG(Error) << "Unable to get format: " << strerror(-ret);
+		return ret;
+	}
+
+	config->setWidth(pix->width);
+	config->setHeight(pix->height);
+	config->setPixelFormat(pix->pixelformat);
+
+	return 0;
+}
+
+int V4L2Device::setFormatMultiplane(StreamConfiguration *config)
+{
+	struct v4l2_format v4l2Fmt;
+	struct v4l2_pix_format_mplane *pix = &v4l2Fmt.fmt.pix_mp;
+	int ret;
+
+	v4l2Fmt.type = buftype_;
+	pix->width = config->width();
+	pix->height = config->height();
+	pix->pixelformat = config->pixelformat();
+
+	unsigned int numPlanes = getPlanesFromFormat(pix->pixelformat);
+	unsigned int bpp = getBppFromFormat(pix->pixelformat);
+	for (unsigned int i = 0; i < numPlanes; ++i) {
+		pix->plane_fmt[i].bytesperline = bpp * pix->width;
+		pix->plane_fmt[i].sizeimage = bpp * pix->width * pix->height;
+	}
+
+	ret = ioctl(fd_, VIDIOC_S_FMT, &v4l2Fmt);
+	if (ret) {
+		ret = -errno;
+		LOG(Error) << "Unable to set format: " << strerror(-ret);
+		return ret;
+	}
 
 	return 0;
 }
-- 
2.20.1



More information about the libcamera-devel mailing list