[{"id":24820,"web_url":"https://patchwork.libcamera.org/comment/24820/","msgid":"<Yw03cj32TbFX2IYx@pendragon.ideasonboard.com>","date":"2022-08-29T22:02:26","subject":"Re: [libcamera-devel] [PATCH v3 2/7] libcamera: v4l2_device: Adjust\n\tcolorspace based on pixel format","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Umang,\n\nThank you for the patch.\n\nOn Mon, Aug 29, 2022 at 10:07:37PM +0530, Umang Jain via libcamera-devel wrote:\n> V4L2 has no \"none\" YCbCr encoding, and thus reports an encoding for all\n> formats, including RGB and raw formats. This causes the libcamera\n> ColorSpace to report incorrect encodings for non-YUV formats. Fix it by\n> overriding the encoding reported by the kernel to YCbCrEncoding::None\n> for non-YUV pixel formats and media bus formats.\n> \n> Similarly, override the quantization range of non-YUV formats to full\n> range, as limited range isn't used for RGB and raw formats.\n> \n> Signed-off-by: Umang Jain <umang.jain@ideasonboard.com>\n> ---\n>  include/libcamera/internal/v4l2_device.h |  5 +++-\n>  src/libcamera/v4l2_device.cpp            | 29 ++++++++++++++++++---\n>  src/libcamera/v4l2_subdevice.cpp         | 32 ++++++++++++++++++++++--\n>  src/libcamera/v4l2_videodevice.cpp       | 12 ++++++---\n>  4 files changed, 67 insertions(+), 11 deletions(-)\n> \n> diff --git a/include/libcamera/internal/v4l2_device.h b/include/libcamera/internal/v4l2_device.h\n> index a52a5f2c..75304be1 100644\n> --- a/include/libcamera/internal/v4l2_device.h\n> +++ b/include/libcamera/internal/v4l2_device.h\n> @@ -22,6 +22,8 @@\n>  #include <libcamera/color_space.h>\n>  #include <libcamera/controls.h>\n>  \n> +#include \"libcamera/internal/formats.h\"\n> +\n>  namespace libcamera {\n>  \n>  class EventNotifier;\n> @@ -59,7 +61,8 @@ protected:\n>  \tint fd() const { return fd_.get(); }\n>  \n>  \ttemplate<typename T>\n> -\tstatic std::optional<ColorSpace> toColorSpace(const T &v4l2Format);\n> +\tstatic std::optional<ColorSpace> toColorSpace(const T &v4l2Format,\n> +\t\t\t\t\t\t      PixelFormatInfo::ColourEncoding colourEncoding);\n>  \n>  \ttemplate<typename T>\n>  \tstatic int fromColorSpace(const std::optional<ColorSpace> &colorSpace, T &v4l2Format);\n> diff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp\n> index b22a981f..301620f8 100644\n> --- a/src/libcamera/v4l2_device.cpp\n> +++ b/src/libcamera/v4l2_device.cpp\n> @@ -24,6 +24,7 @@\n>  #include <libcamera/base/log.h>\n>  #include <libcamera/base/utils.h>\n>  \n> +#include \"libcamera/internal/formats.h\"\n>  #include \"libcamera/internal/sysfs.h\"\n>  \n>  /**\n> @@ -805,6 +806,7 @@ static const std::map<ColorSpace::Range, v4l2_quantization> rangeToV4l2 = {\n>  /**\n>   * \\brief Convert the color space fields in a V4L2 format to a ColorSpace\n>   * \\param[in] v4l2Format A V4L2 format containing color space information\n> + * \\param[in] colourEncoding Type of colour encoding\n>   *\n>   * The colorspace, ycbcr_enc, xfer_func and quantization fields within a\n>   * V4L2 format structure are converted to a corresponding ColorSpace.\n> @@ -816,7 +818,8 @@ static const std::map<ColorSpace::Range, v4l2_quantization> rangeToV4l2 = {\n>   * \\retval std::nullopt One or more V4L2 color space fields were not recognised\n>   */\n>  template<typename T>\n> -std::optional<ColorSpace> V4L2Device::toColorSpace(const T &v4l2Format)\n> +std::optional<ColorSpace> V4L2Device::toColorSpace(const T &v4l2Format,\n> +\t\t\t\t\t\t   PixelFormatInfo::ColourEncoding colourEncoding)\n>  {\n>  \tauto itColor = v4l2ToColorSpace.find(v4l2Format.colorspace);\n>  \tif (itColor == v4l2ToColorSpace.end())\n> @@ -839,6 +842,14 @@ std::optional<ColorSpace> V4L2Device::toColorSpace(const T &v4l2Format)\n>  \t\t\treturn std::nullopt;\n>  \n>  \t\tcolorSpace.ycbcrEncoding = itYcbcrEncoding->second;\n> +\n> +\t\t/*\n> +\t\t * V4L2 has no \"none\" encoding, override the value returned by\n> +\t\t * the kernel for non-YUV formats as YCbCr encoding isn't\n> +\t\t * applicable in that case.\n> +\t\t */\n> +\t\tif (colourEncoding != PixelFormatInfo::ColourEncodingYUV)\n> +\t\t\tcolorSpace.ycbcrEncoding = ColorSpace::YcbcrEncoding::None;\n>  \t}\n>  \n>  \tif (v4l2Format.quantization != V4L2_QUANTIZATION_DEFAULT) {\n> @@ -847,14 +858,24 @@ std::optional<ColorSpace> V4L2Device::toColorSpace(const T &v4l2Format)\n>  \t\t\treturn std::nullopt;\n>  \n>  \t\tcolorSpace.range = itRange->second;\n> +\n> +\t\t/*\n> +\t\t * \"Limited\" quantization range is only meant for YUV formats.\n> +\t\t * Override the range to \"Full\" for all other formats.\n> +\t\t */\n> +\t\tif (colourEncoding != PixelFormatInfo::ColourEncodingYUV)\n> +\t\t\tcolorSpace.range = ColorSpace::Range::Full;\n>  \t}\n>  \n>  \treturn colorSpace;\n>  }\n>  \n> -template std::optional<ColorSpace> V4L2Device::toColorSpace(const struct v4l2_pix_format &);\n> -template std::optional<ColorSpace> V4L2Device::toColorSpace(const struct v4l2_pix_format_mplane &);\n> -template std::optional<ColorSpace> V4L2Device::toColorSpace(const struct v4l2_mbus_framefmt &);\n> +template std::optional<ColorSpace> V4L2Device::toColorSpace(const struct v4l2_pix_format &,\n> +\t\t\t\t\t\t\t    PixelFormatInfo::ColourEncoding);\n> +template std::optional<ColorSpace> V4L2Device::toColorSpace(const struct v4l2_pix_format_mplane &,\n> +\t\t\t\t\t\t\t    PixelFormatInfo::ColourEncoding);\n> +template std::optional<ColorSpace> V4L2Device::toColorSpace(const struct v4l2_mbus_framefmt &,\n> +\t\t\t\t\t\t\t    PixelFormatInfo::ColourEncoding);\n>  \n>  /**\n>   * \\brief Fill in the color space fields of a V4L2 format from a ColorSpace\n> diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp\n> index 07a0bb07..0389f1b3 100644\n> --- a/src/libcamera/v4l2_subdevice.cpp\n> +++ b/src/libcamera/v4l2_subdevice.cpp\n> @@ -502,8 +502,22 @@ int V4L2Subdevice::getFormat(unsigned int pad, V4L2SubdeviceFormat *format,\n>  \n>  \tformat->size.width = subdevFmt.format.width;\n>  \tformat->size.height = subdevFmt.format.height;\n> +\n> +\tPixelFormatInfo::ColourEncoding colourEncoding;\n> +\tauto iter = formatInfoMap.find(subdevFmt.format.code);\n> +\tif (iter != formatInfoMap.end()) {\n> +\t\tcolourEncoding = iter->second.colourEncoding;\n> +\t} else {\n> +\t\tLOG(V4L2, Warning)\n> +\t\t\t<< \"Unknown subdev format \"\n> +\t\t\t<< utils::hex(subdevFmt.format.code, 4)\n> +\t\t\t<< \", defaulting to RGB encoding\";\n> +\n> +\t\tcolourEncoding = PixelFormatInfo::ColourEncodingRGB;\n> +\t}\n> +\n>  \tformat->mbus_code = subdevFmt.format.code;\n\nI'd move this line above just after size.height, to keep all the color\nspace code grouped together.\n\n> -\tformat->colorSpace = toColorSpace(subdevFmt.format);\n> +\tformat->colorSpace = toColorSpace(subdevFmt.format, colourEncoding);\n>  \n>  \treturn 0;\n>  }\n> @@ -548,8 +562,22 @@ int V4L2Subdevice::setFormat(unsigned int pad, V4L2SubdeviceFormat *format,\n>  \n>  \tformat->size.width = subdevFmt.format.width;\n>  \tformat->size.height = subdevFmt.format.height;\n> +\n> +\tPixelFormatInfo::ColourEncoding colourEncoding;\n> +\tauto iter = formatInfoMap.find(subdevFmt.format.code);\n> +\tif (iter != formatInfoMap.end()) {\n> +\t\tcolourEncoding = iter->second.colourEncoding;\n> +\t} else {\n> +\t\tLOG(V4L2, Warning)\n> +\t\t\t<< \"Unknown subdev format \"\n> +\t\t\t<< utils::hex(subdevFmt.format.code, 4)\n> +\t\t\t<< \", defaulting to RGB encoding\";\n> +\n> +\t\tcolourEncoding = PixelFormatInfo::ColourEncodingRGB;\n> +\t}\n> +\n>  \tformat->mbus_code = subdevFmt.format.code;\n\nSame here.\n\nReviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\n> -\tformat->colorSpace = toColorSpace(subdevFmt.format);\n> +\tformat->colorSpace = toColorSpace(subdevFmt.format, colourEncoding);\n>  \n>  \treturn 0;\n>  }\n> diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp\n> index 5a2d0e5b..0e3f5436 100644\n> --- a/src/libcamera/v4l2_videodevice.cpp\n> +++ b/src/libcamera/v4l2_videodevice.cpp\n> @@ -931,7 +931,8 @@ int V4L2VideoDevice::getFormatMultiplane(V4L2DeviceFormat *format)\n>  \tformat->size.height = pix->height;\n>  \tformat->fourcc = V4L2PixelFormat(pix->pixelformat);\n>  \tformat->planesCount = pix->num_planes;\n> -\tformat->colorSpace = toColorSpace(*pix);\n> +\tformat->colorSpace =\n> +\t\ttoColorSpace(*pix, PixelFormatInfo::info(format->fourcc).colourEncoding);\n>  \n>  \tfor (unsigned int i = 0; i < format->planesCount; ++i) {\n>  \t\tformat->planes[i].bpl = pix->plane_fmt[i].bytesperline;\n> @@ -987,7 +988,8 @@ int V4L2VideoDevice::trySetFormatMultiplane(V4L2DeviceFormat *format, bool set)\n>  \t\tformat->planes[i].bpl = pix->plane_fmt[i].bytesperline;\n>  \t\tformat->planes[i].size = pix->plane_fmt[i].sizeimage;\n>  \t}\n> -\tformat->colorSpace = toColorSpace(*pix);\n> +\tformat->colorSpace =\n> +\t\ttoColorSpace(*pix, PixelFormatInfo::info(format->fourcc).colourEncoding);\n>  \n>  \treturn 0;\n>  }\n> @@ -1011,7 +1013,8 @@ int V4L2VideoDevice::getFormatSingleplane(V4L2DeviceFormat *format)\n>  \tformat->planesCount = 1;\n>  \tformat->planes[0].bpl = pix->bytesperline;\n>  \tformat->planes[0].size = pix->sizeimage;\n> -\tformat->colorSpace = toColorSpace(*pix);\n> +\tformat->colorSpace =\n> +\t\ttoColorSpace(*pix, PixelFormatInfo::info(format->fourcc).colourEncoding);\n>  \n>  \treturn 0;\n>  }\n> @@ -1053,7 +1056,8 @@ int V4L2VideoDevice::trySetFormatSingleplane(V4L2DeviceFormat *format, bool set)\n>  \tformat->planesCount = 1;\n>  \tformat->planes[0].bpl = pix->bytesperline;\n>  \tformat->planes[0].size = pix->sizeimage;\n> -\tformat->colorSpace = toColorSpace(*pix);\n> +\tformat->colorSpace =\n> +\t\ttoColorSpace(*pix, PixelFormatInfo::info(format->fourcc).colourEncoding);\n>  \n>  \treturn 0;\n>  }","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id E8D77C0DA4\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 29 Aug 2022 22:02:38 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 5741761FC0;\n\tTue, 30 Aug 2022 00:02:38 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id DE21061FBC\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 30 Aug 2022 00:02:36 +0200 (CEST)","from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi\n\t[62.78.145.57])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 3777A481;\n\tTue, 30 Aug 2022 00:02:36 +0200 (CEST)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1661810558;\n\tbh=NvZXMpJX+P0AZgfBAMcfCtgu884QHh5zVUME/5a7IEY=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc:\n\tFrom;\n\tb=zvcXAX3xLtdflgToWDSqc17Xd+PzDpfT3e3M96HvvuUPTL/aGOuVAxl4xrJgQx4qZ\n\tHX5/XT6rlzuHGRF5HgiDgZRiwofvOWcia1eTL6+mTe1qDzmLdguwrotrYqpM8DSHRV\n\tp5iFeJ/2VL2KBRt7H7wwyvTOdh1aWkZRDPOi89LSZremZGiVaMm6ovsbytuc2dCvdL\n\t/icbaJIU7R8uQkq9WDpG9HGcikK2D5oeCQyl1hfUAUWszWmFi4PA2gY5jI2H2Orhjc\n\tF4J2CM+vv/o979RyeT+2xIOCQkYQrtMlL9WN0B8gIITNAH07kUWMcjhPcY/hvihfg6\n\tYuKQV6GCAAwOQ==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1661810556;\n\tbh=NvZXMpJX+P0AZgfBAMcfCtgu884QHh5zVUME/5a7IEY=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=TjoRTT0hfDhzWshcTldePbxXy1e/JQAQqFIafLyvxxYvhr74fOXw75A2n10tTOfTf\n\tlup4E3gLmmWNnRUSFxTPt5CJ+6S+3U5op3U9YE8OCxp+ekB0OSFwQNDojelWRgEzR5\n\tdyMfoXZ57sHJWpRILYBLbLPEZqDfMMpNi4yc371o="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"TjoRTT0h\"; dkim-atps=neutral","Date":"Tue, 30 Aug 2022 01:02:26 +0300","To":"Umang Jain <umang.jain@ideasonboard.com>","Message-ID":"<Yw03cj32TbFX2IYx@pendragon.ideasonboard.com>","References":"<20220829163742.1006102-1-umang.jain@ideasonboard.com>\n\t<20220829163742.1006102-3-umang.jain@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20220829163742.1006102-3-umang.jain@ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH v3 2/7] libcamera: v4l2_device: Adjust\n\tcolorspace based on pixel format","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","From":"Laurent Pinchart via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>","Reply-To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]