[libcamera-devel,4/4] v4l2: camera_proxy: Create format info array

Message ID 20200106161417.19150-5-laurent.pinchart@ideasonboard.com
State Accepted
Headers show
Series
  • v4l2: Miscellaneous improvements
Related show

Commit Message

Laurent Pinchart Jan. 6, 2020, 4:14 p.m. UTC
Create a PixelFormatInfo structure to store information about a format,
and add a global array of format info for all the formats currently
supported. Move the format helpers to use the information from the
array.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 src/v4l2/v4l2_camera_proxy.cpp | 180 +++++++++++++--------------------
 1 file changed, 70 insertions(+), 110 deletions(-)

Comments

Kieran Bingham Jan. 6, 2020, 4:48 p.m. UTC | #1
Hi Laurent,

On 06/01/2020 16:14, Laurent Pinchart wrote:
> Create a PixelFormatInfo structure to store information about a format,
> and add a global array of format info for all the formats currently
> supported. Move the format helpers to use the information from the
> array.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
>  src/v4l2/v4l2_camera_proxy.cpp | 180 +++++++++++++--------------------
>  1 file changed, 70 insertions(+), 110 deletions(-)
> 
> diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp
> index 6a222d702e13..b8c1a53af1c2 100644
> --- a/src/v4l2/v4l2_camera_proxy.cpp
> +++ b/src/v4l2/v4l2_camera_proxy.cpp
> @@ -509,134 +509,94 @@ int V4L2CameraProxy::ioctl(unsigned long request, void *arg)
>  	return ret;
>  }
>  
> +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 {
> +
> +constexpr std::array<PixelFormatInfo, 13> pixelFormatInfo = {{
> +	/* RGB formats. */
> +	{ DRM_FORMAT_RGB888,	V4L2_PIX_FMT_BGR24,	1, {{ { 24, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
> +	{ DRM_FORMAT_BGR888,	V4L2_PIX_FMT_RGB24,	1, {{ { 24, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
> +	{ DRM_FORMAT_BGRA8888,	V4L2_PIX_FMT_ARGB32,	1, {{ { 32, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
> +	/* YUV packed formats. */
> +	{ DRM_FORMAT_UYVY,	V4L2_PIX_FMT_UYVY,	1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
> +	{ DRM_FORMAT_VYUY,	V4L2_PIX_FMT_VYUY,	1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
> +	{ DRM_FORMAT_YUYV,	V4L2_PIX_FMT_YUYV,	1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
> +	{ DRM_FORMAT_YVYU,	V4L2_PIX_FMT_YVYU,	1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
> +	/* YUY planar formats. */
> +	{ DRM_FORMAT_NV12,	V4L2_PIX_FMT_NV12,	2, {{ {  8, 1, 1 }, { 16, 2, 2 }, {  0, 0, 0 } }} },
> +	{ DRM_FORMAT_NV21,	V4L2_PIX_FMT_NV21,	2, {{ {  8, 1, 1 }, { 16, 2, 2 }, {  0, 0, 0 } }} },
> +	{ DRM_FORMAT_NV16,	V4L2_PIX_FMT_NV16,	2, {{ {  8, 1, 1 }, { 16, 2, 1 }, {  0, 0, 0 } }} },
> +	{ DRM_FORMAT_NV61,	V4L2_PIX_FMT_NV61,	2, {{ {  8, 1, 1 }, { 16, 2, 1 }, {  0, 0, 0 } }} },
> +	{ DRM_FORMAT_NV24,	V4L2_PIX_FMT_NV24,	2, {{ {  8, 1, 1 }, { 16, 2, 1 }, {  0, 0, 0 } }} },
> +	{ DRM_FORMAT_NV42,	V4L2_PIX_FMT_NV42,	2, {{ {  8, 1, 1 }, { 16, 1, 1 }, {  0, 0, 0 } }} },
> +}};
> +
> +} /* namespace */


I think this table will be easier to manage, but is there anyway we can
keep a common table shared between the v4l2 library and libcamera?

Actually - before that - Do we need this information in libcamera :D

We need to identify mappings between DRM formats and V4L2 formats, but
perhaps we don't actually need the pixel specific data ....?

--
Kieran

> +
>  /* \todo make libcamera export these */
>  unsigned int V4L2CameraProxy::bplMultiplier(uint32_t format)
>  {
> -	switch (format) {
> -	case V4L2_PIX_FMT_NV12:
> -	case V4L2_PIX_FMT_NV21:
> -	case V4L2_PIX_FMT_NV16:
> -	case V4L2_PIX_FMT_NV61:
> -	case V4L2_PIX_FMT_NV24:
> -	case V4L2_PIX_FMT_NV42:
> -		return 1;
> -	case V4L2_PIX_FMT_BGR24:
> -	case V4L2_PIX_FMT_RGB24:
> -		return 3;
> -	case V4L2_PIX_FMT_ARGB32:
> -		return 4;
> -	case V4L2_PIX_FMT_VYUY:
> -	case V4L2_PIX_FMT_YVYU:
> -	case V4L2_PIX_FMT_UYVY:
> -	case V4L2_PIX_FMT_YUYV:
> -		return 2;
> -	default:
> +	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)
>  {
> -	switch (format) {
> -	case V4L2_PIX_FMT_NV12:
> -	case V4L2_PIX_FMT_NV21:
> -		return width * height * 3 / 2;
> -	case V4L2_PIX_FMT_NV16:
> -	case V4L2_PIX_FMT_NV61:
> -		return width * height * 2;
> -	case V4L2_PIX_FMT_NV24:
> -	case V4L2_PIX_FMT_NV42:
> -		return width * height * 3;
> -	case V4L2_PIX_FMT_BGR24:
> -	case V4L2_PIX_FMT_RGB24:
> -		return width * height * 3;
> -	case V4L2_PIX_FMT_ARGB32:
> -		return width * height * 4;
> -	case V4L2_PIX_FMT_VYUY:
> -	case V4L2_PIX_FMT_YVYU:
> -	case V4L2_PIX_FMT_UYVY:
> -	case V4L2_PIX_FMT_YUYV:
> -		return width * height * 2;
> -	default:
> +	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)
>  {
> -	switch (format) {
> -	/* 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:
> -		return DRM_FORMAT_NV16;
> -	case V4L2_PIX_FMT_NV61:
> -		return DRM_FORMAT_NV61;
> -	case V4L2_PIX_FMT_NV12:
> -		return DRM_FORMAT_NV12;
> -	case V4L2_PIX_FMT_NV21:
> -		return DRM_FORMAT_NV21;
> -	case V4L2_PIX_FMT_NV24:
> -		return DRM_FORMAT_NV24;
> -	case V4L2_PIX_FMT_NV42:
> -		return DRM_FORMAT_NV42;
> -	default:
> +	auto info = std::find_if(pixelFormatInfo.begin(), pixelFormatInfo.end(),
> +				 [format](const PixelFormatInfo &info) {
> +					 return info.v4l2Format == format;
> +				 });
> +	if (info == pixelFormatInfo.end())
>  		return format;
> -	};
> +
> +	return info->format;
>  }
>  
>  uint32_t V4L2CameraProxy::drmToV4L2(PixelFormat format)
>  {
> -	switch (format) {
> -	/* 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. */
> -	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;
> -	case DRM_FORMAT_NV24:
> -		return V4L2_PIX_FMT_NV24;
> -	case DRM_FORMAT_NV42:
> -		return V4L2_PIX_FMT_NV42;
> -	default:
> +	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;
>  }
>
Laurent Pinchart Jan. 6, 2020, 4:53 p.m. UTC | #2
Hi Kieran,

On Mon, Jan 06, 2020 at 04:48:42PM +0000, Kieran Bingham wrote:
> On 06/01/2020 16:14, Laurent Pinchart wrote:
> > Create a PixelFormatInfo structure to store information about a format,
> > and add a global array of format info for all the formats currently
> > supported. Move the format helpers to use the information from the
> > array.
> > 
> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > ---
> >  src/v4l2/v4l2_camera_proxy.cpp | 180 +++++++++++++--------------------
> >  1 file changed, 70 insertions(+), 110 deletions(-)
> > 
> > diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp
> > index 6a222d702e13..b8c1a53af1c2 100644
> > --- a/src/v4l2/v4l2_camera_proxy.cpp
> > +++ b/src/v4l2/v4l2_camera_proxy.cpp
> > @@ -509,134 +509,94 @@ int V4L2CameraProxy::ioctl(unsigned long request, void *arg)
> >  	return ret;
> >  }
> >  
> > +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 {
> > +
> > +constexpr std::array<PixelFormatInfo, 13> pixelFormatInfo = {{
> > +	/* RGB formats. */
> > +	{ DRM_FORMAT_RGB888,	V4L2_PIX_FMT_BGR24,	1, {{ { 24, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
> > +	{ DRM_FORMAT_BGR888,	V4L2_PIX_FMT_RGB24,	1, {{ { 24, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
> > +	{ DRM_FORMAT_BGRA8888,	V4L2_PIX_FMT_ARGB32,	1, {{ { 32, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
> > +	/* YUV packed formats. */
> > +	{ DRM_FORMAT_UYVY,	V4L2_PIX_FMT_UYVY,	1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
> > +	{ DRM_FORMAT_VYUY,	V4L2_PIX_FMT_VYUY,	1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
> > +	{ DRM_FORMAT_YUYV,	V4L2_PIX_FMT_YUYV,	1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
> > +	{ DRM_FORMAT_YVYU,	V4L2_PIX_FMT_YVYU,	1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
> > +	/* YUY planar formats. */
> > +	{ DRM_FORMAT_NV12,	V4L2_PIX_FMT_NV12,	2, {{ {  8, 1, 1 }, { 16, 2, 2 }, {  0, 0, 0 } }} },
> > +	{ DRM_FORMAT_NV21,	V4L2_PIX_FMT_NV21,	2, {{ {  8, 1, 1 }, { 16, 2, 2 }, {  0, 0, 0 } }} },
> > +	{ DRM_FORMAT_NV16,	V4L2_PIX_FMT_NV16,	2, {{ {  8, 1, 1 }, { 16, 2, 1 }, {  0, 0, 0 } }} },
> > +	{ DRM_FORMAT_NV61,	V4L2_PIX_FMT_NV61,	2, {{ {  8, 1, 1 }, { 16, 2, 1 }, {  0, 0, 0 } }} },
> > +	{ DRM_FORMAT_NV24,	V4L2_PIX_FMT_NV24,	2, {{ {  8, 1, 1 }, { 16, 2, 1 }, {  0, 0, 0 } }} },
> > +	{ DRM_FORMAT_NV42,	V4L2_PIX_FMT_NV42,	2, {{ {  8, 1, 1 }, { 16, 1, 1 }, {  0, 0, 0 } }} },
> > +}};
> > +
> > +} /* namespace */
> 
> I think this table will be easier to manage, but is there anyway we can
> keep a common table shared between the v4l2 library and libcamera?
> 
> Actually - before that - Do we need this information in libcamera :D
> 
> We need to identify mappings between DRM formats and V4L2 formats, but
> perhaps we don't actually need the pixel specific data ....?

We may not need all the information in libcamera, but I think it could
still be potentially useful for pipeline handlers, depending on their
individual needs. In any case, I believe we should move this array to
libcamera and export it for the V4L2 compatibility layer. We should also
create a set of helper functions to look up entries and perform
calculations. All this isn't part of this series, but it still paves the
way in that direction.

> > +
> >  /* \todo make libcamera export these */
> >  unsigned int V4L2CameraProxy::bplMultiplier(uint32_t format)
> >  {
> > -	switch (format) {
> > -	case V4L2_PIX_FMT_NV12:
> > -	case V4L2_PIX_FMT_NV21:
> > -	case V4L2_PIX_FMT_NV16:
> > -	case V4L2_PIX_FMT_NV61:
> > -	case V4L2_PIX_FMT_NV24:
> > -	case V4L2_PIX_FMT_NV42:
> > -		return 1;
> > -	case V4L2_PIX_FMT_BGR24:
> > -	case V4L2_PIX_FMT_RGB24:
> > -		return 3;
> > -	case V4L2_PIX_FMT_ARGB32:
> > -		return 4;
> > -	case V4L2_PIX_FMT_VYUY:
> > -	case V4L2_PIX_FMT_YVYU:
> > -	case V4L2_PIX_FMT_UYVY:
> > -	case V4L2_PIX_FMT_YUYV:
> > -		return 2;
> > -	default:
> > +	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)
> >  {
> > -	switch (format) {
> > -	case V4L2_PIX_FMT_NV12:
> > -	case V4L2_PIX_FMT_NV21:
> > -		return width * height * 3 / 2;
> > -	case V4L2_PIX_FMT_NV16:
> > -	case V4L2_PIX_FMT_NV61:
> > -		return width * height * 2;
> > -	case V4L2_PIX_FMT_NV24:
> > -	case V4L2_PIX_FMT_NV42:
> > -		return width * height * 3;
> > -	case V4L2_PIX_FMT_BGR24:
> > -	case V4L2_PIX_FMT_RGB24:
> > -		return width * height * 3;
> > -	case V4L2_PIX_FMT_ARGB32:
> > -		return width * height * 4;
> > -	case V4L2_PIX_FMT_VYUY:
> > -	case V4L2_PIX_FMT_YVYU:
> > -	case V4L2_PIX_FMT_UYVY:
> > -	case V4L2_PIX_FMT_YUYV:
> > -		return width * height * 2;
> > -	default:
> > +	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)
> >  {
> > -	switch (format) {
> > -	/* 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:
> > -		return DRM_FORMAT_NV16;
> > -	case V4L2_PIX_FMT_NV61:
> > -		return DRM_FORMAT_NV61;
> > -	case V4L2_PIX_FMT_NV12:
> > -		return DRM_FORMAT_NV12;
> > -	case V4L2_PIX_FMT_NV21:
> > -		return DRM_FORMAT_NV21;
> > -	case V4L2_PIX_FMT_NV24:
> > -		return DRM_FORMAT_NV24;
> > -	case V4L2_PIX_FMT_NV42:
> > -		return DRM_FORMAT_NV42;
> > -	default:
> > +	auto info = std::find_if(pixelFormatInfo.begin(), pixelFormatInfo.end(),
> > +				 [format](const PixelFormatInfo &info) {
> > +					 return info.v4l2Format == format;
> > +				 });
> > +	if (info == pixelFormatInfo.end())
> >  		return format;
> > -	};
> > +
> > +	return info->format;
> >  }
> >  
> >  uint32_t V4L2CameraProxy::drmToV4L2(PixelFormat format)
> >  {
> > -	switch (format) {
> > -	/* 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. */
> > -	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;
> > -	case DRM_FORMAT_NV24:
> > -		return V4L2_PIX_FMT_NV24;
> > -	case DRM_FORMAT_NV42:
> > -		return V4L2_PIX_FMT_NV42;
> > -	default:
> > +	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;
> >  }
> >
Kieran Bingham Jan. 6, 2020, 4:59 p.m. UTC | #3
Hi Laurent,

On 06/01/2020 16:53, Laurent Pinchart wrote:
> Hi Kieran,
> 
> On Mon, Jan 06, 2020 at 04:48:42PM +0000, Kieran Bingham wrote:
>> On 06/01/2020 16:14, Laurent Pinchart wrote:
>>> Create a PixelFormatInfo structure to store information about a format,
>>> and add a global array of format info for all the formats currently
>>> supported. Move the format helpers to use the information from the
>>> array.
>>>
>>> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>>> ---
>>>  src/v4l2/v4l2_camera_proxy.cpp | 180 +++++++++++++--------------------
>>>  1 file changed, 70 insertions(+), 110 deletions(-)
>>>
>>> diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp
>>> index 6a222d702e13..b8c1a53af1c2 100644
>>> --- a/src/v4l2/v4l2_camera_proxy.cpp
>>> +++ b/src/v4l2/v4l2_camera_proxy.cpp
>>> @@ -509,134 +509,94 @@ int V4L2CameraProxy::ioctl(unsigned long request, void *arg)
>>>  	return ret;
>>>  }
>>>  
>>> +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 {
>>> +
>>> +constexpr std::array<PixelFormatInfo, 13> pixelFormatInfo = {{
>>> +	/* RGB formats. */
>>> +	{ DRM_FORMAT_RGB888,	V4L2_PIX_FMT_BGR24,	1, {{ { 24, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
>>> +	{ DRM_FORMAT_BGR888,	V4L2_PIX_FMT_RGB24,	1, {{ { 24, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
>>> +	{ DRM_FORMAT_BGRA8888,	V4L2_PIX_FMT_ARGB32,	1, {{ { 32, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
>>> +	/* YUV packed formats. */
>>> +	{ DRM_FORMAT_UYVY,	V4L2_PIX_FMT_UYVY,	1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
>>> +	{ DRM_FORMAT_VYUY,	V4L2_PIX_FMT_VYUY,	1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
>>> +	{ DRM_FORMAT_YUYV,	V4L2_PIX_FMT_YUYV,	1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
>>> +	{ DRM_FORMAT_YVYU,	V4L2_PIX_FMT_YVYU,	1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
>>> +	/* YUY planar formats. */
>>> +	{ DRM_FORMAT_NV12,	V4L2_PIX_FMT_NV12,	2, {{ {  8, 1, 1 }, { 16, 2, 2 }, {  0, 0, 0 } }} },
>>> +	{ DRM_FORMAT_NV21,	V4L2_PIX_FMT_NV21,	2, {{ {  8, 1, 1 }, { 16, 2, 2 }, {  0, 0, 0 } }} },
>>> +	{ DRM_FORMAT_NV16,	V4L2_PIX_FMT_NV16,	2, {{ {  8, 1, 1 }, { 16, 2, 1 }, {  0, 0, 0 } }} },
>>> +	{ DRM_FORMAT_NV61,	V4L2_PIX_FMT_NV61,	2, {{ {  8, 1, 1 }, { 16, 2, 1 }, {  0, 0, 0 } }} },
>>> +	{ DRM_FORMAT_NV24,	V4L2_PIX_FMT_NV24,	2, {{ {  8, 1, 1 }, { 16, 2, 1 }, {  0, 0, 0 } }} },
>>> +	{ DRM_FORMAT_NV42,	V4L2_PIX_FMT_NV42,	2, {{ {  8, 1, 1 }, { 16, 1, 1 }, {  0, 0, 0 } }} },
>>> +}};
>>> +
>>> +} /* namespace */
>>
>> I think this table will be easier to manage, but is there anyway we can
>> keep a common table shared between the v4l2 library and libcamera?
>>
>> Actually - before that - Do we need this information in libcamera :D
>>
>> We need to identify mappings between DRM formats and V4L2 formats, but
>> perhaps we don't actually need the pixel specific data ....?
> 
> We may not need all the information in libcamera, but I think it could
> still be potentially useful for pipeline handlers, depending on their
> individual needs. In any case, I believe we should move this array to
> libcamera and export it for the V4L2 compatibility layer. We should also
> create a set of helper functions to look up entries and perform
> calculations. All this isn't part of this series, but it still paves the
> way in that direction.

Sure, fine by me :-D

--
Kieran


> 
>>> +
>>>  /* \todo make libcamera export these */
>>>  unsigned int V4L2CameraProxy::bplMultiplier(uint32_t format)
>>>  {
>>> -	switch (format) {
>>> -	case V4L2_PIX_FMT_NV12:
>>> -	case V4L2_PIX_FMT_NV21:
>>> -	case V4L2_PIX_FMT_NV16:
>>> -	case V4L2_PIX_FMT_NV61:
>>> -	case V4L2_PIX_FMT_NV24:
>>> -	case V4L2_PIX_FMT_NV42:
>>> -		return 1;
>>> -	case V4L2_PIX_FMT_BGR24:
>>> -	case V4L2_PIX_FMT_RGB24:
>>> -		return 3;
>>> -	case V4L2_PIX_FMT_ARGB32:
>>> -		return 4;
>>> -	case V4L2_PIX_FMT_VYUY:
>>> -	case V4L2_PIX_FMT_YVYU:
>>> -	case V4L2_PIX_FMT_UYVY:
>>> -	case V4L2_PIX_FMT_YUYV:
>>> -		return 2;
>>> -	default:
>>> +	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)
>>>  {
>>> -	switch (format) {
>>> -	case V4L2_PIX_FMT_NV12:
>>> -	case V4L2_PIX_FMT_NV21:
>>> -		return width * height * 3 / 2;
>>> -	case V4L2_PIX_FMT_NV16:
>>> -	case V4L2_PIX_FMT_NV61:
>>> -		return width * height * 2;
>>> -	case V4L2_PIX_FMT_NV24:
>>> -	case V4L2_PIX_FMT_NV42:
>>> -		return width * height * 3;
>>> -	case V4L2_PIX_FMT_BGR24:
>>> -	case V4L2_PIX_FMT_RGB24:
>>> -		return width * height * 3;
>>> -	case V4L2_PIX_FMT_ARGB32:
>>> -		return width * height * 4;
>>> -	case V4L2_PIX_FMT_VYUY:
>>> -	case V4L2_PIX_FMT_YVYU:
>>> -	case V4L2_PIX_FMT_UYVY:
>>> -	case V4L2_PIX_FMT_YUYV:
>>> -		return width * height * 2;
>>> -	default:
>>> +	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)
>>>  {
>>> -	switch (format) {
>>> -	/* 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:
>>> -		return DRM_FORMAT_NV16;
>>> -	case V4L2_PIX_FMT_NV61:
>>> -		return DRM_FORMAT_NV61;
>>> -	case V4L2_PIX_FMT_NV12:
>>> -		return DRM_FORMAT_NV12;
>>> -	case V4L2_PIX_FMT_NV21:
>>> -		return DRM_FORMAT_NV21;
>>> -	case V4L2_PIX_FMT_NV24:
>>> -		return DRM_FORMAT_NV24;
>>> -	case V4L2_PIX_FMT_NV42:
>>> -		return DRM_FORMAT_NV42;
>>> -	default:
>>> +	auto info = std::find_if(pixelFormatInfo.begin(), pixelFormatInfo.end(),
>>> +				 [format](const PixelFormatInfo &info) {
>>> +					 return info.v4l2Format == format;
>>> +				 });
>>> +	if (info == pixelFormatInfo.end())
>>>  		return format;
>>> -	};
>>> +
>>> +	return info->format;
>>>  }
>>>  
>>>  uint32_t V4L2CameraProxy::drmToV4L2(PixelFormat format)
>>>  {
>>> -	switch (format) {
>>> -	/* 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. */
>>> -	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;
>>> -	case DRM_FORMAT_NV24:
>>> -		return V4L2_PIX_FMT_NV24;
>>> -	case DRM_FORMAT_NV42:
>>> -		return V4L2_PIX_FMT_NV42;
>>> -	default:
>>> +	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;
>>>  }
>>>
>
Kieran Bingham Jan. 6, 2020, 5:01 p.m. UTC | #4
<snip>

>> We may not need all the information in libcamera, but I think it could
>> still be potentially useful for pipeline handlers, depending on their
>> individual needs. In any case, I believe we should move this array to
>> libcamera and export it for the V4L2 compatibility layer. We should also
>> create a set of helper functions to look up entries and perform
>> calculations. All this isn't part of this series, but it still paves the
>> way in that direction.
> 
> Sure, fine by me :-D


Ahem, in which case,

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

<snip>
Jacopo Mondi Jan. 7, 2020, 10:17 a.m. UTC | #5
Hi Laurent,

On Mon, Jan 06, 2020 at 06:14:17PM +0200, Laurent Pinchart wrote:
> Create a PixelFormatInfo structure to store information about a format,
> and add a global array of format info for all the formats currently
> supported. Move the format helpers to use the information from the
> array.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
>  src/v4l2/v4l2_camera_proxy.cpp | 180 +++++++++++++--------------------
>  1 file changed, 70 insertions(+), 110 deletions(-)
>
> diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp
> index 6a222d702e13..b8c1a53af1c2 100644
> --- a/src/v4l2/v4l2_camera_proxy.cpp
> +++ b/src/v4l2/v4l2_camera_proxy.cpp
> @@ -509,134 +509,94 @@ int V4L2CameraProxy::ioctl(unsigned long request, void *arg)
>  	return ret;
>  }
>
> +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 {
> +
> +constexpr std::array<PixelFormatInfo, 13> pixelFormatInfo = {{
> +	/* RGB formats. */
> +	{ DRM_FORMAT_RGB888,	V4L2_PIX_FMT_BGR24,	1, {{ { 24, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
> +	{ DRM_FORMAT_BGR888,	V4L2_PIX_FMT_RGB24,	1, {{ { 24, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
> +	{ DRM_FORMAT_BGRA8888,	V4L2_PIX_FMT_ARGB32,	1, {{ { 32, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
> +	/* YUV packed formats. */
> +	{ DRM_FORMAT_UYVY,	V4L2_PIX_FMT_UYVY,	1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
> +	{ DRM_FORMAT_VYUY,	V4L2_PIX_FMT_VYUY,	1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
> +	{ DRM_FORMAT_YUYV,	V4L2_PIX_FMT_YUYV,	1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
> +	{ DRM_FORMAT_YVYU,	V4L2_PIX_FMT_YVYU,	1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
> +	/* YUY planar formats. */
> +	{ DRM_FORMAT_NV12,	V4L2_PIX_FMT_NV12,	2, {{ {  8, 1, 1 }, { 16, 2, 2 }, {  0, 0, 0 } }} },
> +	{ DRM_FORMAT_NV21,	V4L2_PIX_FMT_NV21,	2, {{ {  8, 1, 1 }, { 16, 2, 2 }, {  0, 0, 0 } }} },
> +	{ DRM_FORMAT_NV16,	V4L2_PIX_FMT_NV16,	2, {{ {  8, 1, 1 }, { 16, 2, 1 }, {  0, 0, 0 } }} },
> +	{ DRM_FORMAT_NV61,	V4L2_PIX_FMT_NV61,	2, {{ {  8, 1, 1 }, { 16, 2, 1 }, {  0, 0, 0 } }} },
> +	{ DRM_FORMAT_NV24,	V4L2_PIX_FMT_NV24,	2, {{ {  8, 1, 1 }, { 16, 2, 1 }, {  0, 0, 0 } }} },
> +	{ DRM_FORMAT_NV42,	V4L2_PIX_FMT_NV42,	2, {{ {  8, 1, 1 }, { 16, 1, 1 }, {  0, 0, 0 } }} },
> +}};

While the table seems correct, I wonder

> +
> +} /* namespace */
> +
>  /* \todo make libcamera export these */
>  unsigned int V4L2CameraProxy::bplMultiplier(uint32_t format)
>  {
> -	switch (format) {
> -	case V4L2_PIX_FMT_NV12:
> -	case V4L2_PIX_FMT_NV21:
> -	case V4L2_PIX_FMT_NV16:
> -	case V4L2_PIX_FMT_NV61:
> -	case V4L2_PIX_FMT_NV24:
> -	case V4L2_PIX_FMT_NV42:
> -		return 1;
> -	case V4L2_PIX_FMT_BGR24:
> -	case V4L2_PIX_FMT_RGB24:
> -		return 3;
> -	case V4L2_PIX_FMT_ARGB32:
> -		return 4;
> -	case V4L2_PIX_FMT_VYUY:
> -	case V4L2_PIX_FMT_YVYU:
> -	case V4L2_PIX_FMT_UYVY:
> -	case V4L2_PIX_FMT_YUYV:
> -		return 2;
> -	default:
> +	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;

How does this work for planar YUV420 format where, if I read it
correctly, the Cr and Crb planes portion has half the width of the Y
one ?
https://www.kernel.org/doc/html/v5.4/media/uapi/v4l/pixfmt-yuv420.html

Otherwise, the table looks correct and should be made a library-wide
component later

Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>

Thanks
  j
>  }
>
>  unsigned int V4L2CameraProxy::imageSize(uint32_t format, unsigned int width,
>  					unsigned int height)
>  {
> -	switch (format) {
> -	case V4L2_PIX_FMT_NV12:
> -	case V4L2_PIX_FMT_NV21:
> -		return width * height * 3 / 2;
> -	case V4L2_PIX_FMT_NV16:
> -	case V4L2_PIX_FMT_NV61:
> -		return width * height * 2;
> -	case V4L2_PIX_FMT_NV24:
> -	case V4L2_PIX_FMT_NV42:
> -		return width * height * 3;
> -	case V4L2_PIX_FMT_BGR24:
> -	case V4L2_PIX_FMT_RGB24:
> -		return width * height * 3;
> -	case V4L2_PIX_FMT_ARGB32:
> -		return width * height * 4;
> -	case V4L2_PIX_FMT_VYUY:
> -	case V4L2_PIX_FMT_YVYU:
> -	case V4L2_PIX_FMT_UYVY:
> -	case V4L2_PIX_FMT_YUYV:
> -		return width * height * 2;
> -	default:
> +	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)
>  {
> -	switch (format) {
> -	/* 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:
> -		return DRM_FORMAT_NV16;
> -	case V4L2_PIX_FMT_NV61:
> -		return DRM_FORMAT_NV61;
> -	case V4L2_PIX_FMT_NV12:
> -		return DRM_FORMAT_NV12;
> -	case V4L2_PIX_FMT_NV21:
> -		return DRM_FORMAT_NV21;
> -	case V4L2_PIX_FMT_NV24:
> -		return DRM_FORMAT_NV24;
> -	case V4L2_PIX_FMT_NV42:
> -		return DRM_FORMAT_NV42;
> -	default:
> +	auto info = std::find_if(pixelFormatInfo.begin(), pixelFormatInfo.end(),
> +				 [format](const PixelFormatInfo &info) {
> +					 return info.v4l2Format == format;
> +				 });
> +	if (info == pixelFormatInfo.end())
>  		return format;
> -	};
> +
> +	return info->format;
>  }
>
>  uint32_t V4L2CameraProxy::drmToV4L2(PixelFormat format)
>  {
> -	switch (format) {
> -	/* 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. */
> -	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;
> -	case DRM_FORMAT_NV24:
> -		return V4L2_PIX_FMT_NV24;
> -	case DRM_FORMAT_NV42:
> -		return V4L2_PIX_FMT_NV42;
> -	default:
> +	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;
>  }
> --
> Regards,
>
> Laurent Pinchart
>
> _______________________________________________
> libcamera-devel mailing list
> libcamera-devel@lists.libcamera.org
> https://lists.libcamera.org/listinfo/libcamera-devel
Laurent Pinchart Jan. 7, 2020, 8:38 p.m. UTC | #6
Hi Jacopo,

On Tue, Jan 07, 2020 at 11:17:06AM +0100, Jacopo Mondi wrote:
> On Mon, Jan 06, 2020 at 06:14:17PM +0200, Laurent Pinchart wrote:
> > Create a PixelFormatInfo structure to store information about a format,
> > and add a global array of format info for all the formats currently
> > supported. Move the format helpers to use the information from the
> > array.
> >
> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > ---
> >  src/v4l2/v4l2_camera_proxy.cpp | 180 +++++++++++++--------------------
> >  1 file changed, 70 insertions(+), 110 deletions(-)
> >
> > diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp
> > index 6a222d702e13..b8c1a53af1c2 100644
> > --- a/src/v4l2/v4l2_camera_proxy.cpp
> > +++ b/src/v4l2/v4l2_camera_proxy.cpp
> > @@ -509,134 +509,94 @@ int V4L2CameraProxy::ioctl(unsigned long request, void *arg)
> >  	return ret;
> >  }
> >
> > +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 {
> > +
> > +constexpr std::array<PixelFormatInfo, 13> pixelFormatInfo = {{
> > +	/* RGB formats. */
> > +	{ DRM_FORMAT_RGB888,	V4L2_PIX_FMT_BGR24,	1, {{ { 24, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
> > +	{ DRM_FORMAT_BGR888,	V4L2_PIX_FMT_RGB24,	1, {{ { 24, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
> > +	{ DRM_FORMAT_BGRA8888,	V4L2_PIX_FMT_ARGB32,	1, {{ { 32, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
> > +	/* YUV packed formats. */
> > +	{ DRM_FORMAT_UYVY,	V4L2_PIX_FMT_UYVY,	1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
> > +	{ DRM_FORMAT_VYUY,	V4L2_PIX_FMT_VYUY,	1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
> > +	{ DRM_FORMAT_YUYV,	V4L2_PIX_FMT_YUYV,	1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
> > +	{ DRM_FORMAT_YVYU,	V4L2_PIX_FMT_YVYU,	1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
> > +	/* YUY planar formats. */
> > +	{ DRM_FORMAT_NV12,	V4L2_PIX_FMT_NV12,	2, {{ {  8, 1, 1 }, { 16, 2, 2 }, {  0, 0, 0 } }} },
> > +	{ DRM_FORMAT_NV21,	V4L2_PIX_FMT_NV21,	2, {{ {  8, 1, 1 }, { 16, 2, 2 }, {  0, 0, 0 } }} },
> > +	{ DRM_FORMAT_NV16,	V4L2_PIX_FMT_NV16,	2, {{ {  8, 1, 1 }, { 16, 2, 1 }, {  0, 0, 0 } }} },
> > +	{ DRM_FORMAT_NV61,	V4L2_PIX_FMT_NV61,	2, {{ {  8, 1, 1 }, { 16, 2, 1 }, {  0, 0, 0 } }} },
> > +	{ DRM_FORMAT_NV24,	V4L2_PIX_FMT_NV24,	2, {{ {  8, 1, 1 }, { 16, 2, 1 }, {  0, 0, 0 } }} },
> > +	{ DRM_FORMAT_NV42,	V4L2_PIX_FMT_NV42,	2, {{ {  8, 1, 1 }, { 16, 1, 1 }, {  0, 0, 0 } }} },
> > +}};
> 
> While the table seems correct, I wonder
> 
> > +
> > +} /* namespace */
> > +
> >  /* \todo make libcamera export these */
> >  unsigned int V4L2CameraProxy::bplMultiplier(uint32_t format)
> >  {
> > -	switch (format) {
> > -	case V4L2_PIX_FMT_NV12:
> > -	case V4L2_PIX_FMT_NV21:
> > -	case V4L2_PIX_FMT_NV16:
> > -	case V4L2_PIX_FMT_NV61:
> > -	case V4L2_PIX_FMT_NV24:
> > -	case V4L2_PIX_FMT_NV42:
> > -		return 1;
> > -	case V4L2_PIX_FMT_BGR24:
> > -	case V4L2_PIX_FMT_RGB24:
> > -		return 3;
> > -	case V4L2_PIX_FMT_ARGB32:
> > -		return 4;
> > -	case V4L2_PIX_FMT_VYUY:
> > -	case V4L2_PIX_FMT_YVYU:
> > -	case V4L2_PIX_FMT_UYVY:
> > -	case V4L2_PIX_FMT_YUYV:
> > -		return 2;
> > -	default:
> > +	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;
> 
> How does this work for planar YUV420 format where, if I read it
> correctly, the Cr and Crb planes portion has half the width of the Y
> one ?
> https://www.kernel.org/doc/html/v5.4/media/uapi/v4l/pixfmt-yuv420.html

Short answer, it doesn't :-) The bplMultipler helper is ill-defined for
some formats, we need a set of helpers that will take all formats into
account.

> Otherwise, the table looks correct and should be made a library-wide
> component later
> 
> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
> 
> >  }
> >
> >  unsigned int V4L2CameraProxy::imageSize(uint32_t format, unsigned int width,
> >  					unsigned int height)
> >  {
> > -	switch (format) {
> > -	case V4L2_PIX_FMT_NV12:
> > -	case V4L2_PIX_FMT_NV21:
> > -		return width * height * 3 / 2;
> > -	case V4L2_PIX_FMT_NV16:
> > -	case V4L2_PIX_FMT_NV61:
> > -		return width * height * 2;
> > -	case V4L2_PIX_FMT_NV24:
> > -	case V4L2_PIX_FMT_NV42:
> > -		return width * height * 3;
> > -	case V4L2_PIX_FMT_BGR24:
> > -	case V4L2_PIX_FMT_RGB24:
> > -		return width * height * 3;
> > -	case V4L2_PIX_FMT_ARGB32:
> > -		return width * height * 4;
> > -	case V4L2_PIX_FMT_VYUY:
> > -	case V4L2_PIX_FMT_YVYU:
> > -	case V4L2_PIX_FMT_UYVY:
> > -	case V4L2_PIX_FMT_YUYV:
> > -		return width * height * 2;
> > -	default:
> > +	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)
> >  {
> > -	switch (format) {
> > -	/* 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:
> > -		return DRM_FORMAT_NV16;
> > -	case V4L2_PIX_FMT_NV61:
> > -		return DRM_FORMAT_NV61;
> > -	case V4L2_PIX_FMT_NV12:
> > -		return DRM_FORMAT_NV12;
> > -	case V4L2_PIX_FMT_NV21:
> > -		return DRM_FORMAT_NV21;
> > -	case V4L2_PIX_FMT_NV24:
> > -		return DRM_FORMAT_NV24;
> > -	case V4L2_PIX_FMT_NV42:
> > -		return DRM_FORMAT_NV42;
> > -	default:
> > +	auto info = std::find_if(pixelFormatInfo.begin(), pixelFormatInfo.end(),
> > +				 [format](const PixelFormatInfo &info) {
> > +					 return info.v4l2Format == format;
> > +				 });
> > +	if (info == pixelFormatInfo.end())
> >  		return format;
> > -	};
> > +
> > +	return info->format;
> >  }
> >
> >  uint32_t V4L2CameraProxy::drmToV4L2(PixelFormat format)
> >  {
> > -	switch (format) {
> > -	/* 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. */
> > -	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;
> > -	case DRM_FORMAT_NV24:
> > -		return V4L2_PIX_FMT_NV24;
> > -	case DRM_FORMAT_NV42:
> > -		return V4L2_PIX_FMT_NV42;
> > -	default:
> > +	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;
> >  }

Patch

diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp
index 6a222d702e13..b8c1a53af1c2 100644
--- a/src/v4l2/v4l2_camera_proxy.cpp
+++ b/src/v4l2/v4l2_camera_proxy.cpp
@@ -509,134 +509,94 @@  int V4L2CameraProxy::ioctl(unsigned long request, void *arg)
 	return ret;
 }
 
+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 {
+
+constexpr std::array<PixelFormatInfo, 13> pixelFormatInfo = {{
+	/* RGB formats. */
+	{ DRM_FORMAT_RGB888,	V4L2_PIX_FMT_BGR24,	1, {{ { 24, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
+	{ DRM_FORMAT_BGR888,	V4L2_PIX_FMT_RGB24,	1, {{ { 24, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
+	{ DRM_FORMAT_BGRA8888,	V4L2_PIX_FMT_ARGB32,	1, {{ { 32, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
+	/* YUV packed formats. */
+	{ DRM_FORMAT_UYVY,	V4L2_PIX_FMT_UYVY,	1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
+	{ DRM_FORMAT_VYUY,	V4L2_PIX_FMT_VYUY,	1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
+	{ DRM_FORMAT_YUYV,	V4L2_PIX_FMT_YUYV,	1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
+	{ DRM_FORMAT_YVYU,	V4L2_PIX_FMT_YVYU,	1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },
+	/* YUY planar formats. */
+	{ DRM_FORMAT_NV12,	V4L2_PIX_FMT_NV12,	2, {{ {  8, 1, 1 }, { 16, 2, 2 }, {  0, 0, 0 } }} },
+	{ DRM_FORMAT_NV21,	V4L2_PIX_FMT_NV21,	2, {{ {  8, 1, 1 }, { 16, 2, 2 }, {  0, 0, 0 } }} },
+	{ DRM_FORMAT_NV16,	V4L2_PIX_FMT_NV16,	2, {{ {  8, 1, 1 }, { 16, 2, 1 }, {  0, 0, 0 } }} },
+	{ DRM_FORMAT_NV61,	V4L2_PIX_FMT_NV61,	2, {{ {  8, 1, 1 }, { 16, 2, 1 }, {  0, 0, 0 } }} },
+	{ DRM_FORMAT_NV24,	V4L2_PIX_FMT_NV24,	2, {{ {  8, 1, 1 }, { 16, 2, 1 }, {  0, 0, 0 } }} },
+	{ DRM_FORMAT_NV42,	V4L2_PIX_FMT_NV42,	2, {{ {  8, 1, 1 }, { 16, 1, 1 }, {  0, 0, 0 } }} },
+}};
+
+} /* namespace */
+
 /* \todo make libcamera export these */
 unsigned int V4L2CameraProxy::bplMultiplier(uint32_t format)
 {
-	switch (format) {
-	case V4L2_PIX_FMT_NV12:
-	case V4L2_PIX_FMT_NV21:
-	case V4L2_PIX_FMT_NV16:
-	case V4L2_PIX_FMT_NV61:
-	case V4L2_PIX_FMT_NV24:
-	case V4L2_PIX_FMT_NV42:
-		return 1;
-	case V4L2_PIX_FMT_BGR24:
-	case V4L2_PIX_FMT_RGB24:
-		return 3;
-	case V4L2_PIX_FMT_ARGB32:
-		return 4;
-	case V4L2_PIX_FMT_VYUY:
-	case V4L2_PIX_FMT_YVYU:
-	case V4L2_PIX_FMT_UYVY:
-	case V4L2_PIX_FMT_YUYV:
-		return 2;
-	default:
+	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)
 {
-	switch (format) {
-	case V4L2_PIX_FMT_NV12:
-	case V4L2_PIX_FMT_NV21:
-		return width * height * 3 / 2;
-	case V4L2_PIX_FMT_NV16:
-	case V4L2_PIX_FMT_NV61:
-		return width * height * 2;
-	case V4L2_PIX_FMT_NV24:
-	case V4L2_PIX_FMT_NV42:
-		return width * height * 3;
-	case V4L2_PIX_FMT_BGR24:
-	case V4L2_PIX_FMT_RGB24:
-		return width * height * 3;
-	case V4L2_PIX_FMT_ARGB32:
-		return width * height * 4;
-	case V4L2_PIX_FMT_VYUY:
-	case V4L2_PIX_FMT_YVYU:
-	case V4L2_PIX_FMT_UYVY:
-	case V4L2_PIX_FMT_YUYV:
-		return width * height * 2;
-	default:
+	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)
 {
-	switch (format) {
-	/* 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:
-		return DRM_FORMAT_NV16;
-	case V4L2_PIX_FMT_NV61:
-		return DRM_FORMAT_NV61;
-	case V4L2_PIX_FMT_NV12:
-		return DRM_FORMAT_NV12;
-	case V4L2_PIX_FMT_NV21:
-		return DRM_FORMAT_NV21;
-	case V4L2_PIX_FMT_NV24:
-		return DRM_FORMAT_NV24;
-	case V4L2_PIX_FMT_NV42:
-		return DRM_FORMAT_NV42;
-	default:
+	auto info = std::find_if(pixelFormatInfo.begin(), pixelFormatInfo.end(),
+				 [format](const PixelFormatInfo &info) {
+					 return info.v4l2Format == format;
+				 });
+	if (info == pixelFormatInfo.end())
 		return format;
-	};
+
+	return info->format;
 }
 
 uint32_t V4L2CameraProxy::drmToV4L2(PixelFormat format)
 {
-	switch (format) {
-	/* 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. */
-	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;
-	case DRM_FORMAT_NV24:
-		return V4L2_PIX_FMT_NV24;
-	case DRM_FORMAT_NV42:
-		return V4L2_PIX_FMT_NV42;
-	default:
+	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;
 }