[libcamera-devel] [PATCH v2 6/7] libcamera: v4l2_videodevice: Add PixelFormat conversion

Kieran Bingham kieran.bingham at ideasonboard.com
Mon Oct 28 12:53:08 CET 2019


Hi Jacopo,

On 28/10/2019 11:02, Laurent Pinchart wrote:
> From: Jacopo Mondi <jacopo at jmondi.org>
> 
> In preparation for switching PixelFormat to DRM pixel formats, add
> helper methods to the V4L2VideoDevice class to translate between DRM
> pixel formats and V4L2 pixel formats.
> 
> More work is needed to properly suppor the V4L2 multi-planar (NV[0-9]*M)

s/suppor/support/

> formats.
> 
> Signed-off-by: Jacopo Mondi <jacopo at jmondi.org>
> Reviewed-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>

Reviewed-by: Kieran Bingham <kieran.bingham at ideasonboard.com>


> ---
>  src/libcamera/include/v4l2_videodevice.h |   5 +
>  src/libcamera/v4l2_videodevice.cpp       | 141 +++++++++++++++++++++++
>  2 files changed, 146 insertions(+)
> 
> 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>

Hrm, seeing this makes me think the include file should be
"libcamera/pixelformat.h"

>  #include <libcamera/signal.h>

Because we don't call this libcamera/signals.h :D

>  
>  #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..3f2dc2799796 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 to the corresponding PixelFormat
> + * \param[in] v4l2Fourcc The V4L2 pixel format (V4L2_PIX_FORMAT_*)
> + * \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;
> +	}
> +}

I wonder if these would be more manageable as a table of entries in a
map, with a lookup - but I bet there's not much performance benefits
either way, and it's only ever going to be a (relatively) small table.

Perhaps a future optimisation maybe ...


> +
> +/**
> + * \brief Convert \a PixelFormat to its corresponding V4L2 FourCC
> + * \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.

I think that's fine for now.

We might have issues later if a device uses planar formats even though
it supports MPLANE, but I can't think of a reason why that would happen
at the moment, so lets go with this.


> + *
> + * \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
> + * \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
> 

-- 
Regards
--
Kieran


More information about the libcamera-devel mailing list