[libcamera-devel,6/6] v4l2: v4l2_camera_proxy: Use libcamera formats

Message ID 20200629151411.216477-7-paul.elder@ideasonboard.com
State Superseded
Headers show
Series
  • Move formats from v4l2-compat into libcamera
Related show

Commit Message

Paul Elder June 29, 2020, 3:14 p.m. UTC
Now that calculation of bytes per line, image size, and conversions to
and from v4l2 and drm formats have been moved into libcamera core,
removed them from V4L2CameraProxy. This has a positive side-effect of
cleaning up the code.

Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
---
 src/v4l2/v4l2_camera_proxy.cpp | 167 +++++++--------------------------
 src/v4l2/v4l2_camera_proxy.h   |   7 --
 2 files changed, 36 insertions(+), 138 deletions(-)

Comments

Laurent Pinchart June 29, 2020, 10:30 p.m. UTC | #1
Hi Paul,

Thank you for the patch.

On Tue, Jun 30, 2020 at 12:14:11AM +0900, Paul Elder wrote:
> Now that calculation of bytes per line, image size, and conversions to
> and from v4l2 and drm formats have been moved into libcamera core,
> removed them from V4L2CameraProxy. This has a positive side-effect of
> cleaning up the code.
> 
> Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
> ---
>  src/v4l2/v4l2_camera_proxy.cpp | 167 +++++++--------------------------
>  src/v4l2/v4l2_camera_proxy.h   |   7 --
>  2 files changed, 36 insertions(+), 138 deletions(-)
> 
> diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp
> index c246570..0869797 100644
> --- a/src/v4l2/v4l2_camera_proxy.cpp
> +++ b/src/v4l2/v4l2_camera_proxy.cpp
> @@ -20,6 +20,7 @@
>  #include <libcamera/formats.h>
>  #include <libcamera/object.h>
>  
> +#include "libcamera/internal/formats.h"
>  #include "libcamera/internal/log.h"
>  #include "libcamera/internal/utils.h"
>  
> @@ -164,22 +165,21 @@ bool V4L2CameraProxy::validateMemoryType(uint32_t memory)
>  
>  void V4L2CameraProxy::setFmtFromConfig(StreamConfiguration &streamConfig)
>  {
> -	curV4L2Format_.fmt.pix.width = streamConfig.size.width;
> -	curV4L2Format_.fmt.pix.height = streamConfig.size.height;
> -	curV4L2Format_.fmt.pix.pixelformat = drmToV4L2(streamConfig.pixelFormat);
> -	curV4L2Format_.fmt.pix.field = V4L2_FIELD_NONE;
> -	curV4L2Format_.fmt.pix.bytesperline =
> -		bplMultiplier(curV4L2Format_.fmt.pix.pixelformat) *
> -		curV4L2Format_.fmt.pix.width;
> -	curV4L2Format_.fmt.pix.sizeimage =
> -		imageSize(curV4L2Format_.fmt.pix.pixelformat,
> -			  curV4L2Format_.fmt.pix.width,
> -			  curV4L2Format_.fmt.pix.height);
> -	curV4L2Format_.fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
> -	curV4L2Format_.fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
> -	curV4L2Format_.fmt.pix.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
> +	PixelFormatInfo formatInfo = PixelFormatInfo::info(streamConfig.pixelFormat);

This should be a const reference. Same for other locations below. I
would delete the copy constructor and assignement operators for
PixelFormatInfo, but that will mess up initialization of the static map
:-S

> +	unsigned int width = streamConfig.size.width;
> +	unsigned int height = streamConfig.size.height;
> +
> +	curV4L2Format_.fmt.pix.width        = width;
> +	curV4L2Format_.fmt.pix.height       = height;
> +	curV4L2Format_.fmt.pix.pixelformat  = formatInfo.v4l2Format;
> +	curV4L2Format_.fmt.pix.field        = V4L2_FIELD_NONE;
> +	curV4L2Format_.fmt.pix.bytesperline = formatInfo.bytesPerLine(width);
> +	curV4L2Format_.fmt.pix.sizeimage    = formatInfo.imageSize(width, height);
> +	curV4L2Format_.fmt.pix.colorspace   = V4L2_COLORSPACE_SRGB;
> +	curV4L2Format_.fmt.pix.priv         = V4L2_PIX_FMT_PRIV_MAGIC;
> +	curV4L2Format_.fmt.pix.ycbcr_enc    = V4L2_YCBCR_ENC_DEFAULT;
>  	curV4L2Format_.fmt.pix.quantization = V4L2_QUANTIZATION_DEFAULT;
> -	curV4L2Format_.fmt.pix.xfer_func = V4L2_XFER_FUNC_DEFAULT;
> +	curV4L2Format_.fmt.pix.xfer_func    = V4L2_XFER_FUNC_DEFAULT;
>  }
>  
>  unsigned int V4L2CameraProxy::calculateSizeImage(StreamConfiguration &streamConfig)
> @@ -188,9 +188,11 @@ unsigned int V4L2CameraProxy::calculateSizeImage(StreamConfiguration &streamConf
>  	 * \todo Merge this method with setFmtFromConfig (need imageSize to
>  	 * support all libcamera formats first, or filter out MJPEG for now).
>  	 */
> -	return imageSize(drmToV4L2(streamConfig.pixelFormat),
> -			 streamConfig.size.width,
> -			 streamConfig.size.height);
> +	PixelFormatInfo formatInfo = PixelFormatInfo::info(streamConfig.pixelFormat);
> +	unsigned int width = streamConfig.size.width;
> +	unsigned int height = streamConfig.size.height;
> +
> +	return formatInfo.imageSize(width, height);

In this case I would skip the local width and height variables. I wonder
if PixelFormatInfo::imageSize(unsigned int width, unsigned int height)
shouldn't become PixelFormatInfo::imageSize(const Size &size), so you could write

	return formatInfo.imageSize(streamConfig.size);

>  }
>  
>  void V4L2CameraProxy::querycap(std::shared_ptr<Camera> camera)
> @@ -253,12 +255,13 @@ int V4L2CameraProxy::vidioc_enum_framesizes(V4L2CameraFile *file, struct v4l2_fr
>  {
>  	LOG(V4L2Compat, Debug) << "Servicing vidioc_enum_framesizes fd = " << file->efd();
>  
> -	PixelFormat argFormat = v4l2ToDrm(arg->pixel_format);
> +	V4L2PixelFormat v4l2Format = V4L2PixelFormat(arg->pixel_format);
> +	PixelFormat format = PixelFormatInfo::info(v4l2Format).format;
>  	/*
>  	 * \todo This might need to be expanded as few pipeline handlers
>  	 * report StreamFormats.
>  	 */
> -	const std::vector<Size> &frameSizes = streamConfig_.formats().sizes(argFormat);
> +	const std::vector<Size> &frameSizes = streamConfig_.formats().sizes(format);
>  
>  	if (arg->index >= frameSizes.size())
>  		return -EINVAL;
> @@ -284,7 +287,8 @@ int V4L2CameraProxy::vidioc_enum_fmt(V4L2CameraFile *file, struct v4l2_fmtdesc *
>  	/* \todo Add map from format to description. */
>  	utils::strlcpy(reinterpret_cast<char *>(arg->description),
>  		       "Video Format Description", sizeof(arg->description));
> -	arg->pixelformat = drmToV4L2(streamConfig_.formats().pixelformats()[arg->index]);
> +	arg->pixelformat =
> +		PixelFormatInfo::info(streamConfig_.formats().pixelformats()[arg->index]).v4l2Format;

A local PixelFormat variable could make this more readable.

>  
>  	memset(arg->reserved, 0, sizeof(arg->reserved));
>  
> @@ -306,7 +310,8 @@ int V4L2CameraProxy::vidioc_g_fmt(V4L2CameraFile *file, struct v4l2_format *arg)
>  
>  void V4L2CameraProxy::tryFormat(struct v4l2_format *arg)
>  {
> -	PixelFormat format = v4l2ToDrm(arg->fmt.pix.pixelformat);
> +	V4L2PixelFormat v4l2Format = V4L2PixelFormat(arg->fmt.pix.pixelformat);
> +	PixelFormat format = PixelFormatInfo::info(v4l2Format).format;
>  	const std::vector<PixelFormat> &formats =
>  		streamConfig_.formats().pixelformats();
>  	if (std::find(formats.begin(), formats.end(), format) == formats.end())
> @@ -317,15 +322,14 @@ void V4L2CameraProxy::tryFormat(struct v4l2_format *arg)
>  	if (std::find(sizes.begin(), sizes.end(), size) == sizes.end())
>  		size = streamConfig_.formats().sizes(format)[0];
>  
> +	PixelFormatInfo formatInfo = PixelFormatInfo::info(format);
> +
>  	arg->fmt.pix.width        = size.width;
>  	arg->fmt.pix.height       = size.height;
> -	arg->fmt.pix.pixelformat  = drmToV4L2(format);
> +	arg->fmt.pix.pixelformat  = formatInfo.v4l2Format;
>  	arg->fmt.pix.field        = V4L2_FIELD_NONE;
> -	arg->fmt.pix.bytesperline = bplMultiplier(drmToV4L2(format)) *
> -				    arg->fmt.pix.width;
> -	arg->fmt.pix.sizeimage    = imageSize(drmToV4L2(format),
> -					      arg->fmt.pix.width,
> -					      arg->fmt.pix.height);
> +	arg->fmt.pix.bytesperline = formatInfo.bytesPerLine(size.width);
> +	arg->fmt.pix.sizeimage    = formatInfo.imageSize(size.width, size.height);
>  	arg->fmt.pix.colorspace   = V4L2_COLORSPACE_SRGB;
>  	arg->fmt.pix.priv         = V4L2_PIX_FMT_PRIV_MAGIC;
>  	arg->fmt.pix.ycbcr_enc    = V4L2_YCBCR_ENC_DEFAULT;
> @@ -350,8 +354,9 @@ int V4L2CameraProxy::vidioc_s_fmt(V4L2CameraFile *file, struct v4l2_format *arg)
>  	tryFormat(arg);
>  
>  	Size size(arg->fmt.pix.width, arg->fmt.pix.height);
> +	V4L2PixelFormat v4l2Format = V4L2PixelFormat(arg->fmt.pix.pixelformat);
>  	ret = vcam_->configure(&streamConfig_, size,
> -			       v4l2ToDrm(arg->fmt.pix.pixelformat),
> +			       PixelFormatInfo::info(v4l2Format).format,
>  			       bufferCount_);
>  	if (ret < 0)
>  		return -EINVAL;
> @@ -495,8 +500,9 @@ int V4L2CameraProxy::vidioc_reqbufs(V4L2CameraFile *file, struct v4l2_requestbuf
>  		freeBuffers();
>  
>  	Size size(curV4L2Format_.fmt.pix.width, curV4L2Format_.fmt.pix.height);
> +	V4L2PixelFormat v4l2Format = V4L2PixelFormat(curV4L2Format_.fmt.pix.pixelformat);
>  	int ret = vcam_->configure(&streamConfig_, size,
> -				   v4l2ToDrm(curV4L2Format_.fmt.pix.pixelformat),
> +				   PixelFormatInfo::info(v4l2Format).format,
>  				   arg->count);
>  	if (ret < 0)
>  		return -EINVAL;
> @@ -835,104 +841,3 @@ void V4L2CameraProxy::release(V4L2CameraFile *file)
>  
>  	owner_ = nullptr;
>  }
> -
> -struct PixelFormatPlaneInfo {
> -	unsigned int bitsPerPixel;
> -	unsigned int hSubSampling;
> -	unsigned int vSubSampling;
> -};
> -
> -struct PixelFormatInfo {
> -	PixelFormat format;
> -	uint32_t v4l2Format;
> -	unsigned int numPlanes;
> -	std::array<PixelFormatPlaneInfo, 3> planes;
> -};
> -
> -namespace {
> -
> -static const std::array<PixelFormatInfo, 16> pixelFormatInfo = {{
> -	/* RGB formats. */
> -	{ formats::RGB888,	V4L2_PIX_FMT_BGR24,	1, {{ { 24, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
> -	{ formats::BGR888,	V4L2_PIX_FMT_RGB24,	1, {{ { 24, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
> -	{ formats::BGRA8888,	V4L2_PIX_FMT_ARGB32,	1, {{ { 32, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
> -	/* YUV packed formats. */
> -	{ formats::UYVY,	V4L2_PIX_FMT_UYVY,	1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
> -	{ formats::VYUY,	V4L2_PIX_FMT_VYUY,	1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
> -	{ formats::YUYV,	V4L2_PIX_FMT_YUYV,	1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
> -	{ formats::YVYU,	V4L2_PIX_FMT_YVYU,	1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
> -	/* YUY planar formats. */
> -	{ formats::NV12,	V4L2_PIX_FMT_NV12,	2, {{ {  8, 1, 1 }, { 16, 2, 2 }, {  0, 0, 0 } }} },
> -	{ formats::NV21,	V4L2_PIX_FMT_NV21,	2, {{ {  8, 1, 1 }, { 16, 2, 2 }, {  0, 0, 0 } }} },
> -	{ formats::NV16,	V4L2_PIX_FMT_NV16,	2, {{ {  8, 1, 1 }, { 16, 2, 1 }, {  0, 0, 0 } }} },
> -	{ formats::NV61,	V4L2_PIX_FMT_NV61,	2, {{ {  8, 1, 1 }, { 16, 2, 1 }, {  0, 0, 0 } }} },
> -	{ formats::NV24,	V4L2_PIX_FMT_NV24,	2, {{ {  8, 1, 1 }, { 16, 1, 1 }, {  0, 0, 0 } }} },
> -	{ formats::NV42,	V4L2_PIX_FMT_NV42,	2, {{ {  8, 1, 1 }, { 16, 1, 1 }, {  0, 0, 0 } }} },
> -	{ formats::YUV420,	V4L2_PIX_FMT_YUV420,	3, {{ {  8, 1, 1 }, {  8, 2, 2 }, {  8, 2, 2 } }} },
> -	{ formats::YUV422,	V4L2_PIX_FMT_YUV422P,	3, {{ {  8, 1, 1 }, {  8, 2, 1 }, {  8, 2, 1 } }} },
> -	/* Compressed formats. */
> -	/*
> -	 * \todo Get a better image size estimate for MJPEG, via
> -	 * StreamConfiguration, instead of using the worst-case
> -	 * width * height * bpp of uncompressed data.
> -	 */
> -	{ formats::MJPEG,	V4L2_PIX_FMT_MJPEG,	1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
> -}};
> -
> -} /* namespace */
> -
> -/* \todo make libcamera export these */
> -unsigned int V4L2CameraProxy::bplMultiplier(uint32_t format)
> -{
> -	auto info = std::find_if(pixelFormatInfo.begin(), pixelFormatInfo.end(),
> -				 [format](const PixelFormatInfo &info) {
> -					 return info.v4l2Format == format;
> -				 });
> -	if (info == pixelFormatInfo.end())
> -		return 0;
> -
> -	return info->planes[0].bitsPerPixel / 8;
> -}
> -
> -unsigned int V4L2CameraProxy::imageSize(uint32_t format, unsigned int width,
> -					unsigned int height)
> -{
> -	auto info = std::find_if(pixelFormatInfo.begin(), pixelFormatInfo.end(),
> -				 [format](const PixelFormatInfo &info) {
> -					 return info.v4l2Format == format;
> -				 });
> -	if (info == pixelFormatInfo.end())
> -		return 0;
> -
> -	unsigned int multiplier = 0;
> -	for (unsigned int i = 0; i < info->numPlanes; ++i)
> -		multiplier += info->planes[i].bitsPerPixel
> -			    / info->planes[i].hSubSampling
> -			    / info->planes[i].vSubSampling;
> -
> -	return width * height * multiplier / 8;
> -}
> -
> -PixelFormat V4L2CameraProxy::v4l2ToDrm(uint32_t format)
> -{
> -	auto info = std::find_if(pixelFormatInfo.begin(), pixelFormatInfo.end(),
> -				 [format](const PixelFormatInfo &info) {
> -					 return info.v4l2Format == format;
> -				 });
> -	if (info == pixelFormatInfo.end())
> -		return PixelFormat();
> -
> -	return info->format;
> -}
> -
> -uint32_t V4L2CameraProxy::drmToV4L2(const PixelFormat &format)
> -{
> -	auto info = std::find_if(pixelFormatInfo.begin(), pixelFormatInfo.end(),
> -				 [format](const PixelFormatInfo &info) {
> -					 return info.format == format;
> -				 });
> -	if (info == pixelFormatInfo.end())
> -		return format;
> -
> -	return info->v4l2Format;
> -}
> diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h
> index d78a472..49184a1 100644
> --- a/src/v4l2/v4l2_camera_proxy.h
> +++ b/src/v4l2/v4l2_camera_proxy.h
> @@ -69,13 +69,6 @@ private:
>  	int acquire(V4L2CameraFile *file);
>  	void release(V4L2CameraFile *file);
>  
> -	static unsigned int bplMultiplier(uint32_t format);
> -	static unsigned int imageSize(uint32_t format, unsigned int width,
> -				      unsigned int height);
> -
> -	static PixelFormat v4l2ToDrm(uint32_t format);
> -	static uint32_t drmToV4L2(const PixelFormat &format);
> -
>  	static const std::set<unsigned long> supportedIoctls_;
>  
>  	unsigned int refcount_;

Patch

diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp
index c246570..0869797 100644
--- a/src/v4l2/v4l2_camera_proxy.cpp
+++ b/src/v4l2/v4l2_camera_proxy.cpp
@@ -20,6 +20,7 @@ 
 #include <libcamera/formats.h>
 #include <libcamera/object.h>
 
+#include "libcamera/internal/formats.h"
 #include "libcamera/internal/log.h"
 #include "libcamera/internal/utils.h"
 
@@ -164,22 +165,21 @@  bool V4L2CameraProxy::validateMemoryType(uint32_t memory)
 
 void V4L2CameraProxy::setFmtFromConfig(StreamConfiguration &streamConfig)
 {
-	curV4L2Format_.fmt.pix.width = streamConfig.size.width;
-	curV4L2Format_.fmt.pix.height = streamConfig.size.height;
-	curV4L2Format_.fmt.pix.pixelformat = drmToV4L2(streamConfig.pixelFormat);
-	curV4L2Format_.fmt.pix.field = V4L2_FIELD_NONE;
-	curV4L2Format_.fmt.pix.bytesperline =
-		bplMultiplier(curV4L2Format_.fmt.pix.pixelformat) *
-		curV4L2Format_.fmt.pix.width;
-	curV4L2Format_.fmt.pix.sizeimage =
-		imageSize(curV4L2Format_.fmt.pix.pixelformat,
-			  curV4L2Format_.fmt.pix.width,
-			  curV4L2Format_.fmt.pix.height);
-	curV4L2Format_.fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
-	curV4L2Format_.fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
-	curV4L2Format_.fmt.pix.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+	PixelFormatInfo formatInfo = PixelFormatInfo::info(streamConfig.pixelFormat);
+	unsigned int width = streamConfig.size.width;
+	unsigned int height = streamConfig.size.height;
+
+	curV4L2Format_.fmt.pix.width        = width;
+	curV4L2Format_.fmt.pix.height       = height;
+	curV4L2Format_.fmt.pix.pixelformat  = formatInfo.v4l2Format;
+	curV4L2Format_.fmt.pix.field        = V4L2_FIELD_NONE;
+	curV4L2Format_.fmt.pix.bytesperline = formatInfo.bytesPerLine(width);
+	curV4L2Format_.fmt.pix.sizeimage    = formatInfo.imageSize(width, height);
+	curV4L2Format_.fmt.pix.colorspace   = V4L2_COLORSPACE_SRGB;
+	curV4L2Format_.fmt.pix.priv         = V4L2_PIX_FMT_PRIV_MAGIC;
+	curV4L2Format_.fmt.pix.ycbcr_enc    = V4L2_YCBCR_ENC_DEFAULT;
 	curV4L2Format_.fmt.pix.quantization = V4L2_QUANTIZATION_DEFAULT;
-	curV4L2Format_.fmt.pix.xfer_func = V4L2_XFER_FUNC_DEFAULT;
+	curV4L2Format_.fmt.pix.xfer_func    = V4L2_XFER_FUNC_DEFAULT;
 }
 
 unsigned int V4L2CameraProxy::calculateSizeImage(StreamConfiguration &streamConfig)
@@ -188,9 +188,11 @@  unsigned int V4L2CameraProxy::calculateSizeImage(StreamConfiguration &streamConf
 	 * \todo Merge this method with setFmtFromConfig (need imageSize to
 	 * support all libcamera formats first, or filter out MJPEG for now).
 	 */
-	return imageSize(drmToV4L2(streamConfig.pixelFormat),
-			 streamConfig.size.width,
-			 streamConfig.size.height);
+	PixelFormatInfo formatInfo = PixelFormatInfo::info(streamConfig.pixelFormat);
+	unsigned int width = streamConfig.size.width;
+	unsigned int height = streamConfig.size.height;
+
+	return formatInfo.imageSize(width, height);
 }
 
 void V4L2CameraProxy::querycap(std::shared_ptr<Camera> camera)
@@ -253,12 +255,13 @@  int V4L2CameraProxy::vidioc_enum_framesizes(V4L2CameraFile *file, struct v4l2_fr
 {
 	LOG(V4L2Compat, Debug) << "Servicing vidioc_enum_framesizes fd = " << file->efd();
 
-	PixelFormat argFormat = v4l2ToDrm(arg->pixel_format);
+	V4L2PixelFormat v4l2Format = V4L2PixelFormat(arg->pixel_format);
+	PixelFormat format = PixelFormatInfo::info(v4l2Format).format;
 	/*
 	 * \todo This might need to be expanded as few pipeline handlers
 	 * report StreamFormats.
 	 */
-	const std::vector<Size> &frameSizes = streamConfig_.formats().sizes(argFormat);
+	const std::vector<Size> &frameSizes = streamConfig_.formats().sizes(format);
 
 	if (arg->index >= frameSizes.size())
 		return -EINVAL;
@@ -284,7 +287,8 @@  int V4L2CameraProxy::vidioc_enum_fmt(V4L2CameraFile *file, struct v4l2_fmtdesc *
 	/* \todo Add map from format to description. */
 	utils::strlcpy(reinterpret_cast<char *>(arg->description),
 		       "Video Format Description", sizeof(arg->description));
-	arg->pixelformat = drmToV4L2(streamConfig_.formats().pixelformats()[arg->index]);
+	arg->pixelformat =
+		PixelFormatInfo::info(streamConfig_.formats().pixelformats()[arg->index]).v4l2Format;
 
 	memset(arg->reserved, 0, sizeof(arg->reserved));
 
@@ -306,7 +310,8 @@  int V4L2CameraProxy::vidioc_g_fmt(V4L2CameraFile *file, struct v4l2_format *arg)
 
 void V4L2CameraProxy::tryFormat(struct v4l2_format *arg)
 {
-	PixelFormat format = v4l2ToDrm(arg->fmt.pix.pixelformat);
+	V4L2PixelFormat v4l2Format = V4L2PixelFormat(arg->fmt.pix.pixelformat);
+	PixelFormat format = PixelFormatInfo::info(v4l2Format).format;
 	const std::vector<PixelFormat> &formats =
 		streamConfig_.formats().pixelformats();
 	if (std::find(formats.begin(), formats.end(), format) == formats.end())
@@ -317,15 +322,14 @@  void V4L2CameraProxy::tryFormat(struct v4l2_format *arg)
 	if (std::find(sizes.begin(), sizes.end(), size) == sizes.end())
 		size = streamConfig_.formats().sizes(format)[0];
 
+	PixelFormatInfo formatInfo = PixelFormatInfo::info(format);
+
 	arg->fmt.pix.width        = size.width;
 	arg->fmt.pix.height       = size.height;
-	arg->fmt.pix.pixelformat  = drmToV4L2(format);
+	arg->fmt.pix.pixelformat  = formatInfo.v4l2Format;
 	arg->fmt.pix.field        = V4L2_FIELD_NONE;
-	arg->fmt.pix.bytesperline = bplMultiplier(drmToV4L2(format)) *
-				    arg->fmt.pix.width;
-	arg->fmt.pix.sizeimage    = imageSize(drmToV4L2(format),
-					      arg->fmt.pix.width,
-					      arg->fmt.pix.height);
+	arg->fmt.pix.bytesperline = formatInfo.bytesPerLine(size.width);
+	arg->fmt.pix.sizeimage    = formatInfo.imageSize(size.width, size.height);
 	arg->fmt.pix.colorspace   = V4L2_COLORSPACE_SRGB;
 	arg->fmt.pix.priv         = V4L2_PIX_FMT_PRIV_MAGIC;
 	arg->fmt.pix.ycbcr_enc    = V4L2_YCBCR_ENC_DEFAULT;
@@ -350,8 +354,9 @@  int V4L2CameraProxy::vidioc_s_fmt(V4L2CameraFile *file, struct v4l2_format *arg)
 	tryFormat(arg);
 
 	Size size(arg->fmt.pix.width, arg->fmt.pix.height);
+	V4L2PixelFormat v4l2Format = V4L2PixelFormat(arg->fmt.pix.pixelformat);
 	ret = vcam_->configure(&streamConfig_, size,
-			       v4l2ToDrm(arg->fmt.pix.pixelformat),
+			       PixelFormatInfo::info(v4l2Format).format,
 			       bufferCount_);
 	if (ret < 0)
 		return -EINVAL;
@@ -495,8 +500,9 @@  int V4L2CameraProxy::vidioc_reqbufs(V4L2CameraFile *file, struct v4l2_requestbuf
 		freeBuffers();
 
 	Size size(curV4L2Format_.fmt.pix.width, curV4L2Format_.fmt.pix.height);
+	V4L2PixelFormat v4l2Format = V4L2PixelFormat(curV4L2Format_.fmt.pix.pixelformat);
 	int ret = vcam_->configure(&streamConfig_, size,
-				   v4l2ToDrm(curV4L2Format_.fmt.pix.pixelformat),
+				   PixelFormatInfo::info(v4l2Format).format,
 				   arg->count);
 	if (ret < 0)
 		return -EINVAL;
@@ -835,104 +841,3 @@  void V4L2CameraProxy::release(V4L2CameraFile *file)
 
 	owner_ = nullptr;
 }
-
-struct PixelFormatPlaneInfo {
-	unsigned int bitsPerPixel;
-	unsigned int hSubSampling;
-	unsigned int vSubSampling;
-};
-
-struct PixelFormatInfo {
-	PixelFormat format;
-	uint32_t v4l2Format;
-	unsigned int numPlanes;
-	std::array<PixelFormatPlaneInfo, 3> planes;
-};
-
-namespace {
-
-static const std::array<PixelFormatInfo, 16> pixelFormatInfo = {{
-	/* RGB formats. */
-	{ formats::RGB888,	V4L2_PIX_FMT_BGR24,	1, {{ { 24, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
-	{ formats::BGR888,	V4L2_PIX_FMT_RGB24,	1, {{ { 24, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
-	{ formats::BGRA8888,	V4L2_PIX_FMT_ARGB32,	1, {{ { 32, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
-	/* YUV packed formats. */
-	{ formats::UYVY,	V4L2_PIX_FMT_UYVY,	1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
-	{ formats::VYUY,	V4L2_PIX_FMT_VYUY,	1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
-	{ formats::YUYV,	V4L2_PIX_FMT_YUYV,	1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
-	{ formats::YVYU,	V4L2_PIX_FMT_YVYU,	1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
-	/* YUY planar formats. */
-	{ formats::NV12,	V4L2_PIX_FMT_NV12,	2, {{ {  8, 1, 1 }, { 16, 2, 2 }, {  0, 0, 0 } }} },
-	{ formats::NV21,	V4L2_PIX_FMT_NV21,	2, {{ {  8, 1, 1 }, { 16, 2, 2 }, {  0, 0, 0 } }} },
-	{ formats::NV16,	V4L2_PIX_FMT_NV16,	2, {{ {  8, 1, 1 }, { 16, 2, 1 }, {  0, 0, 0 } }} },
-	{ formats::NV61,	V4L2_PIX_FMT_NV61,	2, {{ {  8, 1, 1 }, { 16, 2, 1 }, {  0, 0, 0 } }} },
-	{ formats::NV24,	V4L2_PIX_FMT_NV24,	2, {{ {  8, 1, 1 }, { 16, 1, 1 }, {  0, 0, 0 } }} },
-	{ formats::NV42,	V4L2_PIX_FMT_NV42,	2, {{ {  8, 1, 1 }, { 16, 1, 1 }, {  0, 0, 0 } }} },
-	{ formats::YUV420,	V4L2_PIX_FMT_YUV420,	3, {{ {  8, 1, 1 }, {  8, 2, 2 }, {  8, 2, 2 } }} },
-	{ formats::YUV422,	V4L2_PIX_FMT_YUV422P,	3, {{ {  8, 1, 1 }, {  8, 2, 1 }, {  8, 2, 1 } }} },
-	/* Compressed formats. */
-	/*
-	 * \todo Get a better image size estimate for MJPEG, via
-	 * StreamConfiguration, instead of using the worst-case
-	 * width * height * bpp of uncompressed data.
-	 */
-	{ formats::MJPEG,	V4L2_PIX_FMT_MJPEG,	1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
-}};
-
-} /* namespace */
-
-/* \todo make libcamera export these */
-unsigned int V4L2CameraProxy::bplMultiplier(uint32_t format)
-{
-	auto info = std::find_if(pixelFormatInfo.begin(), pixelFormatInfo.end(),
-				 [format](const PixelFormatInfo &info) {
-					 return info.v4l2Format == format;
-				 });
-	if (info == pixelFormatInfo.end())
-		return 0;
-
-	return info->planes[0].bitsPerPixel / 8;
-}
-
-unsigned int V4L2CameraProxy::imageSize(uint32_t format, unsigned int width,
-					unsigned int height)
-{
-	auto info = std::find_if(pixelFormatInfo.begin(), pixelFormatInfo.end(),
-				 [format](const PixelFormatInfo &info) {
-					 return info.v4l2Format == format;
-				 });
-	if (info == pixelFormatInfo.end())
-		return 0;
-
-	unsigned int multiplier = 0;
-	for (unsigned int i = 0; i < info->numPlanes; ++i)
-		multiplier += info->planes[i].bitsPerPixel
-			    / info->planes[i].hSubSampling
-			    / info->planes[i].vSubSampling;
-
-	return width * height * multiplier / 8;
-}
-
-PixelFormat V4L2CameraProxy::v4l2ToDrm(uint32_t format)
-{
-	auto info = std::find_if(pixelFormatInfo.begin(), pixelFormatInfo.end(),
-				 [format](const PixelFormatInfo &info) {
-					 return info.v4l2Format == format;
-				 });
-	if (info == pixelFormatInfo.end())
-		return PixelFormat();
-
-	return info->format;
-}
-
-uint32_t V4L2CameraProxy::drmToV4L2(const PixelFormat &format)
-{
-	auto info = std::find_if(pixelFormatInfo.begin(), pixelFormatInfo.end(),
-				 [format](const PixelFormatInfo &info) {
-					 return info.format == format;
-				 });
-	if (info == pixelFormatInfo.end())
-		return format;
-
-	return info->v4l2Format;
-}
diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h
index d78a472..49184a1 100644
--- a/src/v4l2/v4l2_camera_proxy.h
+++ b/src/v4l2/v4l2_camera_proxy.h
@@ -69,13 +69,6 @@  private:
 	int acquire(V4L2CameraFile *file);
 	void release(V4L2CameraFile *file);
 
-	static unsigned int bplMultiplier(uint32_t format);
-	static unsigned int imageSize(uint32_t format, unsigned int width,
-				      unsigned int height);
-
-	static PixelFormat v4l2ToDrm(uint32_t format);
-	static uint32_t drmToV4L2(const PixelFormat &format);
-
 	static const std::set<unsigned long> supportedIoctls_;
 
 	unsigned int refcount_;