[libcamera-devel,07/10] libcamera: v4l2_videodevice: Add PixelFormat conversion

Message ID 20191027234312.35284-8-jacopo@jmondi.org
State Accepted
Headers show
Series
  • libcamera: Use DRM_FORMAT_* fourcc codes
Related show

Commit Message

Jacopo Mondi Oct. 27, 2019, 11:43 p.m. UTC
Add support for the newly introduced PixelFormat type in the
V4L2VideoDevice class by providing helper operations to translate
a PixelFormat to the corresponding V4L2-defined fourcc code and vice
versa.

More work is needed to properly suppor the V4L2 multi-planar (*M)
formats.

Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 src/libcamera/include/v4l2_videodevice.h |   5 +
 src/libcamera/v4l2_videodevice.cpp       | 141 +++++++++++++++++++++++
 2 files changed, 146 insertions(+)

Patch

diff --git a/src/libcamera/include/v4l2_videodevice.h b/src/libcamera/include/v4l2_videodevice.h
index 4b8cf9394eb9..fdf11b3a6ec9 100644
--- a/src/libcamera/include/v4l2_videodevice.h
+++ b/src/libcamera/include/v4l2_videodevice.h
@@ -13,6 +13,7 @@ 
 #include <linux/videodev2.h>
 
 #include <libcamera/geometry.h>
+#include <libcamera/pixelformats.h>
 #include <libcamera/signal.h>
 
 #include "formats.h"
@@ -155,6 +156,10 @@  public:
 	static V4L2VideoDevice *fromEntityName(const MediaDevice *media,
 					       const std::string &entity);
 
+	static PixelFormat toPixelFormat(uint32_t v4l2Fourcc);
+	uint32_t toV4L2Fourcc(PixelFormat pixelFormat);
+	static uint32_t toV4L2Fourcc(PixelFormat pixelFormat, bool multiplanar);
+
 protected:
 	std::string logPrefix() const;
 
diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp
index 208ab54199b1..89370698bcf1 100644
--- a/src/libcamera/v4l2_videodevice.cpp
+++ b/src/libcamera/v4l2_videodevice.cpp
@@ -17,6 +17,8 @@ 
 #include <unistd.h>
 #include <vector>
 
+#include <linux/drm_fourcc.h>
+
 #include <libcamera/buffer.h>
 #include <libcamera/event_notifier.h>
 
@@ -1234,6 +1236,145 @@  V4L2VideoDevice *V4L2VideoDevice::fromEntityName(const MediaDevice *media,
 	return new V4L2VideoDevice(mediaEntity);
 }
 
+/**
+ * \brief Convert a \a v4l2Fourcc code to its corresponding PixelFormat
+ * \param[in] v4l2Fourcc A V4L2_PIX_FORMAT_* pixel code
+ * \return The PixelFormat corresponding to \a v4l2Fourcc
+ */
+PixelFormat V4L2VideoDevice::toPixelFormat(uint32_t v4l2Fourcc)
+{
+	switch (v4l2Fourcc) {
+	/* RGB formats. */
+	case V4L2_PIX_FMT_RGB24:
+		return DRM_FORMAT_BGR888;
+	case V4L2_PIX_FMT_BGR24:
+		return DRM_FORMAT_RGB888;
+	case V4L2_PIX_FMT_ARGB32:
+		return DRM_FORMAT_BGRA8888;
+
+	/* YUV packed formats. */
+	case V4L2_PIX_FMT_YUYV:
+		return DRM_FORMAT_YUYV;
+	case V4L2_PIX_FMT_YVYU:
+		return DRM_FORMAT_YVYU;
+	case V4L2_PIX_FMT_UYVY:
+		return DRM_FORMAT_UYVY;
+	case V4L2_PIX_FMT_VYUY:
+		return DRM_FORMAT_VYUY;
+
+	/* YUY planar formats. */
+	case V4L2_PIX_FMT_NV16:
+	case V4L2_PIX_FMT_NV16M:
+		return DRM_FORMAT_NV16;
+	case V4L2_PIX_FMT_NV61:
+	case V4L2_PIX_FMT_NV61M:
+		return DRM_FORMAT_NV61;
+	case V4L2_PIX_FMT_NV12:
+	case V4L2_PIX_FMT_NV12M:
+		return DRM_FORMAT_NV12;
+	case V4L2_PIX_FMT_NV21:
+	case V4L2_PIX_FMT_NV21M:
+		return DRM_FORMAT_NV21;
+
+	/* Compressed formats. */
+	case V4L2_PIX_FMT_MJPEG:
+		return DRM_FORMAT_MJPEG;
+
+	/* V4L2 formats not yet supported by DRM. */
+	case V4L2_PIX_FMT_GREY:
+	default:
+		/*
+		 * \todo We can't use LOG() in a static method of a Loggable
+		 * class. Until we fix the logger, work around it.
+		 */
+		libcamera::_log(__FILE__, __LINE__, _LOG_CATEGORY(V4L2)(),
+				LogError).stream()
+			<< "Unsupported V4L2 pixel format "
+			<< utils::hex(v4l2Fourcc);
+		return 0;
+	}
+}
+
+/**
+ * \brief Convert \a PixelFormat to its corresponding V4L2 fourcc code
+ * \param[in] pixelFormat The PixelFormat to convert
+ *
+ * For multiplanar formats, the V4L2 format variant (contiguous or
+ * non-contiguous planes) is selected automatically based on the capabilities
+ * of the video device. If the video device supports the V4L2 multiplanar API,
+ * non-contiguous formats are preferred.
+ *
+ * \return The V4L2_PIX_FMT_* pixel format code corresponding to \a pixelFormat
+ */
+uint32_t V4L2VideoDevice::toV4L2Fourcc(PixelFormat pixelFormat)
+{
+	return V4L2VideoDevice::toV4L2Fourcc(pixelFormat, caps_.isMultiplanar());
+}
+
+/**
+ * \brief Convert \a pixelFormat to its corresponding V4L2 fourcc code
+ * \param[in] pixelFormat The PixelFormat to convert
+ * \param[in] multiplanar V4L2 Multiplanar API support flag
+ *
+ * Multiple V4L2 formats may exist for one PixelFormat when the format uses
+ * multiple planes, as V4L2 defines separate 4CCs for contiguous and separate
+ * planes formats. Set the \a multiplanar parameter to false to select a format
+ * with contiguous planes, or to true to select a format with non-contiguous
+ * planes.
+ *
+ * \return The V4L2_PIX_FMT_* pixel format code corresponding to \a pixelFormat
+ */
+uint32_t V4L2VideoDevice::toV4L2Fourcc(PixelFormat pixelFormat, bool multiplanar)
+{
+	switch (pixelFormat) {
+	/* RGB formats. */
+	case DRM_FORMAT_BGR888:
+		return V4L2_PIX_FMT_RGB24;
+	case DRM_FORMAT_RGB888:
+		return V4L2_PIX_FMT_BGR24;
+	case DRM_FORMAT_BGRA8888:
+		return V4L2_PIX_FMT_ARGB32;
+
+	/* YUV packed formats. */
+	case DRM_FORMAT_YUYV:
+		return V4L2_PIX_FMT_YUYV;
+	case DRM_FORMAT_YVYU:
+		return V4L2_PIX_FMT_YVYU;
+	case DRM_FORMAT_UYVY:
+		return V4L2_PIX_FMT_UYVY;
+	case DRM_FORMAT_VYUY:
+		return V4L2_PIX_FMT_VYUY;
+
+	/*
+	 * YUY planar formats.
+	 * \todo Add support for non-contiguous memory planes
+	 * \todo Select the format variant not only based on \a multiplanar but
+	 * also take into account the formats supported by the device.
+	 */
+	case DRM_FORMAT_NV16:
+		return V4L2_PIX_FMT_NV16;
+	case DRM_FORMAT_NV61:
+		return V4L2_PIX_FMT_NV61;
+	case DRM_FORMAT_NV12:
+		return V4L2_PIX_FMT_NV12;
+	case DRM_FORMAT_NV21:
+		return V4L2_PIX_FMT_NV21;
+
+	/* Compressed formats. */
+	case DRM_FORMAT_MJPEG:
+		return V4L2_PIX_FMT_MJPEG;
+	}
+
+	/*
+	 * \todo We can't use LOG() in a static method of a Loggable
+	 * class. Until we fix the logger, work around it.
+	 */
+	libcamera::_log(__FILE__, __LINE__, _LOG_CATEGORY(V4L2)(), LogError).stream()
+		<< "Unsupported V4L2 pixel format "
+		<< utils::hex(pixelFormat);
+	return 0;
+}
+
 /**
  * \class V4L2M2MDevice
  * \brief Memory-to-Memory video device