From patchwork Fri Mar 1 21:20:50 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 19592 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id BBDC1C3260 for ; Fri, 1 Mar 2024 21:21:23 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id EB36D62874; Fri, 1 Mar 2024 22:21:21 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="TBe84TG/"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 877BB62865 for ; Fri, 1 Mar 2024 22:21:20 +0100 (CET) Received: from pendragon.ideasonboard.com (89-27-53-110.bb.dnainternet.fi [89.27.53.110]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 1683DA9A; Fri, 1 Mar 2024 22:21:06 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1709328066; bh=3LkrSUFbAXG1cHSF3thfKl7/pxdzG1CXkpL1z9sYqCs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=TBe84TG/CjFSgAJyRdR0MoElxDQVQ2wJeLQmS70rWsHEREEHb4hfw35ZyNdf6XjEs 0saFv+R8jlAMNxLbBGkxJ4cQZx9biHjL/k8aPljUdijr8EfEt+L5Xr4fZ73zwk9kSi U/MhCTqMAlvABXPwn35nxdFAFSO2GIqiNDOVnwbw= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH/RFC 01/32] libcamera: v4l2_subdevice: Rename V4L2SubdeviceFormatInfo Date: Fri, 1 Mar 2024 23:20:50 +0200 Message-ID: <20240301212121.9072-2-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> References: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sakari Ailus Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The V4L2SubdeviceFormatInfo structure contains information about a media bus format, not a V4L2 subdevice format. Rename it to MediaBusFormatInfo to clarify its purpose. Rename the formatInfoMap map accordingly. Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi --- src/libcamera/v4l2_subdevice.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp index 6d0785b7b484..6c1df7812f07 100644 --- a/src/libcamera/v4l2_subdevice.cpp +++ b/src/libcamera/v4l2_subdevice.cpp @@ -39,24 +39,24 @@ LOG_DECLARE_CATEGORY(V4L2) namespace { /* - * \struct V4L2SubdeviceFormatInfo + * \struct MediaBusFormatInfo * \brief Information about media bus formats * \param bitsPerPixel Bits per pixel * \param name Name of MBUS format * \param colourEncoding Type of colour encoding */ -struct V4L2SubdeviceFormatInfo { +struct MediaBusFormatInfo { unsigned int bitsPerPixel; const char *name; PixelFormatInfo::ColourEncoding colourEncoding; }; /* - * \var formatInfoMap - * \brief A map that associates V4L2SubdeviceFormatInfo struct to V4L2 media + * \var mediaBusFormatInfo + * \brief A map that associates MediaBusFormatInfo struct to V4L2 media * bus codes */ -const std::map formatInfoMap = { +const std::map mediaBusFormatInfo = { /* This table is sorted to match the order in linux/media-bus-format.h */ { MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE, { 16, "RGB444_2X8_PADHI_BE", PixelFormatInfo::ColourEncodingRGB } }, { MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE, { 16, "RGB444_2X8_PADHI_LE", PixelFormatInfo::ColourEncodingRGB } }, @@ -237,8 +237,8 @@ const std::string V4L2SubdeviceFormat::toString() const */ uint8_t V4L2SubdeviceFormat::bitsPerPixel() const { - const auto it = formatInfoMap.find(mbus_code); - if (it == formatInfoMap.end()) { + const auto it = mediaBusFormatInfo.find(mbus_code); + if (it == mediaBusFormatInfo.end()) { LOG(V4L2, Error) << "No information available for format '" << *this << "'"; return 0; @@ -258,9 +258,9 @@ std::ostream &operator<<(std::ostream &out, const V4L2SubdeviceFormat &f) { out << f.size << "-"; - const auto it = formatInfoMap.find(f.mbus_code); + const auto it = mediaBusFormatInfo.find(f.mbus_code); - if (it == formatInfoMap.end()) + if (it == mediaBusFormatInfo.end()) out << utils::hex(f.mbus_code, 4); else out << it->second.name; @@ -511,8 +511,8 @@ std::optional V4L2Subdevice::toColorSpace(const v4l2_mbus_framefmt & return std::nullopt; PixelFormatInfo::ColourEncoding colourEncoding; - auto iter = formatInfoMap.find(format.code); - if (iter != formatInfoMap.end()) { + auto iter = mediaBusFormatInfo.find(format.code); + if (iter != mediaBusFormatInfo.end()) { colourEncoding = iter->second.colourEncoding; } else { LOG(V4L2, Warning) From patchwork Fri Mar 1 21:20:51 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 19593 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id F32E2BD160 for ; Fri, 1 Mar 2024 21:21:24 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id B660262878; Fri, 1 Mar 2024 22:21:24 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="Szqqv1Im"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6AB216285F for ; Fri, 1 Mar 2024 22:21:22 +0100 (CET) Received: from pendragon.ideasonboard.com (89-27-53-110.bb.dnainternet.fi [89.27.53.110]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id B6FA8D04; Fri, 1 Mar 2024 22:21:07 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1709328068; bh=VASb/OfOmSVeQPIoChZGdBqcGDKT9GS/R7dwXDr2ygQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Szqqv1Im264CoY64VQHm4zCeZM/H6fSYRMuZnb+OI3r/WVc/JDphe7IugVMy3gzsC 1YXH80oIv8hMLA0hzmJHv2wMtLP7Ny8rhHFhg1iyE4FfrmojN2zt2lsfNuCP8LY3/J 2dnYUD0MyCEHA4z/0HK3mZ9rTWuctfrLu7l75DtU= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH/RFC 02/32] libcamera: v4l2_subdevice: Add code member to MediaBusFormatInfo Date: Fri, 1 Mar 2024 23:20:51 +0200 Message-ID: <20240301212121.9072-3-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> References: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sakari Ailus Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" To prepare for exposing the MediaBusFormatInfo structure as an internal API, add a code member to the structure to store the media bus code. This makes MediaBusFormatInfo usable standalone, without having to externally associate the code related to the info. The entries in the mediaBusFormatInfo map are becoming too long, so split them on multiple lines. While at it, swap the order of the members to match the PixelFormatInfo class for consistency. Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi --- src/libcamera/v4l2_subdevice.cpp | 554 ++++++++++++++++++++++++++----- 1 file changed, 473 insertions(+), 81 deletions(-) diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp index 6c1df7812f07..a74b8362b6d1 100644 --- a/src/libcamera/v4l2_subdevice.cpp +++ b/src/libcamera/v4l2_subdevice.cpp @@ -41,13 +41,15 @@ namespace { /* * \struct MediaBusFormatInfo * \brief Information about media bus formats - * \param bitsPerPixel Bits per pixel * \param name Name of MBUS format + * \param code The media bus format code + * \param bitsPerPixel Bits per pixel * \param colourEncoding Type of colour encoding */ struct MediaBusFormatInfo { - unsigned int bitsPerPixel; const char *name; + uint32_t code; + unsigned int bitsPerPixel; PixelFormatInfo::ColourEncoding colourEncoding; }; @@ -56,87 +58,477 @@ struct MediaBusFormatInfo { * \brief A map that associates MediaBusFormatInfo struct to V4L2 media * bus codes */ -const std::map mediaBusFormatInfo = { +const std::map mediaBusFormatInfo{ /* This table is sorted to match the order in linux/media-bus-format.h */ - { MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE, { 16, "RGB444_2X8_PADHI_BE", PixelFormatInfo::ColourEncodingRGB } }, - { MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE, { 16, "RGB444_2X8_PADHI_LE", PixelFormatInfo::ColourEncodingRGB } }, - { MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, { 16, "RGB555_2X8_PADHI_BE", PixelFormatInfo::ColourEncodingRGB } }, - { MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, { 16, "RGB555_2X8_PADHI_LE", PixelFormatInfo::ColourEncodingRGB } }, - { MEDIA_BUS_FMT_RGB565_1X16, { 16, "RGB565_1X16", PixelFormatInfo::ColourEncodingRGB } }, - { MEDIA_BUS_FMT_BGR565_2X8_BE, { 16, "BGR565_2X8_BE", PixelFormatInfo::ColourEncodingRGB } }, - { MEDIA_BUS_FMT_BGR565_2X8_LE, { 16, "BGR565_2X8_LE", PixelFormatInfo::ColourEncodingRGB } }, - { MEDIA_BUS_FMT_RGB565_2X8_BE, { 16, "RGB565_2X8_BE", PixelFormatInfo::ColourEncodingRGB } }, - { MEDIA_BUS_FMT_RGB565_2X8_LE, { 16, "RGB565_2X8_LE", PixelFormatInfo::ColourEncodingRGB } }, - { MEDIA_BUS_FMT_RGB666_1X18, { 18, "RGB666_1X18", PixelFormatInfo::ColourEncodingRGB } }, - { MEDIA_BUS_FMT_BGR888_1X24, { 24, "BGR888_1X24", PixelFormatInfo::ColourEncodingRGB } }, - { MEDIA_BUS_FMT_RGB888_1X24, { 24, "RGB888_1X24", PixelFormatInfo::ColourEncodingRGB } }, - { MEDIA_BUS_FMT_RGB888_2X12_BE, { 24, "RGB888_2X12_BE", PixelFormatInfo::ColourEncodingRGB } }, - { MEDIA_BUS_FMT_RGB888_2X12_LE, { 24, "RGB888_2X12_LE", PixelFormatInfo::ColourEncodingRGB } }, - { MEDIA_BUS_FMT_ARGB8888_1X32, { 32, "ARGB8888_1X32", PixelFormatInfo::ColourEncodingRGB } }, - { MEDIA_BUS_FMT_Y8_1X8, { 8, "Y8_1X8", PixelFormatInfo::ColourEncodingYUV } }, - { MEDIA_BUS_FMT_UV8_1X8, { 8, "UV8_1X8", PixelFormatInfo::ColourEncodingYUV } }, - { MEDIA_BUS_FMT_UYVY8_1_5X8, { 12, "UYVY8_1_5X8", PixelFormatInfo::ColourEncodingYUV } }, - { MEDIA_BUS_FMT_VYUY8_1_5X8, { 12, "VYUY8_1_5X8", PixelFormatInfo::ColourEncodingYUV } }, - { MEDIA_BUS_FMT_YUYV8_1_5X8, { 12, "YUYV8_1_5X8", PixelFormatInfo::ColourEncodingYUV } }, - { MEDIA_BUS_FMT_YVYU8_1_5X8, { 12, "YVYU8_1_5X8", PixelFormatInfo::ColourEncodingYUV } }, - { MEDIA_BUS_FMT_UYVY8_2X8, { 16, "UYVY8_2X8", PixelFormatInfo::ColourEncodingYUV } }, - { MEDIA_BUS_FMT_VYUY8_2X8, { 16, "VYUY8_2X8", PixelFormatInfo::ColourEncodingYUV } }, - { MEDIA_BUS_FMT_YUYV8_2X8, { 16, "YUYV8_2X8", PixelFormatInfo::ColourEncodingYUV } }, - { MEDIA_BUS_FMT_YVYU8_2X8, { 16, "YVYU8_2X8", PixelFormatInfo::ColourEncodingYUV } }, - { MEDIA_BUS_FMT_Y10_1X10, { 10, "Y10_1X10", PixelFormatInfo::ColourEncodingYUV } }, - { MEDIA_BUS_FMT_UYVY10_2X10, { 20, "UYVY10_2X10", PixelFormatInfo::ColourEncodingYUV } }, - { MEDIA_BUS_FMT_VYUY10_2X10, { 20, "VYUY10_2X10", PixelFormatInfo::ColourEncodingYUV } }, - { MEDIA_BUS_FMT_YUYV10_2X10, { 20, "YUYV10_2X10", PixelFormatInfo::ColourEncodingYUV } }, - { MEDIA_BUS_FMT_YVYU10_2X10, { 20, "YVYU10_2X10", PixelFormatInfo::ColourEncodingYUV } }, - { MEDIA_BUS_FMT_Y12_1X12, { 12, "Y12_1X12", PixelFormatInfo::ColourEncodingYUV } }, - { MEDIA_BUS_FMT_Y16_1X16, { 16, "Y16_1X16", PixelFormatInfo::ColourEncodingYUV } }, - { MEDIA_BUS_FMT_UYVY8_1X16, { 16, "UYVY8_1X16", PixelFormatInfo::ColourEncodingYUV } }, - { MEDIA_BUS_FMT_VYUY8_1X16, { 16, "VYUY8_1X16", PixelFormatInfo::ColourEncodingYUV } }, - { MEDIA_BUS_FMT_YUYV8_1X16, { 16, "YUYV8_1X16", PixelFormatInfo::ColourEncodingYUV } }, - { MEDIA_BUS_FMT_YVYU8_1X16, { 16, "YVYU8_1X16", PixelFormatInfo::ColourEncodingYUV } }, - { MEDIA_BUS_FMT_YDYUYDYV8_1X16, { 16, "YDYUYDYV8_1X16", PixelFormatInfo::ColourEncodingYUV } }, - { MEDIA_BUS_FMT_UYVY10_1X20, { 20, "UYVY10_1X20", PixelFormatInfo::ColourEncodingYUV } }, - { MEDIA_BUS_FMT_VYUY10_1X20, { 20, "VYUY10_1X20", PixelFormatInfo::ColourEncodingYUV } }, - { MEDIA_BUS_FMT_YUYV10_1X20, { 20, "YUYV10_1X20", PixelFormatInfo::ColourEncodingYUV } }, - { MEDIA_BUS_FMT_YVYU10_1X20, { 20, "YVYU10_1X20", PixelFormatInfo::ColourEncodingYUV } }, - { MEDIA_BUS_FMT_YUV8_1X24, { 24, "YUV8_1X24", PixelFormatInfo::ColourEncodingYUV } }, - { MEDIA_BUS_FMT_YUV10_1X30, { 30, "YUV10_1X30", PixelFormatInfo::ColourEncodingYUV } }, - { MEDIA_BUS_FMT_AYUV8_1X32, { 32, "AYUV8_1X32", PixelFormatInfo::ColourEncodingYUV } }, - { MEDIA_BUS_FMT_UYVY12_2X12, { 24, "UYVY12_2X12", PixelFormatInfo::ColourEncodingYUV } }, - { MEDIA_BUS_FMT_VYUY12_2X12, { 24, "VYUY12_2X12", PixelFormatInfo::ColourEncodingYUV } }, - { MEDIA_BUS_FMT_YUYV12_2X12, { 24, "YUYV12_2X12", PixelFormatInfo::ColourEncodingYUV } }, - { MEDIA_BUS_FMT_YVYU12_2X12, { 24, "YVYU12_2X12", PixelFormatInfo::ColourEncodingYUV } }, - { MEDIA_BUS_FMT_UYVY12_1X24, { 24, "UYVY12_1X24", PixelFormatInfo::ColourEncodingYUV } }, - { MEDIA_BUS_FMT_VYUY12_1X24, { 24, "VYUY12_1X24", PixelFormatInfo::ColourEncodingYUV } }, - { MEDIA_BUS_FMT_YUYV12_1X24, { 24, "YUYV12_1X24", PixelFormatInfo::ColourEncodingYUV } }, - { MEDIA_BUS_FMT_YVYU12_1X24, { 24, "YVYU12_1X24", PixelFormatInfo::ColourEncodingYUV } }, - { MEDIA_BUS_FMT_SBGGR8_1X8, { 8, "SBGGR8_1X8", PixelFormatInfo::ColourEncodingRAW } }, - { MEDIA_BUS_FMT_SGBRG8_1X8, { 8, "SGBRG8_1X8", PixelFormatInfo::ColourEncodingRAW } }, - { MEDIA_BUS_FMT_SGRBG8_1X8, { 8, "SGRBG8_1X8", PixelFormatInfo::ColourEncodingRAW } }, - { MEDIA_BUS_FMT_SRGGB8_1X8, { 8, "SRGGB8_1X8", PixelFormatInfo::ColourEncodingRAW } }, - { MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8, { 8, "SBGGR10_ALAW8_1X8", PixelFormatInfo::ColourEncodingRAW } }, - { MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8, { 8, "SGBRG10_ALAW8_1X8", PixelFormatInfo::ColourEncodingRAW } }, - { MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8, { 8, "SGRBG10_ALAW8_1X8", PixelFormatInfo::ColourEncodingRAW } }, - { MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8, { 8, "SRGGB10_ALAW8_1X8", PixelFormatInfo::ColourEncodingRAW } }, - { MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8, { 8, "SBGGR10_DPCM8_1X8", PixelFormatInfo::ColourEncodingRAW } }, - { MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8, { 8, "SGBRG10_DPCM8_1X8", PixelFormatInfo::ColourEncodingRAW } }, - { MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, { 8, "SGRBG10_DPCM8_1X8", PixelFormatInfo::ColourEncodingRAW } }, - { MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8, { 8, "SRGGB10_DPCM8_1X8", PixelFormatInfo::ColourEncodingRAW } }, - { MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE, { 16, "SBGGR10_2X8_PADHI_BE", PixelFormatInfo::ColourEncodingRAW } }, - { MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, { 16, "SBGGR10_2X8_PADHI_LE", PixelFormatInfo::ColourEncodingRAW } }, - { MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE, { 16, "SBGGR10_2X8_PADLO_BE", PixelFormatInfo::ColourEncodingRAW } }, - { MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE, { 16, "SBGGR10_2X8_PADLO_LE", PixelFormatInfo::ColourEncodingRAW } }, - { MEDIA_BUS_FMT_SBGGR10_1X10, { 10, "SBGGR10_1X10", PixelFormatInfo::ColourEncodingRAW } }, - { MEDIA_BUS_FMT_SGBRG10_1X10, { 10, "SGBRG10_1X10", PixelFormatInfo::ColourEncodingRAW } }, - { MEDIA_BUS_FMT_SGRBG10_1X10, { 10, "SGRBG10_1X10", PixelFormatInfo::ColourEncodingRAW } }, - { MEDIA_BUS_FMT_SRGGB10_1X10, { 10, "SRGGB10_1X10", PixelFormatInfo::ColourEncodingRAW } }, - { MEDIA_BUS_FMT_SBGGR12_1X12, { 12, "SBGGR12_1X12", PixelFormatInfo::ColourEncodingRAW } }, - { MEDIA_BUS_FMT_SGBRG12_1X12, { 12, "SGBRG12_1X12", PixelFormatInfo::ColourEncodingRAW } }, - { MEDIA_BUS_FMT_SGRBG12_1X12, { 12, "SGRBG12_1X12", PixelFormatInfo::ColourEncodingRAW } }, - { MEDIA_BUS_FMT_SRGGB12_1X12, { 12, "SRGGB12_1X12", PixelFormatInfo::ColourEncodingRAW } }, + { MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE, { + .name = "RGB444_2X8_PADHI_BE", + .code = MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE, + .bitsPerPixel = 16, + .colourEncoding = PixelFormatInfo::ColourEncodingRGB, + } }, + { MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE, { + .name = "RGB444_2X8_PADHI_LE", + .code = MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE, + .bitsPerPixel = 16, + .colourEncoding = PixelFormatInfo::ColourEncodingRGB, + } }, + { MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, { + .name = "RGB555_2X8_PADHI_BE", + .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, + .bitsPerPixel = 16, + .colourEncoding = PixelFormatInfo::ColourEncodingRGB, + } }, + { MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, { + .name = "RGB555_2X8_PADHI_LE", + .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, + .bitsPerPixel = 16, + .colourEncoding = PixelFormatInfo::ColourEncodingRGB, + } }, + { MEDIA_BUS_FMT_RGB565_1X16, { + .name = "RGB565_1X16", + .code = MEDIA_BUS_FMT_RGB565_1X16, + .bitsPerPixel = 16, + .colourEncoding = PixelFormatInfo::ColourEncodingRGB, + } }, + { MEDIA_BUS_FMT_BGR565_2X8_BE, { + .name = "BGR565_2X8_BE", + .code = MEDIA_BUS_FMT_BGR565_2X8_BE, + .bitsPerPixel = 16, + .colourEncoding = PixelFormatInfo::ColourEncodingRGB, + } }, + { MEDIA_BUS_FMT_BGR565_2X8_LE, { + .name = "BGR565_2X8_LE", + .code = MEDIA_BUS_FMT_BGR565_2X8_LE, + .bitsPerPixel = 16, + .colourEncoding = PixelFormatInfo::ColourEncodingRGB, + } }, + { MEDIA_BUS_FMT_RGB565_2X8_BE, { + .name = "RGB565_2X8_BE", + .code = MEDIA_BUS_FMT_RGB565_2X8_BE, + .bitsPerPixel = 16, + .colourEncoding = PixelFormatInfo::ColourEncodingRGB, + } }, + { MEDIA_BUS_FMT_RGB565_2X8_LE, { + .name = "RGB565_2X8_LE", + .code = MEDIA_BUS_FMT_RGB565_2X8_LE, + .bitsPerPixel = 16, + .colourEncoding = PixelFormatInfo::ColourEncodingRGB, + } }, + { MEDIA_BUS_FMT_RGB666_1X18, { + .name = "RGB666_1X18", + .code = MEDIA_BUS_FMT_RGB666_1X18, + .bitsPerPixel = 18, + .colourEncoding = PixelFormatInfo::ColourEncodingRGB, + } }, + { MEDIA_BUS_FMT_BGR888_1X24, { + .name = "BGR888_1X24", + .code = MEDIA_BUS_FMT_BGR888_1X24, + .bitsPerPixel = 24, + .colourEncoding = PixelFormatInfo::ColourEncodingRGB, + } }, + { MEDIA_BUS_FMT_RGB888_1X24, { + .name = "RGB888_1X24", + .code = MEDIA_BUS_FMT_RGB888_1X24, + .bitsPerPixel = 24, + .colourEncoding = PixelFormatInfo::ColourEncodingRGB, + } }, + { MEDIA_BUS_FMT_RGB888_2X12_BE, { + .name = "RGB888_2X12_BE", + .code = MEDIA_BUS_FMT_RGB888_2X12_BE, + .bitsPerPixel = 24, + .colourEncoding = PixelFormatInfo::ColourEncodingRGB, + } }, + { MEDIA_BUS_FMT_RGB888_2X12_LE, { + .name = "RGB888_2X12_LE", + .code = MEDIA_BUS_FMT_RGB888_2X12_LE, + .bitsPerPixel = 24, + .colourEncoding = PixelFormatInfo::ColourEncodingRGB, + } }, + { MEDIA_BUS_FMT_ARGB8888_1X32, { + .name = "ARGB8888_1X32", + .code = MEDIA_BUS_FMT_ARGB8888_1X32, + .bitsPerPixel = 32, + .colourEncoding = PixelFormatInfo::ColourEncodingRGB, + } }, + { MEDIA_BUS_FMT_Y8_1X8, { + .name = "Y8_1X8", + .code = MEDIA_BUS_FMT_Y8_1X8, + .bitsPerPixel = 8, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, + { MEDIA_BUS_FMT_UV8_1X8, { + .name = "UV8_1X8", + .code = MEDIA_BUS_FMT_UV8_1X8, + .bitsPerPixel = 8, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, + { MEDIA_BUS_FMT_UYVY8_1_5X8, { + .name = "UYVY8_1_5X8", + .code = MEDIA_BUS_FMT_UYVY8_1_5X8, + .bitsPerPixel = 12, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, + { MEDIA_BUS_FMT_VYUY8_1_5X8, { + .name = "VYUY8_1_5X8", + .code = MEDIA_BUS_FMT_VYUY8_1_5X8, + .bitsPerPixel = 12, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, + { MEDIA_BUS_FMT_YUYV8_1_5X8, { + .name = "YUYV8_1_5X8", + .code = MEDIA_BUS_FMT_YUYV8_1_5X8, + .bitsPerPixel = 12, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, + { MEDIA_BUS_FMT_YVYU8_1_5X8, { + .name = "YVYU8_1_5X8", + .code = MEDIA_BUS_FMT_YVYU8_1_5X8, + .bitsPerPixel = 12, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, + { MEDIA_BUS_FMT_UYVY8_2X8, { + .name = "UYVY8_2X8", + .code = MEDIA_BUS_FMT_UYVY8_2X8, + .bitsPerPixel = 16, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, + { MEDIA_BUS_FMT_VYUY8_2X8, { + .name = "VYUY8_2X8", + .code = MEDIA_BUS_FMT_VYUY8_2X8, + .bitsPerPixel = 16, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, + { MEDIA_BUS_FMT_YUYV8_2X8, { + .name = "YUYV8_2X8", + .code = MEDIA_BUS_FMT_YUYV8_2X8, + .bitsPerPixel = 16, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, + { MEDIA_BUS_FMT_YVYU8_2X8, { + .name = "YVYU8_2X8", + .code = MEDIA_BUS_FMT_YVYU8_2X8, + .bitsPerPixel = 16, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, + { MEDIA_BUS_FMT_Y10_1X10, { + .name = "Y10_1X10", + .code = MEDIA_BUS_FMT_Y10_1X10, + .bitsPerPixel = 10, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, + { MEDIA_BUS_FMT_UYVY10_2X10, { + .name = "UYVY10_2X10", + .code = MEDIA_BUS_FMT_UYVY10_2X10, + .bitsPerPixel = 20, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, + { MEDIA_BUS_FMT_VYUY10_2X10, { + .name = "VYUY10_2X10", + .code = MEDIA_BUS_FMT_VYUY10_2X10, + .bitsPerPixel = 20, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, + { MEDIA_BUS_FMT_YUYV10_2X10, { + .name = "YUYV10_2X10", + .code = MEDIA_BUS_FMT_YUYV10_2X10, + .bitsPerPixel = 20, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, + { MEDIA_BUS_FMT_YVYU10_2X10, { + .name = "YVYU10_2X10", + .code = MEDIA_BUS_FMT_YVYU10_2X10, + .bitsPerPixel = 20, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, + { MEDIA_BUS_FMT_Y12_1X12, { + .name = "Y12_1X12", + .code = MEDIA_BUS_FMT_Y12_1X12, + .bitsPerPixel = 12, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, + { MEDIA_BUS_FMT_Y16_1X16, { + .name = "Y16_1X16", + .code = MEDIA_BUS_FMT_Y16_1X16, + .bitsPerPixel = 16, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, + { MEDIA_BUS_FMT_UYVY8_1X16, { + .name = "UYVY8_1X16", + .code = MEDIA_BUS_FMT_UYVY8_1X16, + .bitsPerPixel = 16, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, + { MEDIA_BUS_FMT_VYUY8_1X16, { + .name = "VYUY8_1X16", + .code = MEDIA_BUS_FMT_VYUY8_1X16, + .bitsPerPixel = 16, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, + { MEDIA_BUS_FMT_YUYV8_1X16, { + .name = "YUYV8_1X16", + .code = MEDIA_BUS_FMT_YUYV8_1X16, + .bitsPerPixel = 16, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, + { MEDIA_BUS_FMT_YVYU8_1X16, { + .name = "YVYU8_1X16", + .code = MEDIA_BUS_FMT_YVYU8_1X16, + .bitsPerPixel = 16, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, + { MEDIA_BUS_FMT_YDYUYDYV8_1X16, { + .name = "YDYUYDYV8_1X16", + .code = MEDIA_BUS_FMT_YDYUYDYV8_1X16, + .bitsPerPixel = 16, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, + { MEDIA_BUS_FMT_UYVY10_1X20, { + .name = "UYVY10_1X20", + .code = MEDIA_BUS_FMT_UYVY10_1X20, + .bitsPerPixel = 20, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, + { MEDIA_BUS_FMT_VYUY10_1X20, { + .name = "VYUY10_1X20", + .code = MEDIA_BUS_FMT_VYUY10_1X20, + .bitsPerPixel = 20, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, + { MEDIA_BUS_FMT_YUYV10_1X20, { + .name = "YUYV10_1X20", + .code = MEDIA_BUS_FMT_YUYV10_1X20, + .bitsPerPixel = 20, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, + { MEDIA_BUS_FMT_YVYU10_1X20, { + .name = "YVYU10_1X20", + .code = MEDIA_BUS_FMT_YVYU10_1X20, + .bitsPerPixel = 20, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, + { MEDIA_BUS_FMT_YUV8_1X24, { + .name = "YUV8_1X24", + .code = MEDIA_BUS_FMT_YUV8_1X24, + .bitsPerPixel = 24, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, + { MEDIA_BUS_FMT_YUV10_1X30, { + .name = "YUV10_1X30", + .code = MEDIA_BUS_FMT_YUV10_1X30, + .bitsPerPixel = 30, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, + { MEDIA_BUS_FMT_AYUV8_1X32, { + .name = "AYUV8_1X32", + .code = MEDIA_BUS_FMT_AYUV8_1X32, + .bitsPerPixel = 32, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, + { MEDIA_BUS_FMT_UYVY12_2X12, { + .name = "UYVY12_2X12", + .code = MEDIA_BUS_FMT_UYVY12_2X12, + .bitsPerPixel = 24, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, + { MEDIA_BUS_FMT_VYUY12_2X12, { + .name = "VYUY12_2X12", + .code = MEDIA_BUS_FMT_VYUY12_2X12, + .bitsPerPixel = 24, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, + { MEDIA_BUS_FMT_YUYV12_2X12, { + .name = "YUYV12_2X12", + .code = MEDIA_BUS_FMT_YUYV12_2X12, + .bitsPerPixel = 24, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, + { MEDIA_BUS_FMT_YVYU12_2X12, { + .name = "YVYU12_2X12", + .code = MEDIA_BUS_FMT_YVYU12_2X12, + .bitsPerPixel = 24, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, + { MEDIA_BUS_FMT_UYVY12_1X24, { + .name = "UYVY12_1X24", + .code = MEDIA_BUS_FMT_UYVY12_1X24, + .bitsPerPixel = 24, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, + { MEDIA_BUS_FMT_VYUY12_1X24, { + .name = "VYUY12_1X24", + .code = MEDIA_BUS_FMT_VYUY12_1X24, + .bitsPerPixel = 24, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, + { MEDIA_BUS_FMT_YUYV12_1X24, { + .name = "YUYV12_1X24", + .code = MEDIA_BUS_FMT_YUYV12_1X24, + .bitsPerPixel = 24, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, + { MEDIA_BUS_FMT_YVYU12_1X24, { + .name = "YVYU12_1X24", + .code = MEDIA_BUS_FMT_YVYU12_1X24, + .bitsPerPixel = 24, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, + { MEDIA_BUS_FMT_SBGGR8_1X8, { + .name = "SBGGR8_1X8", + .code = MEDIA_BUS_FMT_SBGGR8_1X8, + .bitsPerPixel = 8, + .colourEncoding = PixelFormatInfo::ColourEncodingRAW, + } }, + { MEDIA_BUS_FMT_SGBRG8_1X8, { + .name = "SGBRG8_1X8", + .code = MEDIA_BUS_FMT_SGBRG8_1X8, + .bitsPerPixel = 8, + .colourEncoding = PixelFormatInfo::ColourEncodingRAW, + } }, + { MEDIA_BUS_FMT_SGRBG8_1X8, { + .name = "SGRBG8_1X8", + .code = MEDIA_BUS_FMT_SGRBG8_1X8, + .bitsPerPixel = 8, + .colourEncoding = PixelFormatInfo::ColourEncodingRAW, + } }, + { MEDIA_BUS_FMT_SRGGB8_1X8, { + .name = "SRGGB8_1X8", + .code = MEDIA_BUS_FMT_SRGGB8_1X8, + .bitsPerPixel = 8, + .colourEncoding = PixelFormatInfo::ColourEncodingRAW, + } }, + { MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8, { + .name = "SBGGR10_ALAW8_1X8", + .code = MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8, + .bitsPerPixel = 8, + .colourEncoding = PixelFormatInfo::ColourEncodingRAW, + } }, + { MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8, { + .name = "SGBRG10_ALAW8_1X8", + .code = MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8, + .bitsPerPixel = 8, + .colourEncoding = PixelFormatInfo::ColourEncodingRAW, + } }, + { MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8, { + .name = "SGRBG10_ALAW8_1X8", + .code = MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8, + .bitsPerPixel = 8, + .colourEncoding = PixelFormatInfo::ColourEncodingRAW, + } }, + { MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8, { + .name = "SRGGB10_ALAW8_1X8", + .code = MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8, + .bitsPerPixel = 8, + .colourEncoding = PixelFormatInfo::ColourEncodingRAW, + } }, + { MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8, { + .name = "SBGGR10_DPCM8_1X8", + .code = MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8, + .bitsPerPixel = 8, + .colourEncoding = PixelFormatInfo::ColourEncodingRAW, + } }, + { MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8, { + .name = "SGBRG10_DPCM8_1X8", + .code = MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8, + .bitsPerPixel = 8, + .colourEncoding = PixelFormatInfo::ColourEncodingRAW, + } }, + { MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, { + .name = "SGRBG10_DPCM8_1X8", + .code = MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, + .bitsPerPixel = 8, + .colourEncoding = PixelFormatInfo::ColourEncodingRAW, + } }, + { MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8, { + .name = "SRGGB10_DPCM8_1X8", + .code = MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8, + .bitsPerPixel = 8, + .colourEncoding = PixelFormatInfo::ColourEncodingRAW, + } }, + { MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE, { + .name = "SBGGR10_2X8_PADHI_BE", + .code = MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE, + .bitsPerPixel = 16, + .colourEncoding = PixelFormatInfo::ColourEncodingRAW, + } }, + { MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, { + .name = "SBGGR10_2X8_PADHI_LE", + .code = MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, + .bitsPerPixel = 16, + .colourEncoding = PixelFormatInfo::ColourEncodingRAW, + } }, + { MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE, { + .name = "SBGGR10_2X8_PADLO_BE", + .code = MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE, + .bitsPerPixel = 16, + .colourEncoding = PixelFormatInfo::ColourEncodingRAW, + } }, + { MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE, { + .name = "SBGGR10_2X8_PADLO_LE", + .code = MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE, + .bitsPerPixel = 16, + .colourEncoding = PixelFormatInfo::ColourEncodingRAW, + } }, + { MEDIA_BUS_FMT_SBGGR10_1X10, { + .name = "SBGGR10_1X10", + .code = MEDIA_BUS_FMT_SBGGR10_1X10, + .bitsPerPixel = 10, + .colourEncoding = PixelFormatInfo::ColourEncodingRAW, + } }, + { MEDIA_BUS_FMT_SGBRG10_1X10, { + .name = "SGBRG10_1X10", + .code = MEDIA_BUS_FMT_SGBRG10_1X10, + .bitsPerPixel = 10, + .colourEncoding = PixelFormatInfo::ColourEncodingRAW, + } }, + { MEDIA_BUS_FMT_SGRBG10_1X10, { + .name = "SGRBG10_1X10", + .code = MEDIA_BUS_FMT_SGRBG10_1X10, + .bitsPerPixel = 10, + .colourEncoding = PixelFormatInfo::ColourEncodingRAW, + } }, + { MEDIA_BUS_FMT_SRGGB10_1X10, { + .name = "SRGGB10_1X10", + .code = MEDIA_BUS_FMT_SRGGB10_1X10, + .bitsPerPixel = 10, + .colourEncoding = PixelFormatInfo::ColourEncodingRAW, + } }, + { MEDIA_BUS_FMT_SBGGR12_1X12, { + .name = "SBGGR12_1X12", + .code = MEDIA_BUS_FMT_SBGGR12_1X12, + .bitsPerPixel = 12, + .colourEncoding = PixelFormatInfo::ColourEncodingRAW, + } }, + { MEDIA_BUS_FMT_SGBRG12_1X12, { + .name = "SGBRG12_1X12", + .code = MEDIA_BUS_FMT_SGBRG12_1X12, + .bitsPerPixel = 12, + .colourEncoding = PixelFormatInfo::ColourEncodingRAW, + } }, + { MEDIA_BUS_FMT_SGRBG12_1X12, { + .name = "SGRBG12_1X12", + .code = MEDIA_BUS_FMT_SGRBG12_1X12, + .bitsPerPixel = 12, + .colourEncoding = PixelFormatInfo::ColourEncodingRAW, + } }, + { MEDIA_BUS_FMT_SRGGB12_1X12, { + .name = "SRGGB12_1X12", + .code = MEDIA_BUS_FMT_SRGGB12_1X12, + .bitsPerPixel = 12, + .colourEncoding = PixelFormatInfo::ColourEncodingRAW, + } }, /* \todo Clarify colour encoding for HSV formats */ - { MEDIA_BUS_FMT_AHSV8888_1X32, { 32, "AHSV8888_1X32", PixelFormatInfo::ColourEncodingRGB } }, - { MEDIA_BUS_FMT_JPEG_1X8, { 8, "JPEG_1X8", PixelFormatInfo::ColourEncodingYUV } }, + { MEDIA_BUS_FMT_AHSV8888_1X32, { + .name = "AHSV8888_1X32", + .code = MEDIA_BUS_FMT_AHSV8888_1X32, + .bitsPerPixel = 32, + .colourEncoding = PixelFormatInfo::ColourEncodingRGB, + } }, + { MEDIA_BUS_FMT_JPEG_1X8, { + .name = "JPEG_1X8", + .code = MEDIA_BUS_FMT_JPEG_1X8, + .bitsPerPixel = 8, + .colourEncoding = PixelFormatInfo::ColourEncodingYUV, + } }, }; } /* namespace */ From patchwork Fri Mar 1 21:20:52 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 19594 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id E3779C3260 for ; Fri, 1 Mar 2024 21:21:27 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 981E06291F; Fri, 1 Mar 2024 22:21:27 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="iNXiVSvs"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id DCCA86285F for ; Fri, 1 Mar 2024 22:21:23 +0100 (CET) Received: from pendragon.ideasonboard.com (89-27-53-110.bb.dnainternet.fi [89.27.53.110]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 635DA22D9; Fri, 1 Mar 2024 22:21:09 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1709328069; bh=Pryi86G56Po2LfBqhi8dYt6D0q7V9kmJ8DOU5lu3nW0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=iNXiVSvsAshYhUqftUGrtuvWYxF9SOzzqC8iwvWCPBWbd0j7SZbRbbkDlbPYWtSTB v5qwG1QI/oCBERiFM2FbSRNvDDeivpsY2Cx3EvK9M9s7K7oICKmvba+cAaaQnI5ZOH Tf37KFkgUZbf6iZ2BoA08q3+kqXeNrLeGmFa1izE= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH/RFC 03/32] libcamera: v4l2_subdevice: Expose media bus format info as internal API Date: Fri, 1 Mar 2024 23:20:52 +0200 Message-ID: <20240301212121.9072-4-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> References: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sakari Ailus Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The V4L2SubdeviceFormatInfo structure, internal to the v4l2_subdevice.cpp compilation unit, contains information about media bus formats that will be useful in other parts of libcamera. To prepare for this, expose the structure in the v4l2_subdevice.h header and turn it into a class with a similar design as PixelFormatInfo. Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi --- Changes since v1: - Improve MediaBusFormatInfo::code documentation --- include/libcamera/internal/v4l2_subdevice.h | 13 +++ src/libcamera/v4l2_subdevice.cpp | 94 ++++++++++++++------- 2 files changed, 76 insertions(+), 31 deletions(-) diff --git a/include/libcamera/internal/v4l2_subdevice.h b/include/libcamera/internal/v4l2_subdevice.h index 17db311bcfb3..a4df9ddfd322 100644 --- a/include/libcamera/internal/v4l2_subdevice.h +++ b/include/libcamera/internal/v4l2_subdevice.h @@ -29,6 +29,19 @@ namespace libcamera { class MediaDevice; +class MediaBusFormatInfo +{ +public: + bool isValid() const { return code != 0; } + + static const MediaBusFormatInfo &info(uint32_t code); + + const char *name; + uint32_t code; + unsigned int bitsPerPixel; + PixelFormatInfo::ColourEncoding colourEncoding; +}; + struct V4L2SubdeviceCapability final : v4l2_subdev_capability { bool isReadOnly() const { diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp index a74b8362b6d1..6a491088161b 100644 --- a/src/libcamera/v4l2_subdevice.cpp +++ b/src/libcamera/v4l2_subdevice.cpp @@ -36,28 +36,40 @@ namespace libcamera { LOG_DECLARE_CATEGORY(V4L2) +/** + * \class MediaBusFormatInfo + * \brief Information about media bus formats + * + * The MediaBusFormatInfo class groups together information describing a media + * bus format. It facilitates handling of media bus formats by providing data + * commonly used in pipeline handlers. + * + * \var MediaBusFormatInfo::name + * \brief The format name as a human-readable string, used as the text + * representation of the format + * + * \var MediaBusFormatInfo::code + * \brief The media bus format code described by this instance (MEDIA_BUS_FMT_*) + * + * \var MediaBusFormatInfo::bitsPerPixel + * \brief The average number of bits per pixel + * + * The number of bits per pixel averages the total number of bits for all + * colour components over the whole image, excluding any padding bits or + * padding pixels. + * + * For formats that transmit multiple or fractional pixels per sample, the + * value will differ from the bus width. + * + * Formats that don't have a fixed number of bits per pixel, such as compressed + * formats, report 0 in this field. + * + * \var MediaBusFormatInfo::colourEncoding + * \brief The colour encoding type + */ + namespace { -/* - * \struct MediaBusFormatInfo - * \brief Information about media bus formats - * \param name Name of MBUS format - * \param code The media bus format code - * \param bitsPerPixel Bits per pixel - * \param colourEncoding Type of colour encoding - */ -struct MediaBusFormatInfo { - const char *name; - uint32_t code; - unsigned int bitsPerPixel; - PixelFormatInfo::ColourEncoding colourEncoding; -}; - -/* - * \var mediaBusFormatInfo - * \brief A map that associates MediaBusFormatInfo struct to V4L2 media - * bus codes - */ const std::map mediaBusFormatInfo{ /* This table is sorted to match the order in linux/media-bus-format.h */ { MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE, { @@ -533,6 +545,33 @@ const std::map mediaBusFormatInfo{ } /* namespace */ +/** + * \fn bool MediaBusFormatInfo::isValid() const + * \brief Check if the media bus format info is valid + * \return True if the media bus format info is valid, false otherwise + */ + +/** + * \brief Retrieve information about a media bus format + * \param[in] code The media bus format code + * \return The MediaBusFormatInfo describing the \a code if known, or an invalid + * MediaBusFormatInfo otherwise + */ +const MediaBusFormatInfo &MediaBusFormatInfo::info(uint32_t code) +{ + static const MediaBusFormatInfo invalid{}; + + const auto it = mediaBusFormatInfo.find(code); + if (it == mediaBusFormatInfo.end()) { + LOG(V4L2, Warning) + << "Unsupported media bus format " + << utils::hex(code, 4); + return invalid; + } + + return it->second; +} + /** * \struct V4L2SubdeviceCapability * \brief struct v4l2_subdev_capability object wrapper and helpers @@ -629,14 +668,7 @@ const std::string V4L2SubdeviceFormat::toString() const */ uint8_t V4L2SubdeviceFormat::bitsPerPixel() const { - const auto it = mediaBusFormatInfo.find(mbus_code); - if (it == mediaBusFormatInfo.end()) { - LOG(V4L2, Error) << "No information available for format '" - << *this << "'"; - return 0; - } - - return it->second.bitsPerPixel; + return MediaBusFormatInfo::info(mbus_code).bitsPerPixel; } /** @@ -903,9 +935,9 @@ std::optional V4L2Subdevice::toColorSpace(const v4l2_mbus_framefmt & return std::nullopt; PixelFormatInfo::ColourEncoding colourEncoding; - auto iter = mediaBusFormatInfo.find(format.code); - if (iter != mediaBusFormatInfo.end()) { - colourEncoding = iter->second.colourEncoding; + const MediaBusFormatInfo &info = MediaBusFormatInfo::info(format.code); + if (info.isValid()) { + colourEncoding = info.colourEncoding; } else { LOG(V4L2, Warning) << "Unknown subdev format " From patchwork Fri Mar 1 21:20:53 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 19595 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 73D37BD160 for ; Fri, 1 Mar 2024 21:21:29 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 332B56287B; Fri, 1 Mar 2024 22:21:29 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="qqJwEXxY"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 660B46286C for ; Fri, 1 Mar 2024 22:21:25 +0100 (CET) Received: from pendragon.ideasonboard.com (89-27-53-110.bb.dnainternet.fi [89.27.53.110]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id BE983293D; Fri, 1 Mar 2024 22:21:10 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1709328071; bh=ZxjstwvH4YnRoUWb/a5PWz8cYBwxnHCwYjb2yxl0boU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=qqJwEXxYJZfcd+DV8J88uTzizxyhMos3RHXMykiKYAfcYDiNV7lDu5eCB4HJGs5RN Im1wC1xaXN9XjA55Ydneyab1vKWRWENcdj4lBsO0ngiJrnRcCr5+maGEB4kGS7ZUhk lgrt9J/bNz/VgTgmXZPteGVqqFUfyOxzllzF1RuA= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH/RFC 04/32] libcamera: v4l2_subdevice: Extend MediaBusFormatInfo with metadata formats Date: Fri, 1 Mar 2024 23:20:53 +0200 Message-ID: <20240301212121.9072-5-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> References: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sakari Ailus Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Not all media bus formats describe image formats. Extend the MediaBusFormatInfo class with a type member to indicate if the format corresponds to image data or metadata, and add the (only) metatdata format supported by the kernel to the known mediaBusFormatInfo. The kernel doesn't (yet) have any metadata format specific to sensor embedded data. This is being addressed in the V4L2 API. In preparation for embedded data support, already introduce the EmbeddedData type here. Corresponding formats will be added when available. Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi --- include/libcamera/internal/v4l2_subdevice.h | 7 ++ src/libcamera/v4l2_subdevice.cpp | 106 +++++++++++++++++++- 2 files changed, 112 insertions(+), 1 deletion(-) diff --git a/include/libcamera/internal/v4l2_subdevice.h b/include/libcamera/internal/v4l2_subdevice.h index a4df9ddfd322..c9aa90e00ec8 100644 --- a/include/libcamera/internal/v4l2_subdevice.h +++ b/include/libcamera/internal/v4l2_subdevice.h @@ -32,12 +32,19 @@ class MediaDevice; class MediaBusFormatInfo { public: + enum class Type { + Image, + Metadata, + EmbeddedData, + }; + bool isValid() const { return code != 0; } static const MediaBusFormatInfo &info(uint32_t code); const char *name; uint32_t code; + Type type; unsigned int bitsPerPixel; PixelFormatInfo::ColourEncoding colourEncoding; }; diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp index 6a491088161b..4dce8a81a97d 100644 --- a/src/libcamera/v4l2_subdevice.cpp +++ b/src/libcamera/v4l2_subdevice.cpp @@ -51,6 +51,9 @@ LOG_DECLARE_CATEGORY(V4L2) * \var MediaBusFormatInfo::code * \brief The media bus format code described by this instance (MEDIA_BUS_FMT_*) * + * \var MediaBusFormatInfo::type + * \brief The media bus format type + * * \var MediaBusFormatInfo::bitsPerPixel * \brief The average number of bits per pixel * @@ -62,10 +65,26 @@ LOG_DECLARE_CATEGORY(V4L2) * value will differ from the bus width. * * Formats that don't have a fixed number of bits per pixel, such as compressed - * formats, report 0 in this field. + * formats, or device-specific embedded data formats, report 0 in this field. * * \var MediaBusFormatInfo::colourEncoding * \brief The colour encoding type + * + * This field is valid for Type::Image formats only. + */ + +/** + * \enum MediaBusFormatInfo::Type + * \brief The format type + * + * \var MediaBusFormatInfo::Type::Image + * \brief The format describes image data + * + * \var MediaBusFormatInfo::Type::Metadata + * \brief The format describes generic metadata + * + * \var MediaBusFormatInfo::Type::EmbeddedData + * \brief The format describes sensor embedded data */ namespace { @@ -75,456 +94,532 @@ const std::map mediaBusFormatInfo{ { MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE, { .name = "RGB444_2X8_PADHI_BE", .code = MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 16, .colourEncoding = PixelFormatInfo::ColourEncodingRGB, } }, { MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE, { .name = "RGB444_2X8_PADHI_LE", .code = MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 16, .colourEncoding = PixelFormatInfo::ColourEncodingRGB, } }, { MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, { .name = "RGB555_2X8_PADHI_BE", .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 16, .colourEncoding = PixelFormatInfo::ColourEncodingRGB, } }, { MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, { .name = "RGB555_2X8_PADHI_LE", .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 16, .colourEncoding = PixelFormatInfo::ColourEncodingRGB, } }, { MEDIA_BUS_FMT_RGB565_1X16, { .name = "RGB565_1X16", .code = MEDIA_BUS_FMT_RGB565_1X16, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 16, .colourEncoding = PixelFormatInfo::ColourEncodingRGB, } }, { MEDIA_BUS_FMT_BGR565_2X8_BE, { .name = "BGR565_2X8_BE", .code = MEDIA_BUS_FMT_BGR565_2X8_BE, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 16, .colourEncoding = PixelFormatInfo::ColourEncodingRGB, } }, { MEDIA_BUS_FMT_BGR565_2X8_LE, { .name = "BGR565_2X8_LE", .code = MEDIA_BUS_FMT_BGR565_2X8_LE, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 16, .colourEncoding = PixelFormatInfo::ColourEncodingRGB, } }, { MEDIA_BUS_FMT_RGB565_2X8_BE, { .name = "RGB565_2X8_BE", .code = MEDIA_BUS_FMT_RGB565_2X8_BE, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 16, .colourEncoding = PixelFormatInfo::ColourEncodingRGB, } }, { MEDIA_BUS_FMT_RGB565_2X8_LE, { .name = "RGB565_2X8_LE", .code = MEDIA_BUS_FMT_RGB565_2X8_LE, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 16, .colourEncoding = PixelFormatInfo::ColourEncodingRGB, } }, { MEDIA_BUS_FMT_RGB666_1X18, { .name = "RGB666_1X18", .code = MEDIA_BUS_FMT_RGB666_1X18, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 18, .colourEncoding = PixelFormatInfo::ColourEncodingRGB, } }, { MEDIA_BUS_FMT_BGR888_1X24, { .name = "BGR888_1X24", .code = MEDIA_BUS_FMT_BGR888_1X24, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 24, .colourEncoding = PixelFormatInfo::ColourEncodingRGB, } }, { MEDIA_BUS_FMT_RGB888_1X24, { .name = "RGB888_1X24", .code = MEDIA_BUS_FMT_RGB888_1X24, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 24, .colourEncoding = PixelFormatInfo::ColourEncodingRGB, } }, { MEDIA_BUS_FMT_RGB888_2X12_BE, { .name = "RGB888_2X12_BE", .code = MEDIA_BUS_FMT_RGB888_2X12_BE, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 24, .colourEncoding = PixelFormatInfo::ColourEncodingRGB, } }, { MEDIA_BUS_FMT_RGB888_2X12_LE, { .name = "RGB888_2X12_LE", .code = MEDIA_BUS_FMT_RGB888_2X12_LE, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 24, .colourEncoding = PixelFormatInfo::ColourEncodingRGB, } }, { MEDIA_BUS_FMT_ARGB8888_1X32, { .name = "ARGB8888_1X32", .code = MEDIA_BUS_FMT_ARGB8888_1X32, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 32, .colourEncoding = PixelFormatInfo::ColourEncodingRGB, } }, { MEDIA_BUS_FMT_Y8_1X8, { .name = "Y8_1X8", .code = MEDIA_BUS_FMT_Y8_1X8, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 8, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, { MEDIA_BUS_FMT_UV8_1X8, { .name = "UV8_1X8", .code = MEDIA_BUS_FMT_UV8_1X8, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 8, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, { MEDIA_BUS_FMT_UYVY8_1_5X8, { .name = "UYVY8_1_5X8", .code = MEDIA_BUS_FMT_UYVY8_1_5X8, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 12, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, { MEDIA_BUS_FMT_VYUY8_1_5X8, { .name = "VYUY8_1_5X8", .code = MEDIA_BUS_FMT_VYUY8_1_5X8, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 12, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, { MEDIA_BUS_FMT_YUYV8_1_5X8, { .name = "YUYV8_1_5X8", .code = MEDIA_BUS_FMT_YUYV8_1_5X8, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 12, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, { MEDIA_BUS_FMT_YVYU8_1_5X8, { .name = "YVYU8_1_5X8", .code = MEDIA_BUS_FMT_YVYU8_1_5X8, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 12, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, { MEDIA_BUS_FMT_UYVY8_2X8, { .name = "UYVY8_2X8", .code = MEDIA_BUS_FMT_UYVY8_2X8, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 16, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, { MEDIA_BUS_FMT_VYUY8_2X8, { .name = "VYUY8_2X8", .code = MEDIA_BUS_FMT_VYUY8_2X8, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 16, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, { MEDIA_BUS_FMT_YUYV8_2X8, { .name = "YUYV8_2X8", .code = MEDIA_BUS_FMT_YUYV8_2X8, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 16, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, { MEDIA_BUS_FMT_YVYU8_2X8, { .name = "YVYU8_2X8", .code = MEDIA_BUS_FMT_YVYU8_2X8, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 16, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, { MEDIA_BUS_FMT_Y10_1X10, { .name = "Y10_1X10", .code = MEDIA_BUS_FMT_Y10_1X10, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 10, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, { MEDIA_BUS_FMT_UYVY10_2X10, { .name = "UYVY10_2X10", .code = MEDIA_BUS_FMT_UYVY10_2X10, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 20, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, { MEDIA_BUS_FMT_VYUY10_2X10, { .name = "VYUY10_2X10", .code = MEDIA_BUS_FMT_VYUY10_2X10, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 20, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, { MEDIA_BUS_FMT_YUYV10_2X10, { .name = "YUYV10_2X10", .code = MEDIA_BUS_FMT_YUYV10_2X10, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 20, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, { MEDIA_BUS_FMT_YVYU10_2X10, { .name = "YVYU10_2X10", .code = MEDIA_BUS_FMT_YVYU10_2X10, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 20, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, { MEDIA_BUS_FMT_Y12_1X12, { .name = "Y12_1X12", .code = MEDIA_BUS_FMT_Y12_1X12, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 12, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, { MEDIA_BUS_FMT_Y16_1X16, { .name = "Y16_1X16", .code = MEDIA_BUS_FMT_Y16_1X16, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 16, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, { MEDIA_BUS_FMT_UYVY8_1X16, { .name = "UYVY8_1X16", .code = MEDIA_BUS_FMT_UYVY8_1X16, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 16, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, { MEDIA_BUS_FMT_VYUY8_1X16, { .name = "VYUY8_1X16", .code = MEDIA_BUS_FMT_VYUY8_1X16, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 16, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, { MEDIA_BUS_FMT_YUYV8_1X16, { .name = "YUYV8_1X16", .code = MEDIA_BUS_FMT_YUYV8_1X16, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 16, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, { MEDIA_BUS_FMT_YVYU8_1X16, { .name = "YVYU8_1X16", .code = MEDIA_BUS_FMT_YVYU8_1X16, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 16, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, { MEDIA_BUS_FMT_YDYUYDYV8_1X16, { .name = "YDYUYDYV8_1X16", .code = MEDIA_BUS_FMT_YDYUYDYV8_1X16, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 16, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, { MEDIA_BUS_FMT_UYVY10_1X20, { .name = "UYVY10_1X20", .code = MEDIA_BUS_FMT_UYVY10_1X20, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 20, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, { MEDIA_BUS_FMT_VYUY10_1X20, { .name = "VYUY10_1X20", .code = MEDIA_BUS_FMT_VYUY10_1X20, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 20, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, { MEDIA_BUS_FMT_YUYV10_1X20, { .name = "YUYV10_1X20", .code = MEDIA_BUS_FMT_YUYV10_1X20, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 20, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, { MEDIA_BUS_FMT_YVYU10_1X20, { .name = "YVYU10_1X20", .code = MEDIA_BUS_FMT_YVYU10_1X20, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 20, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, { MEDIA_BUS_FMT_YUV8_1X24, { .name = "YUV8_1X24", .code = MEDIA_BUS_FMT_YUV8_1X24, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 24, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, { MEDIA_BUS_FMT_YUV10_1X30, { .name = "YUV10_1X30", .code = MEDIA_BUS_FMT_YUV10_1X30, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 30, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, { MEDIA_BUS_FMT_AYUV8_1X32, { .name = "AYUV8_1X32", .code = MEDIA_BUS_FMT_AYUV8_1X32, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 32, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, { MEDIA_BUS_FMT_UYVY12_2X12, { .name = "UYVY12_2X12", .code = MEDIA_BUS_FMT_UYVY12_2X12, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 24, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, { MEDIA_BUS_FMT_VYUY12_2X12, { .name = "VYUY12_2X12", .code = MEDIA_BUS_FMT_VYUY12_2X12, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 24, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, { MEDIA_BUS_FMT_YUYV12_2X12, { .name = "YUYV12_2X12", .code = MEDIA_BUS_FMT_YUYV12_2X12, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 24, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, { MEDIA_BUS_FMT_YVYU12_2X12, { .name = "YVYU12_2X12", .code = MEDIA_BUS_FMT_YVYU12_2X12, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 24, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, { MEDIA_BUS_FMT_UYVY12_1X24, { .name = "UYVY12_1X24", .code = MEDIA_BUS_FMT_UYVY12_1X24, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 24, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, { MEDIA_BUS_FMT_VYUY12_1X24, { .name = "VYUY12_1X24", .code = MEDIA_BUS_FMT_VYUY12_1X24, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 24, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, { MEDIA_BUS_FMT_YUYV12_1X24, { .name = "YUYV12_1X24", .code = MEDIA_BUS_FMT_YUYV12_1X24, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 24, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, { MEDIA_BUS_FMT_YVYU12_1X24, { .name = "YVYU12_1X24", .code = MEDIA_BUS_FMT_YVYU12_1X24, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 24, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, { MEDIA_BUS_FMT_SBGGR8_1X8, { .name = "SBGGR8_1X8", .code = MEDIA_BUS_FMT_SBGGR8_1X8, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 8, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, } }, { MEDIA_BUS_FMT_SGBRG8_1X8, { .name = "SGBRG8_1X8", .code = MEDIA_BUS_FMT_SGBRG8_1X8, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 8, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, } }, { MEDIA_BUS_FMT_SGRBG8_1X8, { .name = "SGRBG8_1X8", .code = MEDIA_BUS_FMT_SGRBG8_1X8, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 8, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, } }, { MEDIA_BUS_FMT_SRGGB8_1X8, { .name = "SRGGB8_1X8", .code = MEDIA_BUS_FMT_SRGGB8_1X8, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 8, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, } }, { MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8, { .name = "SBGGR10_ALAW8_1X8", .code = MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 8, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, } }, { MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8, { .name = "SGBRG10_ALAW8_1X8", .code = MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 8, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, } }, { MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8, { .name = "SGRBG10_ALAW8_1X8", .code = MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 8, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, } }, { MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8, { .name = "SRGGB10_ALAW8_1X8", .code = MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 8, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, } }, { MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8, { .name = "SBGGR10_DPCM8_1X8", .code = MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 8, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, } }, { MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8, { .name = "SGBRG10_DPCM8_1X8", .code = MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 8, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, } }, { MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, { .name = "SGRBG10_DPCM8_1X8", .code = MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 8, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, } }, { MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8, { .name = "SRGGB10_DPCM8_1X8", .code = MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 8, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, } }, { MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE, { .name = "SBGGR10_2X8_PADHI_BE", .code = MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 16, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, } }, { MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, { .name = "SBGGR10_2X8_PADHI_LE", .code = MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 16, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, } }, { MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE, { .name = "SBGGR10_2X8_PADLO_BE", .code = MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 16, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, } }, { MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE, { .name = "SBGGR10_2X8_PADLO_LE", .code = MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 16, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, } }, { MEDIA_BUS_FMT_SBGGR10_1X10, { .name = "SBGGR10_1X10", .code = MEDIA_BUS_FMT_SBGGR10_1X10, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 10, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, } }, { MEDIA_BUS_FMT_SGBRG10_1X10, { .name = "SGBRG10_1X10", .code = MEDIA_BUS_FMT_SGBRG10_1X10, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 10, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, } }, { MEDIA_BUS_FMT_SGRBG10_1X10, { .name = "SGRBG10_1X10", .code = MEDIA_BUS_FMT_SGRBG10_1X10, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 10, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, } }, { MEDIA_BUS_FMT_SRGGB10_1X10, { .name = "SRGGB10_1X10", .code = MEDIA_BUS_FMT_SRGGB10_1X10, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 10, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, } }, { MEDIA_BUS_FMT_SBGGR12_1X12, { .name = "SBGGR12_1X12", .code = MEDIA_BUS_FMT_SBGGR12_1X12, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 12, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, } }, { MEDIA_BUS_FMT_SGBRG12_1X12, { .name = "SGBRG12_1X12", .code = MEDIA_BUS_FMT_SGBRG12_1X12, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 12, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, } }, { MEDIA_BUS_FMT_SGRBG12_1X12, { .name = "SGRBG12_1X12", .code = MEDIA_BUS_FMT_SGRBG12_1X12, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 12, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, } }, { MEDIA_BUS_FMT_SRGGB12_1X12, { .name = "SRGGB12_1X12", .code = MEDIA_BUS_FMT_SRGGB12_1X12, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 12, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, } }, @@ -532,15 +627,24 @@ const std::map mediaBusFormatInfo{ { MEDIA_BUS_FMT_AHSV8888_1X32, { .name = "AHSV8888_1X32", .code = MEDIA_BUS_FMT_AHSV8888_1X32, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 32, .colourEncoding = PixelFormatInfo::ColourEncodingRGB, } }, { MEDIA_BUS_FMT_JPEG_1X8, { .name = "JPEG_1X8", .code = MEDIA_BUS_FMT_JPEG_1X8, + .type = MediaBusFormatInfo::Type::Image, .bitsPerPixel = 8, .colourEncoding = PixelFormatInfo::ColourEncodingYUV, } }, + { MEDIA_BUS_FMT_METADATA_FIXED, { + .name = "METADATA_FIXED", + .code = MEDIA_BUS_FMT_METADATA_FIXED, + .type = MediaBusFormatInfo::Type::Metadata, + .bitsPerPixel = 0, + .colourEncoding = PixelFormatInfo::ColourEncodingRAW, + } }, }; } /* namespace */ From patchwork Fri Mar 1 21:20:54 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 19596 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 4E13EC32C3 for ; Fri, 1 Mar 2024 21:21:30 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id E3404628AC; Fri, 1 Mar 2024 22:21:29 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="HDEkulrM"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 5053662871 for ; Fri, 1 Mar 2024 22:21:27 +0100 (CET) Received: from pendragon.ideasonboard.com (89-27-53-110.bb.dnainternet.fi [89.27.53.110]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 46CA1A9A; Fri, 1 Mar 2024 22:21:12 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1709328073; bh=iSk4SkBmskR3lKQlyR7vJ379H0m7K2JrlgNEBsrqmIU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=HDEkulrMVhnrb0sfpVPvg1IamBZ1LIVVvZ3+DGM8HI3ne/5av/FCKTr00ACY7J2ds 3GLEMCGKedDtU1ke4x3YqvkUgQ3h3M++03GJpgeI8Fn7zkeNXIlpvSBqmwAP6Xi+Sk O+GA24+rFRKrzK/WPoYIRCwn7Z9VRZKtMwEAH1iM= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH/RFC 05/32] libcamera: v4l2_subdevice: Drop V4L2SubdeviceFormat::bitsPerPixel() Date: Fri, 1 Mar 2024 23:20:54 +0200 Message-ID: <20240301212121.9072-6-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> References: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sakari Ailus Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The V4L2SubdeviceFormat::bitsPerPixel() function is just a wrapper around a MediaBusFormatInfo lookup. It made sense when the MediaBusFormatInfo class was not exposed outside of the compilation unit, but is now redundant. Drop it and use MediaBusFormatInfo in the only caller. Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi --- include/libcamera/internal/v4l2_subdevice.h | 1 - src/libcamera/camera_sensor.cpp | 3 ++- src/libcamera/v4l2_subdevice.cpp | 10 ---------- 3 files changed, 2 insertions(+), 12 deletions(-) diff --git a/include/libcamera/internal/v4l2_subdevice.h b/include/libcamera/internal/v4l2_subdevice.h index c9aa90e00ec8..a87981341d75 100644 --- a/include/libcamera/internal/v4l2_subdevice.h +++ b/include/libcamera/internal/v4l2_subdevice.h @@ -66,7 +66,6 @@ struct V4L2SubdeviceFormat { std::optional colorSpace; const std::string toString() const; - uint8_t bitsPerPixel() const; }; std::ostream &operator<<(std::ostream &out, const V4L2SubdeviceFormat &f); diff --git a/src/libcamera/camera_sensor.cpp b/src/libcamera/camera_sensor.cpp index 0ef78d9c8b0a..55c9c74b10c2 100644 --- a/src/libcamera/camera_sensor.cpp +++ b/src/libcamera/camera_sensor.cpp @@ -1060,7 +1060,8 @@ int CameraSensor::sensorInfo(IPACameraSensorInfo *info) const ret = subdev_->getFormat(pad_, &format); if (ret) return ret; - info->bitsPerPixel = format.bitsPerPixel(); + + info->bitsPerPixel = MediaBusFormatInfo::info(format.mbus_code).bitsPerPixel; info->outputSize = format.size; std::optional cfa = properties_.get(properties::draft::ColorFilterArrangement); diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp index 4dce8a81a97d..e896977121d2 100644 --- a/src/libcamera/v4l2_subdevice.cpp +++ b/src/libcamera/v4l2_subdevice.cpp @@ -765,16 +765,6 @@ const std::string V4L2SubdeviceFormat::toString() const return ss.str(); } -/** - * \brief Retrieve the number of bits per pixel for the V4L2 subdevice format - * \return The number of bits per pixel for the format, or 0 if the format is - * not supported - */ -uint8_t V4L2SubdeviceFormat::bitsPerPixel() const -{ - return MediaBusFormatInfo::info(mbus_code).bitsPerPixel; -} - /** * \brief Insert a text representation of a V4L2SubdeviceFormat into an output * stream From patchwork Fri Mar 1 21:20:55 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 19597 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 3B634C3260 for ; Fri, 1 Mar 2024 21:21:31 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id A687862872; Fri, 1 Mar 2024 22:21:30 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="axNfcypq"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id E653D62871 for ; Fri, 1 Mar 2024 22:21:28 +0100 (CET) Received: from pendragon.ideasonboard.com (89-27-53-110.bb.dnainternet.fi [89.27.53.110]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 420742D6B; Fri, 1 Mar 2024 22:21:14 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1709328074; bh=pRl8v5ykoABSG91wzLr7CkpJAEIISEK18+aMOEaAGbo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=axNfcypq7ABrWt8Fe2VQh46RePGf1bFA6/cMLconE8z7Zy+DsFqBu/9HBHixFagBc 98RouYdzHTAapP1JbdCDyqFX95I6ElLeBoPMUPNKTnArqZt3WfCStqRTk5+5il5AR7 LxoM8oTtMaCt3FEK+8T/Jf7G/SjbSOcvvdPI8Z7I= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH/RFC 06/32] libcamera: v4l2_subdevice: Rename V4L2SubdeviceFormat::mbus_code to code Date: Fri, 1 Mar 2024 23:20:55 +0200 Message-ID: <20240301212121.9072-7-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> References: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sakari Ailus Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The V4L2SubdeviceFormat::mbus_code member doesn't follow the libcamera coding style as it should use camelCase. Fix it by renaming it to just 'code', to shorten lines in addition to fixing the coding style. Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi --- include/libcamera/internal/v4l2_subdevice.h | 2 +- src/libcamera/camera_sensor.cpp | 8 ++++---- src/libcamera/pipeline/imx8-isi/imx8-isi.cpp | 10 +++++----- src/libcamera/pipeline/ipu3/cio2.cpp | 8 ++++---- src/libcamera/pipeline/ipu3/imgu.cpp | 4 ++-- src/libcamera/pipeline/rkisp1/rkisp1.cpp | 2 +- src/libcamera/pipeline/rkisp1/rkisp1_path.cpp | 2 +- .../pipeline/rpi/common/pipeline_base.cpp | 16 ++++++++-------- src/libcamera/pipeline/rpi/vc4/vc4.cpp | 2 +- src/libcamera/pipeline/simple/simple.cpp | 10 +++++----- src/libcamera/pipeline/vimc/vimc.cpp | 4 ++-- src/libcamera/v4l2_subdevice.cpp | 12 ++++++------ test/camera-sensor.cpp | 2 +- test/v4l2_videodevice/v4l2_videodevice_test.cpp | 2 +- 14 files changed, 42 insertions(+), 42 deletions(-) diff --git a/include/libcamera/internal/v4l2_subdevice.h b/include/libcamera/internal/v4l2_subdevice.h index a87981341d75..1115cfa55594 100644 --- a/include/libcamera/internal/v4l2_subdevice.h +++ b/include/libcamera/internal/v4l2_subdevice.h @@ -61,7 +61,7 @@ struct V4L2SubdeviceCapability final : v4l2_subdev_capability { }; struct V4L2SubdeviceFormat { - uint32_t mbus_code; + uint32_t code; Size size; std::optional colorSpace; diff --git a/src/libcamera/camera_sensor.cpp b/src/libcamera/camera_sensor.cpp index 55c9c74b10c2..af5d97f35de1 100644 --- a/src/libcamera/camera_sensor.cpp +++ b/src/libcamera/camera_sensor.cpp @@ -770,7 +770,7 @@ V4L2SubdeviceFormat CameraSensor::getFormat(const std::vector &mbu } V4L2SubdeviceFormat format{ - .mbus_code = bestCode, + .code = bestCode, .size = *bestSize, .colorSpace = ColorSpace::Raw, }; @@ -892,12 +892,12 @@ int CameraSensor::applyConfiguration(const SensorConfiguration &config, size.height != config.outputSize.height) continue; - subdevFormat.mbus_code = code; + subdevFormat.code = code; subdevFormat.size = size; break; } } - if (!subdevFormat.mbus_code) { + if (!subdevFormat.code) { LOG(CameraSensor, Error) << "Invalid output size in sensor configuration"; return -EINVAL; } @@ -1061,7 +1061,7 @@ int CameraSensor::sensorInfo(IPACameraSensorInfo *info) const if (ret) return ret; - info->bitsPerPixel = MediaBusFormatInfo::info(format.mbus_code).bitsPerPixel; + info->bitsPerPixel = MediaBusFormatInfo::info(format.code).bitsPerPixel; info->outputSize = format.size; std::optional cfa = properties_.get(properties::draft::ColorFilterArrangement); diff --git a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp index 9bdfff0b155e..a3782aea2ba9 100644 --- a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp +++ b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp @@ -554,7 +554,7 @@ CameraConfiguration::Status ISICameraConfiguration::validate() PixelFormat pixelFormat = config_[0].pixelFormat; V4L2SubdeviceFormat sensorFormat{}; - sensorFormat.mbus_code = data_->getMediaBusFormat(&pixelFormat); + sensorFormat.code = data_->getMediaBusFormat(&pixelFormat); sensorFormat.size = maxSize; LOG(ISI, Debug) << "Computed sensor configuration: " << sensorFormat; @@ -569,7 +569,7 @@ CameraConfiguration::Status ISICameraConfiguration::validate() * the smallest larger format without considering the aspect ratio * as the ISI can freely scale. */ - auto sizes = sensor->sizes(sensorFormat.mbus_code); + auto sizes = sensor->sizes(sensorFormat.code); Size bestSize; for (const Size &s : sizes) { @@ -595,7 +595,7 @@ CameraConfiguration::Status ISICameraConfiguration::validate() return Invalid; } - sensorFormat_.mbus_code = sensorFormat.mbus_code; + sensorFormat_.code = sensorFormat.code; sensorFormat_.size = bestSize; LOG(ISI, Debug) << "Selected sensor format: " << sensorFormat_; @@ -632,7 +632,7 @@ StreamConfiguration PipelineHandlerISI::generateYUVConfiguration(Camera *camera, /* Adjust the requested size to the sensor's capabilities. */ V4L2SubdeviceFormat sensorFmt; - sensorFmt.mbus_code = mbusCode; + sensorFmt.code = mbusCode; sensorFmt.size = size; int ret = data->sensor_->tryFormat(&sensorFmt); @@ -891,7 +891,7 @@ int PipelineHandlerISI::configure(Camera *camera, CameraConfiguration *c) unsigned int isiCode = ISICameraConfiguration::formatsMap_.at(config.pixelFormat); V4L2SubdeviceFormat isiFormat{}; - isiFormat.mbus_code = isiCode; + isiFormat.code = isiCode; isiFormat.size = config.size; ret = pipe->isi->setFormat(1, &isiFormat); diff --git a/src/libcamera/pipeline/ipu3/cio2.cpp b/src/libcamera/pipeline/ipu3/cio2.cpp index 7400cb0b644c..43c816baf6ef 100644 --- a/src/libcamera/pipeline/ipu3/cio2.cpp +++ b/src/libcamera/pipeline/ipu3/cio2.cpp @@ -202,7 +202,7 @@ int CIO2Device::configure(const Size &size, const Transform &transform, if (ret) return ret; - const auto &itInfo = mbusCodesToPixelFormat.find(sensorFormat.mbus_code); + const auto &itInfo = mbusCodesToPixelFormat.find(sensorFormat.code); if (itInfo == mbusCodesToPixelFormat.end()) return -EINVAL; @@ -230,13 +230,13 @@ StreamConfiguration CIO2Device::generateConfiguration(Size size) const /* Query the sensor static information for closest match. */ std::vector mbusCodes = utils::map_keys(mbusCodesToPixelFormat); V4L2SubdeviceFormat sensorFormat = getSensorFormat(mbusCodes, size); - if (!sensorFormat.mbus_code) { + if (!sensorFormat.code) { LOG(IPU3, Error) << "Sensor does not support mbus code"; return {}; } cfg.size = sensorFormat.size; - cfg.pixelFormat = mbusCodesToPixelFormat.at(sensorFormat.mbus_code); + cfg.pixelFormat = mbusCodesToPixelFormat.at(sensorFormat.code); cfg.bufferCount = kBufferCount; return cfg; @@ -326,7 +326,7 @@ V4L2SubdeviceFormat CIO2Device::getSensorFormat(const std::vector } V4L2SubdeviceFormat format{}; - format.mbus_code = bestCode; + format.code = bestCode; format.size = bestSize; return format; diff --git a/src/libcamera/pipeline/ipu3/imgu.cpp b/src/libcamera/pipeline/ipu3/imgu.cpp index 531879f18183..2202438a75e0 100644 --- a/src/libcamera/pipeline/ipu3/imgu.cpp +++ b/src/libcamera/pipeline/ipu3/imgu.cpp @@ -504,7 +504,7 @@ int ImgUDevice::configure(const PipeConfig &pipeConfig, V4L2DeviceFormat *inputF LOG(IPU3, Debug) << "ImgU BDS rectangle = " << bds; V4L2SubdeviceFormat gdcFormat = {}; - gdcFormat.mbus_code = MEDIA_BUS_FMT_FIXED; + gdcFormat.code = MEDIA_BUS_FMT_FIXED; gdcFormat.size = pipeConfig.gdc; ret = imgu_->setFormat(PAD_INPUT, &gdcFormat); @@ -543,7 +543,7 @@ int ImgUDevice::configureVideoDevice(V4L2VideoDevice *dev, unsigned int pad, V4L2DeviceFormat *outputFormat) { V4L2SubdeviceFormat imguFormat = {}; - imguFormat.mbus_code = MEDIA_BUS_FMT_FIXED; + imguFormat.code = MEDIA_BUS_FMT_FIXED; imguFormat.size = cfg.size; int ret = imgu_->setFormat(pad, &imguFormat); diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp index 586b46d64630..abb21968413a 100644 --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp @@ -761,7 +761,7 @@ int PipelineHandlerRkISP1::configure(Camera *camera, CameraConfiguration *c) /* YUYV8_2X8 is required on the ISP source path pad for YUV output. */ if (!isRaw_) - format.mbus_code = MEDIA_BUS_FMT_YUYV8_2X8; + format.code = MEDIA_BUS_FMT_YUYV8_2X8; LOG(RkISP1, Debug) << "Configuring ISP output pad with " << format diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp index b62b645cae24..9195aad2cff2 100644 --- a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp +++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp @@ -365,7 +365,7 @@ int RkISP1Path::configure(const StreamConfiguration &config, * The configuration has been validated, the pixel format is guaranteed * to be supported and thus found in formatToMediaBus. */ - ispFormat.mbus_code = formatToMediaBus.at(config.pixelFormat); + ispFormat.code = formatToMediaBus.at(config.pixelFormat); ret = resizer_->setFormat(1, &ispFormat); if (ret < 0) diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp index e0bedcd8c664..9449c3dc458c 100644 --- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp @@ -37,10 +37,10 @@ namespace { constexpr unsigned int defaultRawBitDepth = 12; -PixelFormat mbusCodeToPixelFormat(unsigned int mbus_code, +PixelFormat mbusCodeToPixelFormat(unsigned int code, BayerFormat::Packing packingReq) { - BayerFormat bayer = BayerFormat::fromMbusCode(mbus_code); + BayerFormat bayer = BayerFormat::fromMbusCode(code); ASSERT(bayer.isValid()); @@ -221,7 +221,7 @@ CameraConfiguration::Status RPiCameraConfiguration::validate() * without modifications. */ if (sensorConfig) { - BayerFormat bayer = BayerFormat::fromMbusCode(sensorFormat_.mbus_code); + BayerFormat bayer = BayerFormat::fromMbusCode(sensorFormat_.code); if (bayer.bitDepth != sensorConfig->bitDepth || sensorFormat_.size != sensorConfig->outputSize) { @@ -236,7 +236,7 @@ CameraConfiguration::Status RPiCameraConfiguration::validate() StreamConfiguration *rawStream = raw.cfg; /* Adjust the RAW stream to match the computed sensor format. */ - BayerFormat sensorBayer = BayerFormat::fromMbusCode(sensorFormat_.mbus_code); + BayerFormat sensorBayer = BayerFormat::fromMbusCode(sensorFormat_.code); /* * Some sensors change their Bayer order when they are h-flipped @@ -377,8 +377,8 @@ V4L2DeviceFormat PipelineHandlerBase::toV4L2DeviceFormat(const V4L2VideoDevice * const V4L2SubdeviceFormat &format, BayerFormat::Packing packingReq) { - unsigned int mbus_code = format.mbus_code; - const PixelFormat pix = mbusCodeToPixelFormat(mbus_code, packingReq); + unsigned int code = format.code; + const PixelFormat pix = mbusCodeToPixelFormat(code, packingReq); V4L2DeviceFormat deviceFormat; deviceFormat.fourcc = dev->toV4L2PixelFormat(pix); @@ -409,7 +409,7 @@ PipelineHandlerBase::generateConfiguration(Camera *camera, SpanfindBestFormat(size, defaultRawBitDepth); - pixelFormat = mbusCodeToPixelFormat(sensorFormat.mbus_code, + pixelFormat = mbusCodeToPixelFormat(sensorFormat.code, BayerFormat::Packing::CSI2); ASSERT(pixelFormat.isValid()); colorSpace = ColorSpace::Raw; @@ -990,7 +990,7 @@ V4L2SubdeviceFormat CameraData::findBestFormat(const Size &req, unsigned int bit if (score <= bestScore) { bestScore = score; - bestFormat.mbus_code = mbusCode; + bestFormat.code = mbusCode; bestFormat.size = size; } diff --git a/src/libcamera/pipeline/rpi/vc4/vc4.cpp b/src/libcamera/pipeline/rpi/vc4/vc4.cpp index 6b6ecd3ded7d..ad7dddde59f1 100644 --- a/src/libcamera/pipeline/rpi/vc4/vc4.cpp +++ b/src/libcamera/pipeline/rpi/vc4/vc4.cpp @@ -426,7 +426,7 @@ CameraConfiguration::Status Vc4CameraData::platformValidate(RPi::RPiCameraConfig BayerFormat rawBayer = BayerFormat::fromPixelFormat(rawStream->pixelFormat); /* Apply the sensor bitdepth. */ - rawBayer.bitDepth = BayerFormat::fromMbusCode(rpiConfig->sensorFormat_.mbus_code).bitDepth; + rawBayer.bitDepth = BayerFormat::fromMbusCode(rpiConfig->sensorFormat_.code).bitDepth; /* Default to CSI2 packing if the user request is unsupported. */ if (rawBayer.packing != BayerFormat::Packing::CSI2 && diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp index e37b0d1c393f..3d0424969a89 100644 --- a/src/libcamera/pipeline/simple/simple.cpp +++ b/src/libcamera/pipeline/simple/simple.cpp @@ -563,13 +563,13 @@ void SimpleCameraData::tryPipeline(unsigned int code, const Size &size) * corresponding possible V4L2 pixel formats on the video node. */ V4L2SubdeviceFormat format{}; - format.mbus_code = code; + format.code = code; format.size = size; int ret = setupFormats(&format, V4L2Subdevice::TryFormat); if (ret < 0) { /* Pipeline configuration failed, skip this configuration. */ - format.mbus_code = code; + format.code = code; format.size = size; LOG(SimplePipeline, Debug) << "Sensor format " << format @@ -577,7 +577,7 @@ void SimpleCameraData::tryPipeline(unsigned int code, const Size &size) return; } - V4L2VideoDevice::Formats videoFormats = video_->formats(format.mbus_code); + V4L2VideoDevice::Formats videoFormats = video_->formats(format.code); LOG(SimplePipeline, Debug) << "Adding configuration for " << format.size @@ -707,7 +707,7 @@ int SimpleCameraData::setupFormats(V4L2SubdeviceFormat *format, if (ret < 0) return ret; - if (format->mbus_code != sourceFormat.mbus_code || + if (format->code != sourceFormat.code || format->size != sourceFormat.size) { LOG(SimplePipeline, Debug) << "Source '" << source->entity()->name() @@ -1121,7 +1121,7 @@ int SimplePipelineHandler::configure(Camera *camera, CameraConfiguration *c) const SimpleCameraData::Configuration *pipeConfig = config->pipeConfig(); V4L2SubdeviceFormat format{}; - format.mbus_code = pipeConfig->code; + format.code = pipeConfig->code; format.size = pipeConfig->sensorSize; ret = data->setupFormats(&format, V4L2Subdevice::ActiveFormat, diff --git a/src/libcamera/pipeline/vimc/vimc.cpp b/src/libcamera/pipeline/vimc/vimc.cpp index 5536941ac0d5..5e66ee1d26c1 100644 --- a/src/libcamera/pipeline/vimc/vimc.cpp +++ b/src/libcamera/pipeline/vimc/vimc.cpp @@ -244,7 +244,7 @@ int PipelineHandlerVimc::configure(Camera *camera, CameraConfiguration *config) /* The scaler hardcodes a x3 scale-up ratio. */ V4L2SubdeviceFormat subformat = {}; - subformat.mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8; + subformat.code = MEDIA_BUS_FMT_SGRBG8_1X8; subformat.size = { cfg.size.width / 3, cfg.size.height / 3 }; ret = data->sensor_->setFormat(&subformat); @@ -255,7 +255,7 @@ int PipelineHandlerVimc::configure(Camera *camera, CameraConfiguration *config) if (ret) return ret; - subformat.mbus_code = pixelformats.find(cfg.pixelFormat)->second; + subformat.code = pixelformats.find(cfg.pixelFormat)->second; ret = data->debayer_->setFormat(1, &subformat); if (ret) return ret; diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp index e896977121d2..dadc4d1dab92 100644 --- a/src/libcamera/v4l2_subdevice.cpp +++ b/src/libcamera/v4l2_subdevice.cpp @@ -729,7 +729,7 @@ const MediaBusFormatInfo &MediaBusFormatInfo::info(uint32_t code) */ /** - * \var V4L2SubdeviceFormat::mbus_code + * \var V4L2SubdeviceFormat::code * \brief The image format bus code */ @@ -776,10 +776,10 @@ std::ostream &operator<<(std::ostream &out, const V4L2SubdeviceFormat &f) { out << f.size << "-"; - const auto it = mediaBusFormatInfo.find(f.mbus_code); + const auto it = mediaBusFormatInfo.find(f.code); if (it == mediaBusFormatInfo.end()) - out << utils::hex(f.mbus_code, 4); + out << utils::hex(f.code, 4); else out << it->second.name; @@ -1069,7 +1069,7 @@ int V4L2Subdevice::getFormat(unsigned int pad, V4L2SubdeviceFormat *format, format->size.width = subdevFmt.format.width; format->size.height = subdevFmt.format.height; - format->mbus_code = subdevFmt.format.code; + format->code = subdevFmt.format.code; format->colorSpace = toColorSpace(subdevFmt.format); return 0; @@ -1095,7 +1095,7 @@ int V4L2Subdevice::setFormat(unsigned int pad, V4L2SubdeviceFormat *format, subdevFmt.pad = pad; subdevFmt.format.width = format->size.width; subdevFmt.format.height = format->size.height; - subdevFmt.format.code = format->mbus_code; + subdevFmt.format.code = format->code; subdevFmt.format.field = V4L2_FIELD_NONE; if (format->colorSpace) { fromColorSpace(format->colorSpace, subdevFmt.format); @@ -1115,7 +1115,7 @@ int V4L2Subdevice::setFormat(unsigned int pad, V4L2SubdeviceFormat *format, format->size.width = subdevFmt.format.width; format->size.height = subdevFmt.format.height; - format->mbus_code = subdevFmt.format.code; + format->code = subdevFmt.format.code; format->colorSpace = toColorSpace(subdevFmt.format); return 0; diff --git a/test/camera-sensor.cpp b/test/camera-sensor.cpp index 2a17cc79ea76..9503d7753fb9 100644 --- a/test/camera-sensor.cpp +++ b/test/camera-sensor.cpp @@ -100,7 +100,7 @@ protected: MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_BGR888_1X24 }, Size(1024, 768)); - if (format.mbus_code != MEDIA_BUS_FMT_SBGGR10_1X10 || + if (format.code != MEDIA_BUS_FMT_SBGGR10_1X10 || format.size != Size(4096, 2160)) { cerr << "Failed to get a suitable format, expected 4096x2160-0x" << utils::hex(MEDIA_BUS_FMT_SBGGR10_1X10) diff --git a/test/v4l2_videodevice/v4l2_videodevice_test.cpp b/test/v4l2_videodevice/v4l2_videodevice_test.cpp index 125aafd65041..1113cf5bf8cf 100644 --- a/test/v4l2_videodevice/v4l2_videodevice_test.cpp +++ b/test/v4l2_videodevice/v4l2_videodevice_test.cpp @@ -75,7 +75,7 @@ int V4L2VideoDeviceTest::init() format.fourcc = V4L2PixelFormat(V4L2_PIX_FMT_SBGGR8); V4L2SubdeviceFormat subformat = {}; - subformat.mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8; + subformat.code = MEDIA_BUS_FMT_SBGGR8_1X8; subformat.size = format.size; if (sensor_->setFormat(&subformat)) From patchwork Fri Mar 1 21:20:56 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 19598 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 27537BD160 for ; Fri, 1 Mar 2024 21:21:34 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id DF0A6628AC; Fri, 1 Mar 2024 22:21:33 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="h7wptxKt"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 654BC62865 for ; Fri, 1 Mar 2024 22:21:30 +0100 (CET) Received: from pendragon.ideasonboard.com (89-27-53-110.bb.dnainternet.fi [89.27.53.110]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id CF79B31B4; Fri, 1 Mar 2024 22:21:15 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1709328076; bh=HM/4WdMmD/TGOOGIQBOn4pLc0aCvh35TAZ0OSfqPzzo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=h7wptxKtJ/rirWxjeXG5S3+tARIAw//e444i/nAfnQL5WZHfjBH+PyD1ypy6BDw99 YpMr7r/HMv1LKcIz51jdPI2NVjjsh+tTvhlTRSE5Aoyc7wZJIePwzx78lKlChIWICe wzlT4SMAYUR7lcKjNGaP9Wr8If1XUsc/eywIXOaY= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH/RFC 07/32] libcamera: v4l2_subdevice: Add stream support to get/set functions Date: Fri, 1 Mar 2024 23:20:56 +0200 Message-ID: <20240301212121.9072-8-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> References: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sakari Ailus Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Extend the V4L2Subdevice API with stream support for the functions that get and set formats and selection rectangles. Add a Stream structure to identify a subdev pad and stream, and use it to extend the V4L2Subdevice functions that get and set formats and selection rectangles with stream support. To preserve the existing pad-based API, implement overloaded functions that wrap the new stream-based API. This allows callers that are not stream-aware to use a simpler pad-based API, instead of having to explicitly set the stream number to 0 in all API calls. Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi --- Changes since v1: - Drop incorrect comment change - Use operator<<(Stream) - Add comparison operators --- include/libcamera/internal/v4l2_subdevice.h | 58 ++++- src/libcamera/v4l2_subdevice.cpp | 252 +++++++++++++++----- 2 files changed, 240 insertions(+), 70 deletions(-) diff --git a/include/libcamera/internal/v4l2_subdevice.h b/include/libcamera/internal/v4l2_subdevice.h index 1115cfa55594..6cd36730371a 100644 --- a/include/libcamera/internal/v4l2_subdevice.h +++ b/include/libcamera/internal/v4l2_subdevice.h @@ -80,6 +80,21 @@ public: ActiveFormat = V4L2_SUBDEV_FORMAT_ACTIVE, }; + struct Stream { + Stream() + : pad(0), stream(0) + { + } + + Stream(unsigned int p, unsigned int s) + : pad(p), stream(s) + { + } + + unsigned int pad; + unsigned int stream; + }; + class Routing : public std::vector { public: @@ -93,17 +108,39 @@ public: const MediaEntity *entity() const { return entity_; } - int getSelection(unsigned int pad, unsigned int target, + int getSelection(const Stream &stream, unsigned int target, Rectangle *rect); - int setSelection(unsigned int pad, unsigned int target, + int getSelection(unsigned int pad, unsigned int target, Rectangle *rect) + { + return getSelection({ pad, 0 }, target, rect); + } + int setSelection(const Stream &stream, unsigned int target, Rectangle *rect); + int setSelection(unsigned int pad, unsigned int target, Rectangle *rect) + { + return setSelection({ pad, 0 }, target, rect); + } - Formats formats(unsigned int pad); + Formats formats(const Stream &stream); + Formats formats(unsigned int pad) + { + return formats({ pad, 0 }); + } + int getFormat(const Stream &stream, V4L2SubdeviceFormat *format, + Whence whence = ActiveFormat); int getFormat(unsigned int pad, V4L2SubdeviceFormat *format, + Whence whence = ActiveFormat) + { + return getFormat({ pad, 0 }, format, whence); + } + int setFormat(const Stream &stream, V4L2SubdeviceFormat *format, Whence whence = ActiveFormat); int setFormat(unsigned int pad, V4L2SubdeviceFormat *format, - Whence whence = ActiveFormat); + Whence whence = ActiveFormat) + { + return setFormat({ pad, 0 }, format, whence); + } int getRouting(Routing *routing, Whence whence = ActiveFormat); int setRouting(Routing *routing, Whence whence = ActiveFormat); @@ -123,8 +160,8 @@ private: std::optional toColorSpace(const v4l2_mbus_framefmt &format) const; - std::vector enumPadCodes(unsigned int pad); - std::vector enumPadSizes(unsigned int pad, + std::vector enumPadCodes(const Stream &stream); + std::vector enumPadSizes(const Stream &stream, unsigned int code); const MediaEntity *entity_; @@ -133,4 +170,13 @@ private: struct V4L2SubdeviceCapability caps_; }; +bool operator==(const V4L2Subdevice::Stream &lhs, const V4L2Subdevice::Stream &rhs); +static inline bool operator!=(const V4L2Subdevice::Stream &lhs, + const V4L2Subdevice::Stream &rhs) +{ + return !(lhs == rhs); +} + +std::ostream &operator<<(std::ostream &out, const V4L2Subdevice::Stream &stream); + } /* namespace libcamera */ diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp index dadc4d1dab92..5a3c6a02f57c 100644 --- a/src/libcamera/v4l2_subdevice.cpp +++ b/src/libcamera/v4l2_subdevice.cpp @@ -814,6 +814,62 @@ std::ostream &operator<<(std::ostream &out, const V4L2SubdeviceFormat &f) * \brief The format operation applies to TRY formats */ +/** + * \class V4L2Subdevice::Stream + * \brief V4L2 subdevice stream + * + * This class identifies a subdev stream, by bundling the pad number with the + * stream number. It is used in all stream-aware functions of the V4L2Subdevice + * class to identify the stream the functions operate on. + * + * \var V4L2Subdevice::Stream::pad + * \brief The 0-indexed pad number + * + * \var V4L2Subdevice::Stream::stream + * \brief The stream number + */ + +/** + * \fn V4L2Subdevice::Stream::Stream() + * \brief Construct a Stream with pad and stream set to 0 + */ + +/** + * \fn V4L2Subdevice::Stream::Stream(unsigned int pad, unsigned int stream) + * \brief Construct a Stream with a given \a pad and \a stream number + * \param[in] pad The indexed pad number + * \param[in] stream The stream number + */ + +/** + * \brief Compare streams for equality + * \return True if the two streams are equal, false otherwise + */ +bool operator==(const V4L2Subdevice::Stream &lhs, const V4L2Subdevice::Stream &rhs) +{ + return lhs.pad == rhs.pad && lhs.stream == rhs.stream; +} + +/** + * \fn bool operator!=(const V4L2Subdevice::Stream &lhs, const V4L2Subdevice::Stream &rhs) + * \brief Compare streams for inequality + * \return True if the two streams are not equal, false otherwise + */ + +/** + * \brief Insert a text representation of a V4L2Subdevice::Stream into an + * output stream + * \param[in] out The output stream + * \param[in] stream The V4L2Subdevice::Stream + * \return The output stream \a out + */ +std::ostream &operator<<(std::ostream &out, const V4L2Subdevice::Stream &stream) +{ + out << stream.pad << "/" << stream.stream; + + return out; +} + /** * \class V4L2Subdevice::Routing * \brief V4L2 subdevice routing table @@ -905,7 +961,7 @@ int V4L2Subdevice::open() /** * \brief Get selection rectangle \a rect for \a target - * \param[in] pad The 0-indexed pad number the rectangle is retrieved from + * \param[in] stream The stream the rectangle is retrieved from * \param[in] target The selection target defined by the V4L2_SEL_TGT_* flags * \param[out] rect The retrieved selection rectangle * @@ -913,13 +969,14 @@ int V4L2Subdevice::open() * * \return 0 on success or a negative error code otherwise */ -int V4L2Subdevice::getSelection(unsigned int pad, unsigned int target, +int V4L2Subdevice::getSelection(const Stream &stream, unsigned int target, Rectangle *rect) { struct v4l2_subdev_selection sel = {}; sel.which = V4L2_SUBDEV_FORMAT_ACTIVE; - sel.pad = pad; + sel.pad = stream.pad; + sel.stream = stream.stream; sel.target = target; sel.flags = 0; @@ -927,7 +984,7 @@ int V4L2Subdevice::getSelection(unsigned int pad, unsigned int target, if (ret < 0) { LOG(V4L2, Error) << "Unable to get rectangle " << target << " on pad " - << pad << ": " << strerror(-ret); + << stream << ": " << strerror(-ret); return ret; } @@ -939,9 +996,20 @@ int V4L2Subdevice::getSelection(unsigned int pad, unsigned int target, return 0; } +/** + * \fn V4L2Subdevice::getSelection(unsigned int pad, unsigned int target, + * Rectangle *rect) + * \brief Get selection rectangle \a rect for \a target + * \param[in] pad The 0-indexed pad number the rectangle is retrieved from + * \param[in] target The selection target defined by the V4L2_SEL_TGT_* flags + * \param[out] rect The retrieved selection rectangle + * + * \return 0 on success or a negative error code otherwise + */ + /** * \brief Set selection rectangle \a rect for \a target - * \param[in] pad The 0-indexed pad number the rectangle is to be applied to + * \param[in] stream The stream the rectangle is to be applied to * \param[in] target The selection target defined by the V4L2_SEL_TGT_* flags * \param[inout] rect The selection rectangle to be applied * @@ -949,13 +1017,14 @@ int V4L2Subdevice::getSelection(unsigned int pad, unsigned int target, * * \return 0 on success or a negative error code otherwise */ -int V4L2Subdevice::setSelection(unsigned int pad, unsigned int target, +int V4L2Subdevice::setSelection(const Stream &stream, unsigned int target, Rectangle *rect) { struct v4l2_subdev_selection sel = {}; sel.which = V4L2_SUBDEV_FORMAT_ACTIVE; - sel.pad = pad; + sel.pad = stream.pad; + sel.stream = stream.stream; sel.target = target; sel.flags = 0; @@ -968,7 +1037,7 @@ int V4L2Subdevice::setSelection(unsigned int pad, unsigned int target, if (ret < 0) { LOG(V4L2, Error) << "Unable to set rectangle " << target << " on pad " - << pad << ": " << strerror(-ret); + << stream << ": " << strerror(-ret); return ret; } @@ -979,26 +1048,40 @@ int V4L2Subdevice::setSelection(unsigned int pad, unsigned int target, return 0; } + /** - * \brief Enumerate all media bus codes and frame sizes on a \a pad - * \param[in] pad The 0-indexed pad number to enumerate formats on + * \fn V4L2Subdevice::setSelection(unsigned int pad, unsigned int target, + * Rectangle *rect) + * \brief Set selection rectangle \a rect for \a target + * \param[in] pad The 0-indexed pad number the rectangle is to be applied to + * \param[in] target The selection target defined by the V4L2_SEL_TGT_* flags + * \param[inout] rect The selection rectangle to be applied + * + * \todo Define a V4L2SelectionTarget enum for the selection target + * + * \return 0 on success or a negative error code otherwise + */ + +/** + * \brief Enumerate all media bus codes and frame sizes on a \a stream + * \param[in] stream The stream to enumerate formats for * * Enumerate all media bus codes and frame sizes supported by the subdevice on - * a \a pad. + * a \a stream. * * \return A list of the supported device formats */ -V4L2Subdevice::Formats V4L2Subdevice::formats(unsigned int pad) +V4L2Subdevice::Formats V4L2Subdevice::formats(const Stream &stream) { Formats formats; - if (pad >= entity_->pads().size()) { - LOG(V4L2, Error) << "Invalid pad: " << pad; + if (stream.pad >= entity_->pads().size()) { + LOG(V4L2, Error) << "Invalid pad: " << stream.pad; return {}; } - for (unsigned int code : enumPadCodes(pad)) { - std::vector sizes = enumPadSizes(pad, code); + for (unsigned int code : enumPadCodes(stream)) { + std::vector sizes = enumPadSizes(stream, code); if (sizes.empty()) return {}; @@ -1006,7 +1089,7 @@ V4L2Subdevice::Formats V4L2Subdevice::formats(unsigned int pad) if (!inserted.second) { LOG(V4L2, Error) << "Could not add sizes for media bus code " - << code << " on pad " << pad; + << code << " on pad " << stream.pad; return {}; } } @@ -1014,6 +1097,17 @@ V4L2Subdevice::Formats V4L2Subdevice::formats(unsigned int pad) return formats; } +/** + * \fn V4L2Subdevice::formats(unsigned int pad) + * \brief Enumerate all media bus codes and frame sizes on a \a pad + * \param[in] pad The 0-indexed pad number to enumerate formats on + * + * Enumerate all media bus codes and frame sizes supported by the subdevice on + * a \a pad + * + * \return A list of the supported device formats + */ + std::optional V4L2Subdevice::toColorSpace(const v4l2_mbus_framefmt &format) const { /* @@ -1045,25 +1139,26 @@ std::optional V4L2Subdevice::toColorSpace(const v4l2_mbus_framefmt & } /** - * \brief Retrieve the image format set on one of the V4L2 subdevice pads - * \param[in] pad The 0-indexed pad number the format is to be retrieved from + * \brief Retrieve the image format set on one of the V4L2 subdevice streams + * \param[in] stream The stream the format is to be retrieved from * \param[out] format The image bus format * \param[in] whence The format to get, \ref V4L2Subdevice::ActiveFormat * "ActiveFormat" or \ref V4L2Subdevice::TryFormat "TryFormat" * \return 0 on success or a negative error code otherwise */ -int V4L2Subdevice::getFormat(unsigned int pad, V4L2SubdeviceFormat *format, +int V4L2Subdevice::getFormat(const Stream &stream, V4L2SubdeviceFormat *format, Whence whence) { struct v4l2_subdev_format subdevFmt = {}; subdevFmt.which = whence; - subdevFmt.pad = pad; + subdevFmt.pad = stream.pad; + subdevFmt.stream = stream.stream; int ret = ioctl(VIDIOC_SUBDEV_G_FMT, &subdevFmt); if (ret) { LOG(V4L2, Error) - << "Unable to get format on pad " << pad - << ": " << strerror(-ret); + << "Unable to get format on pad " << stream.pad << "/" + << stream.stream << ": " << strerror(-ret); return ret; } @@ -1076,6 +1171,66 @@ int V4L2Subdevice::getFormat(unsigned int pad, V4L2SubdeviceFormat *format, } /** + * \fn V4L2Subdevice::getFormat(unsigned int pad, V4L2SubdeviceFormat *format, + * Whence whence) + * \brief Retrieve the image format set on one of the V4L2 subdevice pads + * \param[in] pad The 0-indexed pad number the format is to be retrieved from + * \param[out] format The image bus format + * \param[in] whence The format to get, \ref V4L2Subdevice::ActiveFormat + * "ActiveFormat" or \ref V4L2Subdevice::TryFormat "TryFormat" + * \return 0 on success or a negative error code otherwise + */ + +/** + * \brief Set an image format on one of the V4L2 subdevice pads + * \param[in] stream The stream the format is to be applied to + * \param[inout] format The image bus format to apply to the stream + * \param[in] whence The format to set, \ref V4L2Subdevice::ActiveFormat + * "ActiveFormat" or \ref V4L2Subdevice::TryFormat "TryFormat" + * + * Apply the requested image format to the desired stream and return the + * actually applied format parameters, as getFormat() would do. + * + * \return 0 on success or a negative error code otherwise + */ +int V4L2Subdevice::setFormat(const Stream &stream, V4L2SubdeviceFormat *format, + Whence whence) +{ + struct v4l2_subdev_format subdevFmt = {}; + subdevFmt.which = whence; + subdevFmt.pad = stream.pad; + subdevFmt.stream = stream.stream; + subdevFmt.format.width = format->size.width; + subdevFmt.format.height = format->size.height; + subdevFmt.format.code = format->code; + subdevFmt.format.field = V4L2_FIELD_NONE; + if (format->colorSpace) { + fromColorSpace(format->colorSpace, subdevFmt.format); + + /* The CSC flag is only applicable to source pads. */ + if (entity_->pads()[stream.pad]->flags() & MEDIA_PAD_FL_SOURCE) + subdevFmt.format.flags |= V4L2_MBUS_FRAMEFMT_SET_CSC; + } + + int ret = ioctl(VIDIOC_SUBDEV_S_FMT, &subdevFmt); + if (ret) { + LOG(V4L2, Error) + << "Unable to set format on pad " << stream.pad << "/" + << stream.stream << ": " << strerror(-ret); + return ret; + } + + format->size.width = subdevFmt.format.width; + format->size.height = subdevFmt.format.height; + format->code = subdevFmt.format.code; + format->colorSpace = toColorSpace(subdevFmt.format); + + return 0; +} + +/** + * \fn V4L2Subdevice::setFormat(unsigned int pad, V4L2SubdeviceFormat *format, + * Whence whence) * \brief Set an image format on one of the V4L2 subdevice pads * \param[in] pad The 0-indexed pad number the format is to be applied to * \param[inout] format The image bus format to apply to the subdevice's pad @@ -1087,39 +1242,6 @@ int V4L2Subdevice::getFormat(unsigned int pad, V4L2SubdeviceFormat *format, * * \return 0 on success or a negative error code otherwise */ -int V4L2Subdevice::setFormat(unsigned int pad, V4L2SubdeviceFormat *format, - Whence whence) -{ - struct v4l2_subdev_format subdevFmt = {}; - subdevFmt.which = whence; - subdevFmt.pad = pad; - subdevFmt.format.width = format->size.width; - subdevFmt.format.height = format->size.height; - subdevFmt.format.code = format->code; - subdevFmt.format.field = V4L2_FIELD_NONE; - if (format->colorSpace) { - fromColorSpace(format->colorSpace, subdevFmt.format); - - /* The CSC flag is only applicable to source pads. */ - if (entity_->pads()[pad]->flags() & MEDIA_PAD_FL_SOURCE) - subdevFmt.format.flags |= V4L2_MBUS_FRAMEFMT_SET_CSC; - } - - int ret = ioctl(VIDIOC_SUBDEV_S_FMT, &subdevFmt); - if (ret) { - LOG(V4L2, Error) - << "Unable to set format on pad " << pad - << ": " << strerror(-ret); - return ret; - } - - format->size.width = subdevFmt.format.width; - format->size.height = subdevFmt.format.height; - format->code = subdevFmt.format.code; - format->colorSpace = toColorSpace(subdevFmt.format); - - return 0; -} /** * \brief Retrieve the subdevice's internal routing table @@ -1282,14 +1404,15 @@ std::string V4L2Subdevice::logPrefix() const return "'" + entity_->name() + "'"; } -std::vector V4L2Subdevice::enumPadCodes(unsigned int pad) +std::vector V4L2Subdevice::enumPadCodes(const Stream &stream) { std::vector codes; int ret; for (unsigned int index = 0; ; index++) { struct v4l2_subdev_mbus_code_enum mbusEnum = {}; - mbusEnum.pad = pad; + mbusEnum.pad = stream.pad; + mbusEnum.stream = stream.stream; mbusEnum.index = index; mbusEnum.which = V4L2_SUBDEV_FORMAT_ACTIVE; @@ -1302,15 +1425,15 @@ std::vector V4L2Subdevice::enumPadCodes(unsigned int pad) if (ret < 0 && ret != -EINVAL) { LOG(V4L2, Error) - << "Unable to enumerate formats on pad " << pad - << ": " << strerror(-ret); + << "Unable to enumerate formats on pad " << stream.pad + << "/" << stream.stream << ": " << strerror(-ret); return {}; } return codes; } -std::vector V4L2Subdevice::enumPadSizes(unsigned int pad, +std::vector V4L2Subdevice::enumPadSizes(const Stream &stream, unsigned int code) { std::vector sizes; @@ -1319,7 +1442,8 @@ std::vector V4L2Subdevice::enumPadSizes(unsigned int pad, for (unsigned int index = 0;; index++) { struct v4l2_subdev_frame_size_enum sizeEnum = {}; sizeEnum.index = index; - sizeEnum.pad = pad; + sizeEnum.pad = stream.pad; + sizeEnum.stream = stream.stream; sizeEnum.code = code; sizeEnum.which = V4L2_SUBDEV_FORMAT_ACTIVE; @@ -1333,8 +1457,8 @@ std::vector V4L2Subdevice::enumPadSizes(unsigned int pad, if (ret < 0 && ret != -EINVAL && ret != -ENOTTY) { LOG(V4L2, Error) - << "Unable to enumerate sizes on pad " << pad - << ": " << strerror(-ret); + << "Unable to enumerate sizes on pad " << stream.pad + << "/" << stream.stream << ": " << strerror(-ret); return {}; } From patchwork Fri Mar 1 21:20:57 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 19599 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id CA8AAC3260 for ; Fri, 1 Mar 2024 21:21:34 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 6D2DF6291F; Fri, 1 Mar 2024 22:21:34 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="EqTZfo88"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C984B62878 for ; Fri, 1 Mar 2024 22:21:31 +0100 (CET) Received: from pendragon.ideasonboard.com (89-27-53-110.bb.dnainternet.fi [89.27.53.110]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 5659CD04; Fri, 1 Mar 2024 22:21:17 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1709328077; bh=uU13D15WMyE83Jjb8watRMLUDFwv/tSjVB+iSXnv2rs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=EqTZfo88GWN8gV5j9uCmNbIwP86QicQ9II25QDnJEh68ke3s+v6qb2X4P5/hQbTKe yUILF6yPsTO7w84gEeTdAFg93fOB4A2A+BN4PZ00zvBKSItkDaj8H4Lrgd5pvz4RPW xPETEL/891dELHes4pihIMPJ66Bzw1if+4D+irdg= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH/RFC 08/32] libcamera: v4l2_subdevice: Replace Routing::toString() with operator<<() Date: Fri, 1 Mar 2024 23:20:57 +0200 Message-ID: <20240301212121.9072-9-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> References: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sakari Ailus Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The main (and only at the moment) use case for the Routing::toString() function is to print a representation of the routing table in a log message. The function is implemented using an std::stringstream, and the returned std::string is then inserted into an std::ostream. This is inefficient. Replace the function with a specialization of the operator<<() and use it in the caller. Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi --- include/libcamera/internal/v4l2_subdevice.h | 7 ++--- src/libcamera/pipeline/simple/simple.cpp | 2 +- src/libcamera/v4l2_subdevice.cpp | 29 +++++++++++---------- 3 files changed, 18 insertions(+), 20 deletions(-) diff --git a/include/libcamera/internal/v4l2_subdevice.h b/include/libcamera/internal/v4l2_subdevice.h index 6cd36730371a..2939dc2411c6 100644 --- a/include/libcamera/internal/v4l2_subdevice.h +++ b/include/libcamera/internal/v4l2_subdevice.h @@ -95,11 +95,7 @@ public: unsigned int stream; }; - class Routing : public std::vector - { - public: - std::string toString() const; - }; + using Routing = std::vector; explicit V4L2Subdevice(const MediaEntity *entity); ~V4L2Subdevice(); @@ -178,5 +174,6 @@ static inline bool operator!=(const V4L2Subdevice::Stream &lhs, } std::ostream &operator<<(std::ostream &out, const V4L2Subdevice::Stream &stream); +std::ostream &operator<<(std::ostream &out, const V4L2Subdevice::Routing &routing); } /* namespace libcamera */ diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp index 3d0424969a89..feea26fd124f 100644 --- a/src/libcamera/pipeline/simple/simple.cpp +++ b/src/libcamera/pipeline/simple/simple.cpp @@ -1388,7 +1388,7 @@ int SimplePipelineHandler::resetRoutingTable(V4L2Subdevice *subdev) LOG(SimplePipeline, Debug) << "Routing table of " << subdev->deviceNode() - << " reset to " << routing.toString(); + << " reset to " << routing; return 0; } diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp index 5a3c6a02f57c..5dedfde4107f 100644 --- a/src/libcamera/v4l2_subdevice.cpp +++ b/src/libcamera/v4l2_subdevice.cpp @@ -871,30 +871,31 @@ std::ostream &operator<<(std::ostream &out, const V4L2Subdevice::Stream &stream) } /** - * \class V4L2Subdevice::Routing + * \typedef V4L2Subdevice::Routing * \brief V4L2 subdevice routing table * * This class stores a subdevice routing table as a vector of routes. */ /** - * \brief Assemble and return a string describing the routing table - * \return A string describing the routing table + * \brief Insert a text representation of a V4L2Subdevice::Routing into an + * output stream + * \param[in] out The output stream + * \param[in] routing The V4L2Subdevice::Routing + * \return The output stream \a out */ -std::string V4L2Subdevice::Routing::toString() const +std::ostream &operator<<(std::ostream &out, const V4L2Subdevice::Routing &routing) { - std::stringstream routing; - - for (const auto &[i, route] : utils::enumerate(*this)) { - routing << "[" << i << "] " - << route.sink_pad << "/" << route.sink_stream << " -> " - << route.source_pad << "/" << route.source_stream - << " (" << utils::hex(route.flags) << ")"; - if (i != size() - 1) - routing << ", "; + for (const auto &[i, route] : utils::enumerate(routing)) { + out << "[" << i << "] " + << route.sink_pad << "/" << route.sink_stream << " -> " + << route.source_pad << "/" << route.source_stream + << " (" << utils::hex(route.flags) << ")"; + if (i != routing.size() - 1) + out << ", "; } - return routing.str(); + return out; } /** From patchwork Fri Mar 1 21:20:58 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 19600 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id A3366C32C3 for ; Fri, 1 Mar 2024 21:21:35 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 3B32962878; Fri, 1 Mar 2024 22:21:35 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="gMG+jCz2"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 3765162878 for ; Fri, 1 Mar 2024 22:21:33 +0100 (CET) Received: from pendragon.ideasonboard.com (89-27-53-110.bb.dnainternet.fi [89.27.53.110]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id AD220293D; Fri, 1 Mar 2024 22:21:18 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1709328078; bh=Rlfx87rM7sN4y+0fZ+Oqh9SJOUziPIAt1Rl3XUIZWxY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=gMG+jCz28A1PmGKznQOMpFO75PRDILJiaV9I5UQHhvziSX1/aBezPxqPKoFiOnDvw d+Xn23YwXGOhx66E0aj2ifnBh7nLP67t5YLlM2QcXt4A7DpydUH9Dfy+UD2axANjtr l4gJGh6Havwl6PwF6SGi14UfVNGDmslmQ9b5Twuk= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH/RFC 09/32] libcamera: v4l2_subdevice: Add V4L2Subdevice::Route structure Date: Fri, 1 Mar 2024 23:20:58 +0200 Message-ID: <20240301212121.9072-10-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> References: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sakari Ailus Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The V4L2Subdevice class deals with streams in two places: - In routing tables, streams as expressed as a pad number and a stream number in a v4l2_subdev_route instance. - In the format and selection get and set functions, streams as expressed using the Stream structure, which binds the pad number and stream number. Expressing streams in different ways requires pipeline handlers and other helpers to convert between the two representations. This isn't much of an issue yet as libcamera has little stream-aware code, but it is expected to increasingly become a burden. To simplify the API, introduce a V4L2Subdevice::Route structure that mimicks the kernel v4l2_subdev_route structure but represents streams as V4L2Subdevice::Stream instances. This will improve seamless integration of routes, formats and selection rectangles. Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi --- Changes since v1: - Clear routing at the beginning of getRouting() and setRouting() --- include/libcamera/internal/v4l2_subdevice.h | 19 +++- src/libcamera/pipeline/simple/simple.cpp | 8 +- src/libcamera/v4l2_subdevice.cpp | 106 ++++++++++++++++++-- 3 files changed, 118 insertions(+), 15 deletions(-) diff --git a/include/libcamera/internal/v4l2_subdevice.h b/include/libcamera/internal/v4l2_subdevice.h index 2939dc2411c6..01ed4c2fc397 100644 --- a/include/libcamera/internal/v4l2_subdevice.h +++ b/include/libcamera/internal/v4l2_subdevice.h @@ -95,7 +95,23 @@ public: unsigned int stream; }; - using Routing = std::vector; + struct Route { + Route() + : flags(0) + { + } + + Route(const Stream &snk, const Stream &src, uint32_t f) + : sink(snk), source(src), flags(f) + { + } + + Stream sink; + Stream source; + uint32_t flags; + }; + + using Routing = std::vector; explicit V4L2Subdevice(const MediaEntity *entity); ~V4L2Subdevice(); @@ -174,6 +190,7 @@ static inline bool operator!=(const V4L2Subdevice::Stream &lhs, } std::ostream &operator<<(std::ostream &out, const V4L2Subdevice::Stream &stream); +std::ostream &operator<<(std::ostream &out, const V4L2Subdevice::Route &route); std::ostream &operator<<(std::ostream &out, const V4L2Subdevice::Routing &routing); } /* namespace libcamera */ diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp index feea26fd124f..01f2a97798ba 100644 --- a/src/libcamera/pipeline/simple/simple.cpp +++ b/src/libcamera/pipeline/simple/simple.cpp @@ -852,17 +852,17 @@ std::vector SimpleCameraData::routedSourcePads(MediaPad *sink) std::vector pads; - for (const struct v4l2_subdev_route &route : routing) { - if (sink->index() != route.sink_pad || + for (const V4L2Subdevice::Route &route : routing) { + if (sink->index() != route.sink.pad || !(route.flags & V4L2_SUBDEV_ROUTE_FL_ACTIVE)) continue; - const MediaPad *pad = entity->getPadByIndex(route.source_pad); + const MediaPad *pad = entity->getPadByIndex(route.source.pad); if (!pad) { LOG(SimplePipeline, Warning) << "Entity " << entity->name() << " has invalid route source pad " - << route.source_pad; + << route.source.pad; } pads.push_back(pad); diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp index 5dedfde4107f..3653f57a7d10 100644 --- a/src/libcamera/v4l2_subdevice.cpp +++ b/src/libcamera/v4l2_subdevice.cpp @@ -870,6 +870,53 @@ std::ostream &operator<<(std::ostream &out, const V4L2Subdevice::Stream &stream) return out; } +/** + * \class V4L2Subdevice::Route + * \brief V4L2 subdevice routing table entry + * + * This class models a route in the subdevice routing table. It is similar to + * the v4l2_subdev_route structure, but uses the V4L2Subdevice::Stream class + * for easier usage with the V4L2Subdevice stream-aware functions. + * + * \var V4L2Subdevice::Route::sink + * \brief The sink stream of the route + * + * \var V4L2Subdevice::Route::source + * \brief The source stream of the route + * + * \var V4L2Subdevice::Route::flags + * \brief The route flags (V4L2_SUBDEV_ROUTE_FL_*) + */ + +/** + * \fn V4L2Subdevice::Route::Route() + * \brief Construct a Route with default streams + */ + +/** + * \fn V4L2Subdevice::Route::Route(const Stream &sink, const Stream &source, + * uint32_t flags) + * \brief Construct a Route from \a sink to \a source + * \param[in] sink The sink stream + * \param[in] source The source stream + * \param[in] flags The route flags + */ + +/** + * \brief Insert a text representation of a V4L2Subdevice::Route into an + * output stream + * \param[in] out The output stream + * \param[in] route The V4L2Subdevice::Route + * \return The output stream \a out + */ +std::ostream &operator<<(std::ostream &out, const V4L2Subdevice::Route &route) +{ + out << route.sink << " -> " << route.source + << " (" << utils::hex(route.flags) << ")"; + + return out; +} + /** * \typedef V4L2Subdevice::Routing * \brief V4L2 subdevice routing table @@ -887,10 +934,7 @@ std::ostream &operator<<(std::ostream &out, const V4L2Subdevice::Stream &stream) std::ostream &operator<<(std::ostream &out, const V4L2Subdevice::Routing &routing) { for (const auto &[i, route] : utils::enumerate(routing)) { - out << "[" << i << "] " - << route.sink_pad << "/" << route.sink_stream << " -> " - << route.source_pad << "/" << route.source_stream - << " (" << utils::hex(route.flags) << ")"; + out << "[" << i << "] " << route; if (i != routing.size() - 1) out << ", "; } @@ -1244,6 +1288,30 @@ int V4L2Subdevice::setFormat(const Stream &stream, V4L2SubdeviceFormat *format, * \return 0 on success or a negative error code otherwise */ +namespace { + +void routeFromKernel(V4L2Subdevice::Route &route, + const struct v4l2_subdev_route &kroute) +{ + route.sink.pad = kroute.sink_pad; + route.sink.stream = kroute.sink_stream; + route.source.pad = kroute.source_pad; + route.source.stream = kroute.source_stream; + route.flags = kroute.flags; +} + +void routeToKernel(const V4L2Subdevice::Route &route, + struct v4l2_subdev_route &kroute) +{ + kroute.sink_pad = route.sink.pad; + kroute.sink_stream = route.sink.stream; + kroute.source_pad = route.source.pad; + kroute.source_stream = route.source.stream; + kroute.flags = route.flags; +} + +} /* namespace */ + /** * \brief Retrieve the subdevice's internal routing table * \param[out] routing The routing table @@ -1254,6 +1322,8 @@ int V4L2Subdevice::setFormat(const Stream &stream, V4L2SubdeviceFormat *format, */ int V4L2Subdevice::getRouting(Routing *routing, Whence whence) { + routing->clear(); + if (!caps_.hasStreams()) return 0; @@ -1272,8 +1342,8 @@ int V4L2Subdevice::getRouting(Routing *routing, Whence whence) return ret; } - routing->resize(rt.num_routes); - rt.routes = reinterpret_cast(routing->data()); + std::vector routes{ rt.num_routes }; + rt.routes = reinterpret_cast(routes.data()); ret = ioctl(VIDIOC_SUBDEV_G_ROUTING, &rt); if (ret) { @@ -1282,11 +1352,16 @@ int V4L2Subdevice::getRouting(Routing *routing, Whence whence) return ret; } - if (rt.num_routes != routing->size()) { + if (rt.num_routes != routes.size()) { LOG(V4L2, Error) << "Invalid number of routes"; return -EINVAL; } + routing->resize(rt.num_routes); + + for (const auto &[i, route] : utils::enumerate(routes)) + routeFromKernel((*routing)[i], route); + return 0; } @@ -1304,13 +1379,20 @@ int V4L2Subdevice::getRouting(Routing *routing, Whence whence) */ int V4L2Subdevice::setRouting(Routing *routing, Whence whence) { - if (!caps_.hasStreams()) + if (!caps_.hasStreams()) { + routing->clear(); return 0; + } + + std::vector routes{ routing->size() }; + + for (const auto &[i, route] : utils::enumerate(*routing)) + routeToKernel(route, routes[i]); struct v4l2_subdev_routing rt = {}; rt.which = whence; - rt.num_routes = routing->size(); - rt.routes = reinterpret_cast(routing->data()); + rt.num_routes = routes.size(); + rt.routes = reinterpret_cast(routes.data()); int ret = ioctl(VIDIOC_SUBDEV_S_ROUTING, &rt); if (ret) { @@ -1318,8 +1400,12 @@ int V4L2Subdevice::setRouting(Routing *routing, Whence whence) return ret; } + routes.resize(rt.num_routes); routing->resize(rt.num_routes); + for (const auto &[i, route] : utils::enumerate(routes)) + routeFromKernel((*routing)[i], route); + return 0; } From patchwork Fri Mar 1 21:20:59 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 19601 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 24604BD160 for ; Fri, 1 Mar 2024 21:21:37 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id D25E36291F; Fri, 1 Mar 2024 22:21:36 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="gmdaRpry"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 956A962879 for ; Fri, 1 Mar 2024 22:21:34 +0100 (CET) Received: from pendragon.ideasonboard.com (89-27-53-110.bb.dnainternet.fi [89.27.53.110]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 12D14673; Fri, 1 Mar 2024 22:21:20 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1709328080; bh=m7f/wpZb+ozgiwkel6l9WYr9kJ2ejvTC3ZSHgVLv8dg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=gmdaRpryszep9Awoj5UJK95daGSzAB3Iuu/yRB+zw7rdXAq/fw96wb+ROW8Y87VaF BLj/pb+Dxioivcz9o2vwQQCi/hBMeAGnqonXemC8CyB6ZjhBQNXL+6f/iID/s2073d AkvD1QtmdHcGlw5ooopOJqRWHpuyUc0B75R4fAgI= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH/RFC 10/32] [DNI] include: linux: Update kernel headers to metadata API Date: Fri, 1 Mar 2024 23:20:59 +0200 Message-ID: <20240301212121.9072-11-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> References: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sakari Ailus Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Update kernel headers to the rpi/v6.8/unicam/dev branch at commit 506b705e8bce. This pulls in the new V4L2 metadata API that is under development, and should not be merged in libcamera until the API stabilizes. Signed-off-by: Laurent Pinchart --- include/linux/README | 2 +- include/linux/media-bus-format.h | 13 +++++++++++++ include/linux/media.h | 1 + include/linux/v4l2-controls.h | 16 ++++++++++++---- include/linux/v4l2-mediabus.h | 18 ++++++++++++------ include/linux/v4l2-subdev.h | 23 +++++++++++++++++------ include/linux/videodev2.h | 29 ++++++++++++++++++++++++++++- 7 files changed, 84 insertions(+), 18 deletions(-) diff --git a/include/linux/README b/include/linux/README index 101e49970af2..4ce1273d32c2 100644 --- a/include/linux/README +++ b/include/linux/README @@ -1,4 +1,4 @@ # SPDX-License-Identifier: CC0-1.0 -Files in this directory are imported from v6.7 of the Linux kernel. Do not +Files in this directory are imported from v6.7-391-g2113eb19631f of the Linux kernel. Do not modify them manually. diff --git a/include/linux/media-bus-format.h b/include/linux/media-bus-format.h index f05f747e444d..13e68c2ccb61 100644 --- a/include/linux/media-bus-format.h +++ b/include/linux/media-bus-format.h @@ -174,4 +174,17 @@ */ #define MEDIA_BUS_FMT_METADATA_FIXED 0x7001 +/* Generic line based metadata formats for serial buses. Next is 0x8008. */ +#define MEDIA_BUS_FMT_META_8 0x8001 +#define MEDIA_BUS_FMT_META_10 0x8002 +#define MEDIA_BUS_FMT_META_12 0x8003 +#define MEDIA_BUS_FMT_META_14 0x8004 +#define MEDIA_BUS_FMT_META_16 0x8005 +#define MEDIA_BUS_FMT_META_20 0x8006 +#define MEDIA_BUS_FMT_META_24 0x8007 + +/* Specific metadata formats. Next is 0x9003. */ +#define MEDIA_BUS_FMT_CCS_EMBEDDED 0x9001 +#define MEDIA_BUS_FMT_OV2740_EMBEDDED 0x9002 + #endif /* __LINUX_MEDIA_BUS_FORMAT_H */ diff --git a/include/linux/media.h b/include/linux/media.h index b5a77bbf4062..4a733b9beb27 100644 --- a/include/linux/media.h +++ b/include/linux/media.h @@ -206,6 +206,7 @@ struct media_entity_desc { #define MEDIA_PAD_FL_SINK (1U << 0) #define MEDIA_PAD_FL_SOURCE (1U << 1) #define MEDIA_PAD_FL_MUST_CONNECT (1U << 2) +#define MEDIA_PAD_FL_INTERNAL (1U << 3) struct media_pad_desc { __u32 entity; /* entity ID */ diff --git a/include/linux/v4l2-controls.h b/include/linux/v4l2-controls.h index b9f6481092c7..90ae4bcfbab4 100644 --- a/include/linux/v4l2-controls.h +++ b/include/linux/v4l2-controls.h @@ -177,10 +177,6 @@ enum v4l2_colorfx { * We reserve 128 controls for this driver. */ #define V4L2_CID_USER_CCS_BASE (V4L2_CID_USER_BASE + 0x10f0) - -/* The base for the bcm2835-isp driver controls. - * We reserve 16 controls for this driver. */ -#define V4L2_CID_USER_BCM2835_ISP_BASE (V4L2_CID_USER_BASE + 0x10e0) /* * The base for Allegro driver controls. * We reserve 16 controls for this driver. @@ -211,6 +207,18 @@ enum v4l2_colorfx { */ #define V4L2_CID_USER_NPCM_BASE (V4L2_CID_USER_BASE + 0x11b0) +/* + * The base for THine THP7312 driver controls. + * We reserve 32 controls for this driver. + */ +#define V4L2_CID_USER_THP7312_BASE (V4L2_CID_USER_BASE + 0x11c0) + +/* + * The base for the bcm2835-isp driver controls. + * We reserve 16 controls for this driver. + */ +#define V4L2_CID_USER_BCM2835_ISP_BASE (V4L2_CID_USER_BASE + 0x11d0) + /* MPEG-class control IDs */ /* The MPEG controls are applicable to all codec controls * and the 'MPEG' part of the define is historical */ diff --git a/include/linux/v4l2-mediabus.h b/include/linux/v4l2-mediabus.h index 2c318de10485..0651b09dee68 100644 --- a/include/linux/v4l2-mediabus.h +++ b/include/linux/v4l2-mediabus.h @@ -19,12 +19,18 @@ * @width: image width * @height: image height * @code: data format code (from enum v4l2_mbus_pixelcode) - * @field: used interlacing type (from enum v4l2_field) - * @colorspace: colorspace of the data (from enum v4l2_colorspace) - * @ycbcr_enc: YCbCr encoding of the data (from enum v4l2_ycbcr_encoding) - * @hsv_enc: HSV encoding of the data (from enum v4l2_hsv_encoding) - * @quantization: quantization of the data (from enum v4l2_quantization) - * @xfer_func: transfer function of the data (from enum v4l2_xfer_func) + * @field: used interlacing type (from enum v4l2_field), zero on metadata + * mbus codes + * @colorspace: colorspace of the data (from enum v4l2_colorspace), zero on + * metadata mbus codes + * @ycbcr_enc: YCbCr encoding of the data (from enum v4l2_ycbcr_encoding), zero + * on metadata mbus codes + * @hsv_enc: HSV encoding of the data (from enum v4l2_hsv_encoding), zero on + * metadata mbus codes + * @quantization: quantization of the data (from enum v4l2_quantization), zero + * on metadata mbus codes + * @xfer_func: transfer function of the data (from enum v4l2_xfer_func), zero + * on metadata mbus codes * @flags: flags (V4L2_MBUS_FRAMEFMT_*) * @reserved: reserved bytes that can be later used */ diff --git a/include/linux/v4l2-subdev.h b/include/linux/v4l2-subdev.h index b383c2fe0cf3..3b72a5956822 100644 --- a/include/linux/v4l2-subdev.h +++ b/include/linux/v4l2-subdev.h @@ -116,13 +116,15 @@ struct v4l2_subdev_frame_size_enum { * @pad: pad number, as reported by the media API * @interval: frame interval in seconds * @stream: stream number, defined in subdev routing + * @which: interval type (from enum v4l2_subdev_format_whence) * @reserved: drivers and applications must zero this array */ struct v4l2_subdev_frame_interval { __u32 pad; struct v4l2_fract interval; __u32 stream; - __u32 reserved[8]; + __u32 which; + __u32 reserved[7]; }; /** @@ -133,7 +135,7 @@ struct v4l2_subdev_frame_interval { * @width: frame width in pixels * @height: frame height in pixels * @interval: frame interval in seconds - * @which: format type (from enum v4l2_subdev_format_whence) + * @which: interval type (from enum v4l2_subdev_format_whence) * @stream: stream number, defined in subdev routing * @reserved: drivers and applications must zero this array */ @@ -222,15 +224,17 @@ struct v4l2_subdev_route { * struct v4l2_subdev_routing - Subdev routing information * * @which: configuration type (from enum v4l2_subdev_format_whence) - * @num_routes: the total number of routes in the routes array + * @len_routes: the length of the routes array, in routes * @routes: pointer to the routes array + * @num_routes: the total number of routes in the routes array * @reserved: drivers and applications must zero this array */ struct v4l2_subdev_routing { __u32 which; - __u32 num_routes; + __u32 len_routes; __u64 routes; - __u32 reserved[6]; + __u32 num_routes; + __u32 reserved[11]; }; /* @@ -239,7 +243,14 @@ struct v4l2_subdev_routing { * set (which is the default), the 'stream' fields will be forced to 0 by the * kernel. */ - #define V4L2_SUBDEV_CLIENT_CAP_STREAMS (1ULL << 0) +#define V4L2_SUBDEV_CLIENT_CAP_STREAMS (1ULL << 0) + +/* + * The client is aware of the struct v4l2_subdev_frame_interval which field. If + * this is not set (which is the default), the which field is forced to + * V4L2_SUBDEV_FORMAT_ACTIVE by the kernel. + */ +#define V4L2_SUBDEV_CLIENT_CAP_INTERVAL_USES_WHICH (1ULL << 1) /** * struct v4l2_subdev_client_capability - Capabilities of the client accessing diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index 7e556911c9e1..33e0ea95e0fa 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -572,6 +572,8 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_Y10BPACK v4l2_fourcc('Y', '1', '0', 'B') /* 10 Greyscale bit-packed */ #define V4L2_PIX_FMT_Y10P v4l2_fourcc('Y', '1', '0', 'P') /* 10 Greyscale, MIPI RAW10 packed */ #define V4L2_PIX_FMT_IPU3_Y10 v4l2_fourcc('i', 'p', '3', 'y') /* IPU3 packed 10-bit greyscale */ +#define V4L2_PIX_FMT_Y12P v4l2_fourcc('Y', '1', '2', 'P') /* 12 Greyscale, MIPI RAW12 packed */ +#define V4L2_PIX_FMT_Y14P v4l2_fourcc('Y', '1', '4', 'P') /* 14 Greyscale, MIPI RAW14 packed */ /* Palette formats */ #define V4L2_PIX_FMT_PAL8 v4l2_fourcc('P', 'A', 'L', '8') /* 8 8-bit palette */ @@ -814,6 +816,14 @@ struct v4l2_pix_format { #define V4L2_META_FMT_RK_ISP1_PARAMS v4l2_fourcc('R', 'K', '1', 'P') /* Rockchip ISP1 3A Parameters */ #define V4L2_META_FMT_RK_ISP1_STAT_3A v4l2_fourcc('R', 'K', '1', 'S') /* Rockchip ISP1 3A Statistics */ +#define V4L2_META_FMT_GENERIC_8 v4l2_fourcc('M', 'E', 'T', '8') /* Generic 8-bit metadata */ +#define V4L2_META_FMT_GENERIC_CSI2_10 v4l2_fourcc('M', 'C', '1', 'A') /* 10-bit CSI-2 packed 8-bit metadata */ +#define V4L2_META_FMT_GENERIC_CSI2_12 v4l2_fourcc('M', 'C', '1', 'C') /* 12-bit CSI-2 packed 8-bit metadata */ +#define V4L2_META_FMT_GENERIC_CSI2_14 v4l2_fourcc('M', 'C', '1', 'E') /* 14-bit CSI-2 packed 8-bit metadata */ +#define V4L2_META_FMT_GENERIC_CSI2_16 v4l2_fourcc('M', 'C', '1', 'G') /* 16-bit CSI-2 packed 8-bit metadata */ +#define V4L2_META_FMT_GENERIC_CSI2_20 v4l2_fourcc('M', 'C', '1', 'K') /* 20-bit CSI-2 packed 8-bit metadata */ +#define V4L2_META_FMT_GENERIC_CSI2_24 v4l2_fourcc('M', 'C', '1', 'O') /* 24-bit CSI-2 packed 8-bit metadata */ + /* priv field value to indicates that subsequent fields are valid. */ #define V4L2_PIX_FMT_PRIV_MAGIC 0xfeedcafe @@ -844,6 +854,7 @@ struct v4l2_fmtdesc { #define V4L2_FMT_FLAG_CSC_YCBCR_ENC 0x0080 #define V4L2_FMT_FLAG_CSC_HSV_ENC V4L2_FMT_FLAG_CSC_YCBCR_ENC #define V4L2_FMT_FLAG_CSC_QUANTIZATION 0x0100 +#define V4L2_FMT_FLAG_META_LINE_BASED 0x0200 /* Frame Size and frame rate enumeration */ /* @@ -993,6 +1004,7 @@ struct v4l2_requestbuffers { #define V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS (1 << 4) #define V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF (1 << 5) #define V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS (1 << 6) +#define V4L2_BUF_CAP_SUPPORTS_MAX_NUM_BUFFERS (1 << 7) /** * struct v4l2_plane - plane info for multi-planar buffers @@ -1787,6 +1799,8 @@ struct v4l2_ext_control { struct v4l2_ctrl_av1_tile_group_entry *p_av1_tile_group_entry; struct v4l2_ctrl_av1_frame *p_av1_frame; struct v4l2_ctrl_av1_film_grain *p_av1_film_grain; + struct v4l2_ctrl_hdr10_cll_info *p_hdr10_cll_info; + struct v4l2_ctrl_hdr10_mastering_display *p_hdr10_mastering_display; void *ptr; }; } __attribute__ ((packed)); @@ -2358,10 +2372,19 @@ struct v4l2_sdr_format { * struct v4l2_meta_format - metadata format definition * @dataformat: little endian four character code (fourcc) * @buffersize: maximum size in bytes required for data + * @width: number of data units of data per line (valid for line + * based formats only, see format documentation) + * @height: number of lines of data per buffer (valid for line based + * formats only) + * @bytesperline: offset between the beginnings of two adjacent lines in + * bytes (valid for line based formats only) */ struct v4l2_meta_format { __u32 dataformat; __u32 buffersize; + __u32 width; + __u32 height; + __u32 bytesperline; } __attribute__ ((packed)); /** @@ -2547,6 +2570,9 @@ struct v4l2_dbg_chip_info { * @flags: additional buffer management attributes (ignored unless the * queue has V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS capability * and configured for MMAP streaming I/O). + * @max_num_buffers: if V4L2_BUF_CAP_SUPPORTS_MAX_NUM_BUFFERS capability flag is set + * this field indicate the maximum possible number of buffers + * for this queue. * @reserved: future extensions */ struct v4l2_create_buffers { @@ -2556,7 +2582,8 @@ struct v4l2_create_buffers { struct v4l2_format format; __u32 capabilities; __u32 flags; - __u32 reserved[6]; + __u32 max_num_buffers; + __u32 reserved[5]; }; /* From patchwork Fri Mar 1 21:21:00 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 19602 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 0E6C8C3260 for ; Fri, 1 Mar 2024 21:21:38 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id A84B562B3D; Fri, 1 Mar 2024 22:21:37 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="XkoeKNse"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 1C21262876 for ; Fri, 1 Mar 2024 22:21:36 +0100 (CET) Received: from pendragon.ideasonboard.com (89-27-53-110.bb.dnainternet.fi [89.27.53.110]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id A60B2A9A; Fri, 1 Mar 2024 22:21:21 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1709328081; bh=A/vx4y0whQuSO5nLGsivMVu/Kx0cQsMGQuhbBsWnia0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=XkoeKNseZEN9MMX0Y/V8QbrdKU340a6GRbfejF5UaI2jk56ID/ucR8m/A+Kf1IJz9 hlclj0e+b5ijjSqxwqQobZNCcUnxNual8FIUhvSGlP9n/yDXcahp8Xqj+aCpfL0/En 2fDqApccTghfbthZOn0vlOhaYuBtQuCX8Yy1rAKY= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH/RFC 11/32] libcamera: v4l2_subdevice: Update to the new kernel routing API Date: Fri, 1 Mar 2024 23:21:00 +0200 Message-ID: <20240301212121.9072-12-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> References: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sakari Ailus Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The subdev embedded data support series includes a change to the VIDIOC_SUBDEV_G_ROUTING and VIDIOC_SUBDEV_S_ROUTING ioctls that impacts the userspace API. Update to the new API. Backward compatibility can't be easily preserved as the ioctl structure size has changed. This is not a major issue, as the routing API isn't enabled in any upstream kernel. Signed-off-by: Laurent Pinchart --- src/libcamera/v4l2_subdevice.cpp | 43 ++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp index 3653f57a7d10..d5d400cdfd58 100644 --- a/src/libcamera/v4l2_subdevice.cpp +++ b/src/libcamera/v4l2_subdevice.cpp @@ -1332,19 +1332,23 @@ int V4L2Subdevice::getRouting(Routing *routing, Whence whence) rt.which = whence; int ret = ioctl(VIDIOC_SUBDEV_G_ROUTING, &rt); - if (ret == 0 || ret == -ENOTTY) - return ret; - - if (ret != -ENOSPC) { - LOG(V4L2, Error) - << "Failed to retrieve number of routes: " - << strerror(-ret); + if (ret) { + if (ret != -ENOTTY) + LOG(V4L2, Error) + << "Failed to retrieve number of routes: " + << strerror(-ret); return ret; } + if (!rt.num_routes) + return 0; + std::vector routes{ rt.num_routes }; rt.routes = reinterpret_cast(routes.data()); + rt.len_routes = rt.num_routes; + rt.num_routes = 0; + ret = ioctl(VIDIOC_SUBDEV_G_ROUTING, &rt); if (ret) { LOG(V4L2, Error) @@ -1391,6 +1395,7 @@ int V4L2Subdevice::setRouting(Routing *routing, Whence whence) struct v4l2_subdev_routing rt = {}; rt.which = whence; + rt.len_routes = routes.size(); rt.num_routes = routes.size(); rt.routes = reinterpret_cast(routes.data()); @@ -1400,7 +1405,29 @@ int V4L2Subdevice::setRouting(Routing *routing, Whence whence) return ret; } - routes.resize(rt.num_routes); + /* + * The kernel wants to return more routes than we have space for. We + * need to issue a VIDIOC_SUBDEV_G_ROUTING call. + */ + if (rt.num_routes > routes.size()) { + routes.resize(rt.num_routes); + + rt.len_routes = rt.num_routes; + rt.num_routes = 0; + + ret = ioctl(VIDIOC_SUBDEV_G_ROUTING, &rt); + if (ret) { + LOG(V4L2, Error) + << "Failed to retrieve routes: " << strerror(-ret); + return ret; + } + } + + if (rt.num_routes != routes.size()) { + LOG(V4L2, Error) << "Invalid number of routes"; + return -EINVAL; + } + routing->resize(rt.num_routes); for (const auto &[i, route] : utils::enumerate(routes)) From patchwork Fri Mar 1 21:21:01 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 19603 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id AE9AABD160 for ; Fri, 1 Mar 2024 21:21:40 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 608EE62B3D; Fri, 1 Mar 2024 22:21:40 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="kIjOTPCh"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 8E6636285F for ; Fri, 1 Mar 2024 22:21:37 +0100 (CET) Received: from pendragon.ideasonboard.com (89-27-53-110.bb.dnainternet.fi [89.27.53.110]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 150A622D9; Fri, 1 Mar 2024 22:21:23 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1709328083; bh=JokVSWnxTHBjOFc7rr8QhD2UCDJefVgfQTFoEZyjlI4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=kIjOTPChipQ3qrl5Er8fArgw1aiKjAcm+oQkA/VCqaEeWxokNoFMWlqvSXCxOp/Te 6PU14vxwE7X1KT3Ik1HuuFpKJuYqTPEKdgWPKS7oju/5opn2qBad2kaWMxhvjT7oOD JfTOvZRzmg3/JQxDt7fT1aO+S5SesMLrbjec5i6Q= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH/RFC 12/32] libcamera: v4l2_subdevice: Add new metadata formats Date: Fri, 1 Mar 2024 23:21:01 +0200 Message-ID: <20240301212121.9072-13-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> References: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sakari Ailus Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Support the newly introduced V4L2 media bus formats for metadata. This includes generic metadata formats, and two sensor-specific embedded data formats. Signed-off-by: Laurent Pinchart --- src/libcamera/v4l2_subdevice.cpp | 63 ++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp index d5d400cdfd58..c2c9577cba9c 100644 --- a/src/libcamera/v4l2_subdevice.cpp +++ b/src/libcamera/v4l2_subdevice.cpp @@ -645,6 +645,69 @@ const std::map mediaBusFormatInfo{ .bitsPerPixel = 0, .colourEncoding = PixelFormatInfo::ColourEncodingRAW, } }, + { MEDIA_BUS_FMT_META_8, { + .name = "META_8", + .code = MEDIA_BUS_FMT_META_8, + .type = MediaBusFormatInfo::Type::Metadata, + .bitsPerPixel = 8, + .colourEncoding = PixelFormatInfo::ColourEncodingRAW, + } }, + { MEDIA_BUS_FMT_META_10, { + .name = "META_10", + .code = MEDIA_BUS_FMT_META_10, + .type = MediaBusFormatInfo::Type::Metadata, + .bitsPerPixel = 10, + .colourEncoding = PixelFormatInfo::ColourEncodingRAW, + } }, + { MEDIA_BUS_FMT_META_12, { + .name = "META_12", + .code = MEDIA_BUS_FMT_META_12, + .type = MediaBusFormatInfo::Type::Metadata, + .bitsPerPixel = 12, + .colourEncoding = PixelFormatInfo::ColourEncodingRAW, + } }, + { MEDIA_BUS_FMT_META_14, { + .name = "META_14", + .code = MEDIA_BUS_FMT_META_14, + .type = MediaBusFormatInfo::Type::Metadata, + .bitsPerPixel = 14, + .colourEncoding = PixelFormatInfo::ColourEncodingRAW, + } }, + { MEDIA_BUS_FMT_META_16, { + .name = "META_16", + .code = MEDIA_BUS_FMT_META_16, + .type = MediaBusFormatInfo::Type::Metadata, + .bitsPerPixel = 16, + .colourEncoding = PixelFormatInfo::ColourEncodingRAW, + } }, + { MEDIA_BUS_FMT_META_20, { + .name = "META_20", + .code = MEDIA_BUS_FMT_META_20, + .type = MediaBusFormatInfo::Type::Metadata, + .bitsPerPixel = 20, + .colourEncoding = PixelFormatInfo::ColourEncodingRAW, + } }, + { MEDIA_BUS_FMT_META_24, { + .name = "META_24", + .code = MEDIA_BUS_FMT_META_24, + .type = MediaBusFormatInfo::Type::Metadata, + .bitsPerPixel = 24, + .colourEncoding = PixelFormatInfo::ColourEncodingRAW, + } }, + { MEDIA_BUS_FMT_CCS_EMBEDDED, { + .name = "CCS_EMBEDDED", + .code = MEDIA_BUS_FMT_CCS_EMBEDDED, + .type = MediaBusFormatInfo::Type::EmbeddedData, + .bitsPerPixel = 0, + .colourEncoding = PixelFormatInfo::ColourEncodingRAW, + } }, + { MEDIA_BUS_FMT_OV2740_EMBEDDED, { + .name = "OV2740_EMBEDDED", + .code = MEDIA_BUS_FMT_CCS_EMBEDDED, + .type = MediaBusFormatInfo::Type::EmbeddedData, + .bitsPerPixel = 0, + .colourEncoding = PixelFormatInfo::ColourEncodingRAW, + } }, }; } /* namespace */ From patchwork Fri Mar 1 21:21:02 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 19604 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 939F0C3260 for ; Fri, 1 Mar 2024 21:21:41 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 29578628AC; Fri, 1 Mar 2024 22:21:41 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="H5+TuIkl"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0635F6285F for ; Fri, 1 Mar 2024 22:21:39 +0100 (CET) Received: from pendragon.ideasonboard.com (89-27-53-110.bb.dnainternet.fi [89.27.53.110]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 8335D335C; Fri, 1 Mar 2024 22:21:24 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1709328084; bh=Ykoy4mK1Q+sBVellJ/mJHZzrIxLMGD90dumBlouCl60=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=H5+TuIkl/Y7AYxagQNo2wO/8A21l6R8rvI1SGErBfBq6Nc7AhZo5S3XyjlqBHuolY +NwcrMzNbWMU13S6xk0h6Clj9zyD+g100y5byi8FeAfgk8wMUVrgAJV797KIsXVnYI gJGOSo0kHs9aLjKcvO4OaB++gkXvBtUDODX1G0Sk= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH/RFC 13/32] libcamera: v4l2_videodevice: Update to the new kernel metadata API Date: Fri, 1 Mar 2024 23:21:02 +0200 Message-ID: <20240301212121.9072-14-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> References: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sakari Ailus Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" With support for metadata in the streams API, the v4l2_meta_format structure has been extended with width, height and bytesperline fields. Support them in the V4L2VideoDevice getFormat() and setFormat() functions. Signed-off-by: Laurent Pinchart --- src/libcamera/v4l2_videodevice.cpp | 31 ++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp index a72ef64de4a2..9d4a0a3ccd0b 100644 --- a/src/libcamera/v4l2_videodevice.cpp +++ b/src/libcamera/v4l2_videodevice.cpp @@ -863,7 +863,7 @@ int V4L2VideoDevice::setFormat(V4L2DeviceFormat *format) int V4L2VideoDevice::getFormatMeta(V4L2DeviceFormat *format) { struct v4l2_format v4l2Format = {}; - struct v4l2_meta_format *pix = &v4l2Format.fmt.meta; + struct v4l2_meta_format *meta = &v4l2Format.fmt.meta; int ret; v4l2Format.type = bufferType_; @@ -873,12 +873,12 @@ int V4L2VideoDevice::getFormatMeta(V4L2DeviceFormat *format) return ret; } - format->size.width = 0; - format->size.height = 0; - format->fourcc = V4L2PixelFormat(pix->dataformat); + format->size.width = meta->width; + format->size.height = meta->height; + format->fourcc = V4L2PixelFormat(meta->dataformat); format->planesCount = 1; - format->planes[0].bpl = pix->buffersize; - format->planes[0].size = pix->buffersize; + format->planes[0].bpl = meta->bytesperline; + format->planes[0].size = meta->buffersize; return 0; } @@ -886,12 +886,15 @@ int V4L2VideoDevice::getFormatMeta(V4L2DeviceFormat *format) int V4L2VideoDevice::trySetFormatMeta(V4L2DeviceFormat *format, bool set) { struct v4l2_format v4l2Format = {}; - struct v4l2_meta_format *pix = &v4l2Format.fmt.meta; + struct v4l2_meta_format *meta = &v4l2Format.fmt.meta; int ret; v4l2Format.type = bufferType_; - pix->dataformat = format->fourcc; - pix->buffersize = format->planes[0].size; + meta->width = format->size.width; + meta->height = format->size.height; + meta->dataformat = format->fourcc; + meta->bytesperline = format->planes[0].bpl; + meta->buffersize = format->planes[0].size; ret = ioctl(set ? VIDIOC_S_FMT : VIDIOC_TRY_FMT, &v4l2Format); if (ret) { LOG(V4L2, Error) @@ -904,12 +907,12 @@ int V4L2VideoDevice::trySetFormatMeta(V4L2DeviceFormat *format, bool set) * Return to caller the format actually applied on the video device, * which might differ from the requested one. */ - format->size.width = 0; - format->size.height = 0; - format->fourcc = V4L2PixelFormat(pix->dataformat); + format->size.width = meta->width; + format->size.height = meta->height; + format->fourcc = V4L2PixelFormat(meta->dataformat); format->planesCount = 1; - format->planes[0].bpl = pix->buffersize; - format->planes[0].size = pix->buffersize; + format->planes[0].bpl = meta->bytesperline; + format->planes[0].size = meta->buffersize; return 0; } From patchwork Fri Mar 1 21:21:03 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 19605 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 4F225BD160 for ; Fri, 1 Mar 2024 21:21:44 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 0A6C462B3D; Fri, 1 Mar 2024 22:21:44 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="sZmJGuyK"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 5F06962876 for ; Fri, 1 Mar 2024 22:21:40 +0100 (CET) Received: from pendragon.ideasonboard.com (89-27-53-110.bb.dnainternet.fi [89.27.53.110]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id DBF1B2D6B; Fri, 1 Mar 2024 22:21:25 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1709328086; bh=5d87m6A4rdpGH5Moa/arL79EQkJ5SF5QdsOgZxFAExs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=sZmJGuyKLkTaqNwPo3Zpy2wunwuPKe2jTts52jdcmOrYqTtJ0IyZmUxa0EQA+bs5F +t+apKLe626511PdSFXPubs5kHCRJVDuhzSwg4iEIxCn+uzJYzN1ykGeIpZd2g2suS jV+W43zLZfgbVu4tvttNVYoLkQnugzewHv4ICb4w= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH/RFC 14/32] libcamera: camera_sensor: Move related classes to subdirectory Date: Fri, 1 Mar 2024 23:21:03 +0200 Message-ID: <20240301212121.9072-15-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> References: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sakari Ailus Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" In preparation for adding alternative implementations of the CameraSensor class, move the code to a subdirectory to avoid cluttering the main src/libcamera/ directory. Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi Reviewed-by: Stefan Klug --- src/libcamera/meson.build | 3 +-- src/libcamera/{ => sensor}/camera_sensor.cpp | 0 src/libcamera/{ => sensor}/camera_sensor_properties.cpp | 0 src/libcamera/sensor/meson.build | 6 ++++++ 4 files changed, 7 insertions(+), 2 deletions(-) rename src/libcamera/{ => sensor}/camera_sensor.cpp (100%) rename src/libcamera/{ => sensor}/camera_sensor_properties.cpp (100%) create mode 100644 src/libcamera/sensor/meson.build diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 45f63e932e4f..2e7b0c77e63c 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -7,8 +7,6 @@ libcamera_sources = files([ 'camera_controls.cpp', 'camera_lens.cpp', 'camera_manager.cpp', - 'camera_sensor.cpp', - 'camera_sensor_properties.cpp', 'color_space.cpp', 'controls.cpp', 'control_serializer.cpp', @@ -69,6 +67,7 @@ subdir('converter') subdir('ipa') subdir('pipeline') subdir('proxy') +subdir('sensor') null_dep = dependency('', required : false) diff --git a/src/libcamera/camera_sensor.cpp b/src/libcamera/sensor/camera_sensor.cpp similarity index 100% rename from src/libcamera/camera_sensor.cpp rename to src/libcamera/sensor/camera_sensor.cpp diff --git a/src/libcamera/camera_sensor_properties.cpp b/src/libcamera/sensor/camera_sensor_properties.cpp similarity index 100% rename from src/libcamera/camera_sensor_properties.cpp rename to src/libcamera/sensor/camera_sensor_properties.cpp diff --git a/src/libcamera/sensor/meson.build b/src/libcamera/sensor/meson.build new file mode 100644 index 000000000000..bf4b131a94b1 --- /dev/null +++ b/src/libcamera/sensor/meson.build @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: CC0-1.0 + +libcamera_sources += files([ + 'camera_sensor.cpp', + 'camera_sensor_properties.cpp', +]) From patchwork Fri Mar 1 21:21:04 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 19606 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 434BCC3260 for ; Fri, 1 Mar 2024 21:21:45 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id B0E5D62C83; Fri, 1 Mar 2024 22:21:44 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="aXwFdjs1"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id B3BA262964 for ; Fri, 1 Mar 2024 22:21:41 +0100 (CET) Received: from pendragon.ideasonboard.com (89-27-53-110.bb.dnainternet.fi [89.27.53.110]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 3F96E3305; Fri, 1 Mar 2024 22:21:27 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1709328087; bh=kxW9XI3rwqAn5ldiS1qOKwd3E4CgfdRqBSW1dMd5HWU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=aXwFdjs1FcPrTbpSJw0Wha6EdhzW8bdg/HkZv5eFY/oZf2UFI9l4Gqb1LZDMU8yz6 +xoiA47zVbxegL33P6gRgRY9yKacOr+/7glDxE3o8lr+jcRcSQqZG+xn5wy5eRXoxK WlBnWj8Wq5FSDXA51+o3RzYV6mPFNO+PUFzJzuiI= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH/RFC 15/32] libcamera: camera_sensor: Drop updateControlInfo() function Date: Fri, 1 Mar 2024 23:21:04 +0200 Message-ID: <20240301212121.9072-16-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> References: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sakari Ailus Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The CameraSensor::updateControlInfo() function is a wrapper around the same function of the V4L2Subdevice class. It was meant to be called by pipeline handlers that modify the sensor configuration directly, bypassing the CameraSensor::setFormat() function. This never happened, and the function is called once only, internally to the CameraSensor class. No external users are foreseen, drop the function and call V4L2Subdevice::updateControlInfo() directly. Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi Reviewed-by: Stefan Klug --- include/libcamera/internal/camera_sensor.h | 2 -- src/libcamera/sensor/camera_sensor.cpp | 20 ++------------------ 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/include/libcamera/internal/camera_sensor.h b/include/libcamera/internal/camera_sensor.h index 60a8b106d175..b2f077b9cc75 100644 --- a/include/libcamera/internal/camera_sensor.h +++ b/include/libcamera/internal/camera_sensor.h @@ -75,8 +75,6 @@ public: const ControlList &properties() const { return properties_; } int sensorInfo(IPACameraSensorInfo *info) const; - void updateControlInfo(); - CameraLens *focusLens() { return focusLens_.get(); } Transform computeTransform(Orientation *orientation) const; diff --git a/src/libcamera/sensor/camera_sensor.cpp b/src/libcamera/sensor/camera_sensor.cpp index af5d97f35de1..545f89d036df 100644 --- a/src/libcamera/sensor/camera_sensor.cpp +++ b/src/libcamera/sensor/camera_sensor.cpp @@ -814,7 +814,7 @@ int CameraSensor::setFormat(V4L2SubdeviceFormat *format, Transform transform) if (ret) return ret; - updateControlInfo(); + subdev_->updateControlInfo(); return 0; } @@ -924,9 +924,7 @@ int CameraSensor::applyConfiguration(const SensorConfiguration &config, * * Control information is updated automatically to reflect the current sensor * configuration when the setFormat() function is called, without invalidating - * any iterator on the ControlInfoMap. A manual update can also be forced by - * calling the updateControlInfo() function for pipeline handlers that change - * the sensor configuration wihtout using setFormat(). + * any iterator on the ControlInfoMap. * * \return A map of the V4L2 controls supported by the sensor */ @@ -1013,10 +1011,6 @@ int CameraSensor::setControls(ControlList *ctrls) * Sensor information is only available for raw sensors. When called for a YUV * sensor, this function returns -EINVAL. * - * Pipeline handlers that do not change the sensor format using the setFormat() - * function may need to call updateControlInfo() beforehand, to ensure all the - * control ranges are up to date. - * * \return 0 on success, a negative error code otherwise */ int CameraSensor::sensorInfo(IPACameraSensorInfo *info) const @@ -1094,16 +1088,6 @@ int CameraSensor::sensorInfo(IPACameraSensorInfo *info) const return 0; } -/** - * \fn void CameraSensor::updateControlInfo() - * \brief Update the sensor's ControlInfoMap in case they have changed - * \sa V4L2Device::updateControlInfo() - */ -void CameraSensor::updateControlInfo() -{ - subdev_->updateControlInfo(); -} - /** * \fn CameraSensor::focusLens() * \brief Retrieve the focus lens controller From patchwork Fri Mar 1 21:21:05 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 19607 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id C2F4FBD160 for ; Fri, 1 Mar 2024 21:21:46 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 7DEDE62B3D; Fri, 1 Mar 2024 22:21:46 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="fWjHfjhc"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2C8BF62973 for ; Fri, 1 Mar 2024 22:21:43 +0100 (CET) Received: from pendragon.ideasonboard.com (89-27-53-110.bb.dnainternet.fi [89.27.53.110]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id A8FC63263; Fri, 1 Mar 2024 22:21:28 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1709328088; bh=l9IhGEVXAL09vcS7KoG1j437iANs+m7qNSq4ZH4nje0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=fWjHfjhcBhWTQMoOawawhrT7w2n/uWxkhk7/2fSLrnt9bF8s0jXkMdc3dhPRZstUZ +dnZZeJM26XK7yUcQY/EzYDmKLQNRx70QuSMqytwc4MnaX8B8CBtCbf8KPSrKivgMn VA3cLB804cOi3HU0Mrrvmp3FjHB0hRGLXtY8m3xA= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH/RFC 16/32] libcamera: camera_sensor: Reorder functions Date: Fri, 1 Mar 2024 23:21:05 +0200 Message-ID: <20240301212121.9072-17-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> References: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sakari Ailus Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The CameraSensor class has grown a lot since its creation, with many functions added for different types of purposes. They are not grouped by categories in the class definition, generating confusion when reading the header file. Improve readability by sorting functions by category: - Getters for static data (model, entity, focus lens, ...) - Format and sensor configuration accessors - Properties and controls (including test pattern mode) Update the .cpp file accordingly. Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi Reviewed-by: Stefan Klug --- include/libcamera/internal/camera_sensor.h | 29 +- src/libcamera/sensor/camera_sensor.cpp | 328 ++++++++++----------- 2 files changed, 179 insertions(+), 178 deletions(-) diff --git a/include/libcamera/internal/camera_sensor.h b/include/libcamera/internal/camera_sensor.h index b2f077b9cc75..750d6d729cac 100644 --- a/include/libcamera/internal/camera_sensor.h +++ b/include/libcamera/internal/camera_sensor.h @@ -46,15 +46,15 @@ public: const std::string &model() const { return model_; } const std::string &id() const { return id_; } + const MediaEntity *entity() const { return entity_; } + V4L2Subdevice *device() { return subdev_.get(); } + + CameraLens *focusLens() { return focusLens_.get(); } + const std::vector &mbusCodes() const { return mbusCodes_; } std::vector sizes(unsigned int mbusCode) const; Size resolution() const; - const std::vector &testPatternModes() const - { - return testPatternModes_; - } - int setTestPatternMode(controls::draft::TestPatternModeEnum mode); V4L2SubdeviceFormat getFormat(const std::vector &mbusCodes, const Size &size) const; @@ -66,18 +66,19 @@ public: Transform transform = Transform::Identity, V4L2SubdeviceFormat *sensorFormat = nullptr); + const ControlList &properties() const { return properties_; } + int sensorInfo(IPACameraSensorInfo *info) const; + Transform computeTransform(Orientation *orientation) const; + const ControlInfoMap &controls() const; ControlList getControls(const std::vector &ids); int setControls(ControlList *ctrls); - V4L2Subdevice *device() { return subdev_.get(); } - - const ControlList &properties() const { return properties_; } - int sensorInfo(IPACameraSensorInfo *info) const; - - CameraLens *focusLens() { return focusLens_.get(); } - - Transform computeTransform(Orientation *orientation) const; + const std::vector &testPatternModes() const + { + return testPatternModes_; + } + int setTestPatternMode(controls::draft::TestPatternModeEnum mode); protected: std::string logPrefix() const override; @@ -91,8 +92,8 @@ private: void initStaticProperties(); void initTestPatternModes(); int initProperties(); - int applyTestPatternMode(controls::draft::TestPatternModeEnum mode); int discoverAncillaryDevices(); + int applyTestPatternMode(controls::draft::TestPatternModeEnum mode); const MediaEntity *entity_; std::unique_ptr subdev_; diff --git a/src/libcamera/sensor/camera_sensor.cpp b/src/libcamera/sensor/camera_sensor.cpp index 545f89d036df..86ad9a85371c 100644 --- a/src/libcamera/sensor/camera_sensor.cpp +++ b/src/libcamera/sensor/camera_sensor.cpp @@ -215,6 +215,30 @@ int CameraSensor::init() return applyTestPatternMode(controls::draft::TestPatternModeEnum::TestPatternModeOff); } +int CameraSensor::generateId() +{ + const std::string devPath = subdev_->devicePath(); + + /* Try to get ID from firmware description. */ + id_ = sysfs::firmwareNodePath(devPath); + if (!id_.empty()) + return 0; + + /* + * Virtual sensors not described in firmware + * + * Verify it's a platform device and construct ID from the device path + * and model of sensor. + */ + if (devPath.find("/sys/devices/platform/", 0) == 0) { + id_ = devPath.substr(strlen("/sys/devices/")) + " " + model(); + return 0; + } + + LOG(CameraSensor, Error) << "Can't generate sensor ID"; + return -EINVAL; +} + int CameraSensor::validateSensorDriver() { int err = 0; @@ -580,6 +604,21 @@ int CameraSensor::discoverAncillaryDevices() * \return The sensor media entity */ +/** + * \fn CameraSensor::device() + * \brief Retrieve the camera sensor device + * \todo Remove this function by integrating DelayedControl with CameraSensor + * \return The camera sensor device + */ + +/** + * \fn CameraSensor::focusLens() + * \brief Retrieve the focus lens controller + * + * \return The focus lens controller. nullptr if no focus lens controller is + * connected to the sensor + */ + /** * \fn CameraSensor::mbusCodes() * \brief Retrieve the media bus codes supported by the camera sensor @@ -632,64 +671,6 @@ Size CameraSensor::resolution() const return std::min(sizes_.back(), activeArea_.size()); } -/** - * \fn CameraSensor::testPatternModes() - * \brief Retrieve all the supported test pattern modes of the camera sensor - * The test pattern mode values correspond to the controls::TestPattern control. - * - * \return The list of test pattern modes - */ - -/** - * \brief Set the test pattern mode for the camera sensor - * \param[in] mode The test pattern mode - * - * The new \a mode is applied to the sensor if it differs from the active test - * pattern mode. Otherwise, this function is a no-op. Setting the same test - * pattern mode for every frame thus incurs no performance penalty. - */ -int CameraSensor::setTestPatternMode(controls::draft::TestPatternModeEnum mode) -{ - if (testPatternMode_ == mode) - return 0; - - if (testPatternModes_.empty()) { - LOG(CameraSensor, Error) - << "Camera sensor does not support test pattern modes."; - return -EINVAL; - } - - return applyTestPatternMode(mode); -} - -int CameraSensor::applyTestPatternMode(controls::draft::TestPatternModeEnum mode) -{ - if (testPatternModes_.empty()) - return 0; - - auto it = std::find(testPatternModes_.begin(), testPatternModes_.end(), - mode); - if (it == testPatternModes_.end()) { - LOG(CameraSensor, Error) << "Unsupported test pattern mode " - << mode; - return -EINVAL; - } - - LOG(CameraSensor, Debug) << "Apply test pattern mode " << mode; - - int32_t index = staticProps_->testPatternModes.at(mode); - ControlList ctrls{ controls() }; - ctrls.set(V4L2_CID_TEST_PATTERN, index); - - int ret = setControls(&ctrls); - if (ret) - return ret; - - testPatternMode_ = mode; - - return 0; -} - /** * \brief Retrieve the best sensor format for a desired output * \param[in] mbusCodes The list of acceptable media bus codes @@ -919,80 +900,6 @@ int CameraSensor::applyConfiguration(const SensorConfiguration &config, return 0; } -/** - * \brief Retrieve the supported V4L2 controls and their information - * - * Control information is updated automatically to reflect the current sensor - * configuration when the setFormat() function is called, without invalidating - * any iterator on the ControlInfoMap. - * - * \return A map of the V4L2 controls supported by the sensor - */ -const ControlInfoMap &CameraSensor::controls() const -{ - return subdev_->controls(); -} - -/** - * \brief Read V4L2 controls from the sensor - * \param[in] ids The list of controls to read, specified by their ID - * - * This function reads the value of all controls contained in \a ids, and - * returns their values as a ControlList. The control identifiers are defined by - * the V4L2 specification (V4L2_CID_*). - * - * If any control in \a ids is not supported by the device, is disabled (i.e. - * has the V4L2_CTRL_FLAG_DISABLED flag set), or if any other error occurs - * during validation of the requested controls, no control is read and this - * function returns an empty control list. - * - * \sa V4L2Device::getControls() - * - * \return The control values in a ControlList on success, or an empty list on - * error - */ -ControlList CameraSensor::getControls(const std::vector &ids) -{ - return subdev_->getControls(ids); -} - -/** - * \brief Write V4L2 controls to the sensor - * \param[in] ctrls The list of controls to write - * - * This function writes the value of all controls contained in \a ctrls, and - * stores the values actually applied to the device in the corresponding \a - * ctrls entry. The control identifiers are defined by the V4L2 specification - * (V4L2_CID_*). - * - * If any control in \a ctrls is not supported by the device, is disabled (i.e. - * has the V4L2_CTRL_FLAG_DISABLED flag set), is read-only, or if any other - * error occurs during validation of the requested controls, no control is - * written and this function returns -EINVAL. - * - * If an error occurs while writing the controls, the index of the first - * control that couldn't be written is returned. All controls below that index - * are written and their values are updated in \a ctrls, while all other - * controls are not written and their values are not changed. - * - * \sa V4L2Device::setControls() - * - * \return 0 on success or an error code otherwise - * \retval -EINVAL One of the control is not supported or not accessible - * \retval i The index of the control that failed - */ -int CameraSensor::setControls(ControlList *ctrls) -{ - return subdev_->setControls(ctrls); -} - -/** - * \fn CameraSensor::device() - * \brief Retrieve the camera sensor device - * \todo Remove this function by integrating DelayedControl with CameraSensor - * \return The camera sensor device - */ - /** * \fn CameraSensor::properties() * \brief Retrieve the camera sensor properties @@ -1088,14 +995,6 @@ int CameraSensor::sensorInfo(IPACameraSensorInfo *info) const return 0; } -/** - * \fn CameraSensor::focusLens() - * \brief Retrieve the focus lens controller - * - * \return The focus lens controller. nullptr if no focus lens controller is - * connected to the sensor - */ - /** * \brief Compute the Transform that gives the requested \a orientation * \param[inout] orientation The desired image orientation @@ -1155,33 +1054,134 @@ Transform CameraSensor::computeTransform(Orientation *orientation) const return transform; } +/** + * \brief Retrieve the supported V4L2 controls and their information + * + * Control information is updated automatically to reflect the current sensor + * configuration when the setFormat() function is called, without invalidating + * any iterator on the ControlInfoMap. + * + * \return A map of the V4L2 controls supported by the sensor + */ +const ControlInfoMap &CameraSensor::controls() const +{ + return subdev_->controls(); +} + +/** + * \brief Read V4L2 controls from the sensor + * \param[in] ids The list of controls to read, specified by their ID + * + * This function reads the value of all controls contained in \a ids, and + * returns their values as a ControlList. The control identifiers are defined by + * the V4L2 specification (V4L2_CID_*). + * + * If any control in \a ids is not supported by the device, is disabled (i.e. + * has the V4L2_CTRL_FLAG_DISABLED flag set), or if any other error occurs + * during validation of the requested controls, no control is read and this + * function returns an empty control list. + * + * \sa V4L2Device::getControls() + * + * \return The control values in a ControlList on success, or an empty list on + * error + */ +ControlList CameraSensor::getControls(const std::vector &ids) +{ + return subdev_->getControls(ids); +} + +/** + * \brief Write V4L2 controls to the sensor + * \param[in] ctrls The list of controls to write + * + * This function writes the value of all controls contained in \a ctrls, and + * stores the values actually applied to the device in the corresponding \a + * ctrls entry. The control identifiers are defined by the V4L2 specification + * (V4L2_CID_*). + * + * If any control in \a ctrls is not supported by the device, is disabled (i.e. + * has the V4L2_CTRL_FLAG_DISABLED flag set), is read-only, or if any other + * error occurs during validation of the requested controls, no control is + * written and this function returns -EINVAL. + * + * If an error occurs while writing the controls, the index of the first + * control that couldn't be written is returned. All controls below that index + * are written and their values are updated in \a ctrls, while all other + * controls are not written and their values are not changed. + * + * \sa V4L2Device::setControls() + * + * \return 0 on success or an error code otherwise + * \retval -EINVAL One of the control is not supported or not accessible + * \retval i The index of the control that failed + */ +int CameraSensor::setControls(ControlList *ctrls) +{ + return subdev_->setControls(ctrls); +} + +/** + * \fn CameraSensor::testPatternModes() + * \brief Retrieve all the supported test pattern modes of the camera sensor + * The test pattern mode values correspond to the controls::TestPattern control. + * + * \return The list of test pattern modes + */ + +/** + * \brief Set the test pattern mode for the camera sensor + * \param[in] mode The test pattern mode + * + * The new \a mode is applied to the sensor if it differs from the active test + * pattern mode. Otherwise, this function is a no-op. Setting the same test + * pattern mode for every frame thus incurs no performance penalty. + */ +int CameraSensor::setTestPatternMode(controls::draft::TestPatternModeEnum mode) +{ + if (testPatternMode_ == mode) + return 0; + + if (testPatternModes_.empty()) { + LOG(CameraSensor, Error) + << "Camera sensor does not support test pattern modes."; + return -EINVAL; + } + + return applyTestPatternMode(mode); +} + +int CameraSensor::applyTestPatternMode(controls::draft::TestPatternModeEnum mode) +{ + if (testPatternModes_.empty()) + return 0; + + auto it = std::find(testPatternModes_.begin(), testPatternModes_.end(), + mode); + if (it == testPatternModes_.end()) { + LOG(CameraSensor, Error) << "Unsupported test pattern mode " + << mode; + return -EINVAL; + } + + LOG(CameraSensor, Debug) << "Apply test pattern mode " << mode; + + int32_t index = staticProps_->testPatternModes.at(mode); + ControlList ctrls{ controls() }; + ctrls.set(V4L2_CID_TEST_PATTERN, index); + + int ret = setControls(&ctrls); + if (ret) + return ret; + + testPatternMode_ = mode; + + return 0; +} + std::string CameraSensor::logPrefix() const { return "'" + entity_->name() + "'"; } -int CameraSensor::generateId() -{ - const std::string devPath = subdev_->devicePath(); - - /* Try to get ID from firmware description. */ - id_ = sysfs::firmwareNodePath(devPath); - if (!id_.empty()) - return 0; - - /* - * Virtual sensors not described in firmware - * - * Verify it's a platform device and construct ID from the device path - * and model of sensor. - */ - if (devPath.find("/sys/devices/platform/", 0) == 0) { - id_ = devPath.substr(strlen("/sys/devices/")) + " " + model(); - return 0; - } - - LOG(CameraSensor, Error) << "Can't generate sensor ID"; - return -EINVAL; -} - } /* namespace libcamera */ From patchwork Fri Mar 1 21:21:06 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 19608 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 3C30CC3260 for ; Fri, 1 Mar 2024 21:21:47 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id F061E628AC; Fri, 1 Mar 2024 22:21:46 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="Zpxlt9pV"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 84608628AC for ; Fri, 1 Mar 2024 22:21:44 +0100 (CET) Received: from pendragon.ideasonboard.com (89-27-53-110.bb.dnainternet.fi [89.27.53.110]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 0C83031B4; Fri, 1 Mar 2024 22:21:29 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1709328090; bh=W1hY9Zc0vUQdCjUpqtgVDU/eAOOlhxehhQVpLFl/zeY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Zpxlt9pVSCF4b2DgE+LSVI2QlBiUVt+wdFsx042BxuBnylK4mqtsA9H9tEEyD8ldr SzWJs2Aazk+baHoaRW28IiGe6rBIJzq+gn1Jm2Zp1yhcausAnIfgKkEyK7sTUlhw4f iEc8/yjBR5y2a4uUgKEYNwrswDp+lS8L0ssqQJ9U= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH/RFC 17/32] libcamera: camera_sensor: Test for read-only HBLANK with READ_ONLY flag Date: Fri, 1 Mar 2024 23:21:06 +0200 Message-ID: <20240301212121.9072-18-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> References: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sakari Ailus Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The CameraSensor class tests if the sensor HBLANK control is read-only by comparing the minimum and maximum values, and documents this as being a workaround for the lack of a read-only control flag in V4L2. This is incorrect, as the V4L2 API provides such a flag. Use it to replace the workaround. Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi Reviewed-by: Kieran Bingham --- src/libcamera/sensor/camera_sensor.cpp | 27 +++++++------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/src/libcamera/sensor/camera_sensor.cpp b/src/libcamera/sensor/camera_sensor.cpp index 86ad9a85371c..402025566544 100644 --- a/src/libcamera/sensor/camera_sensor.cpp +++ b/src/libcamera/sensor/camera_sensor.cpp @@ -188,28 +188,15 @@ int CameraSensor::init() * Set HBLANK to the minimum to start with a well-defined line length, * allowing IPA modules that do not modify HBLANK to use the sensor * minimum line length in their calculations. - * - * At present, there is no way of knowing if a control is read-only. - * As a workaround, assume that if the minimum and maximum values of - * the V4L2_CID_HBLANK control are the same, it implies the control - * is read-only. - * - * \todo The control API ought to have a flag to specify if a control - * is read-only which could be used below. */ - if (ctrls.infoMap()->find(V4L2_CID_HBLANK) != ctrls.infoMap()->end()) { - const ControlInfo hblank = ctrls.infoMap()->at(V4L2_CID_HBLANK); - const int32_t hblankMin = hblank.min().get(); - const int32_t hblankMax = hblank.max().get(); + const struct v4l2_query_ext_ctrl *hblankInfo = subdev_->controlInfo(V4L2_CID_HBLANK); + if (hblankInfo && !(hblankInfo->flags & V4L2_CTRL_FLAG_READ_ONLY)) { + ControlList ctrl(subdev_->controls()); - if (hblankMin != hblankMax) { - ControlList ctrl(subdev_->controls()); - - ctrl.set(V4L2_CID_HBLANK, hblankMin); - ret = subdev_->setControls(&ctrl); - if (ret) - return ret; - } + ctrl.set(V4L2_CID_HBLANK, static_cast(hblankInfo->minimum)); + ret = subdev_->setControls(&ctrl); + if (ret) + return ret; } return applyTestPatternMode(controls::draft::TestPatternModeEnum::TestPatternModeOff); From patchwork Fri Mar 1 21:21:07 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 19609 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 0C57EC32C3 for ; Fri, 1 Mar 2024 21:21:48 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C5E7562C82; Fri, 1 Mar 2024 22:21:47 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="rva6xzn5"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id E7103628AC for ; Fri, 1 Mar 2024 22:21:45 +0100 (CET) Received: from pendragon.ideasonboard.com (89-27-53-110.bb.dnainternet.fi [89.27.53.110]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 6DC55336C; Fri, 1 Mar 2024 22:21:31 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1709328091; bh=b1rUsI6b2Q36C0DLEmTRyOozqBzrEylBXjtvkWrE/LQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=rva6xzn5fDbpkKx3nGkuZkuZZabi8mfQQQ1mZhB6NoP1xy6ggQ0HqlFQnKB0KsLth U1r5uxgOIseHu0dOUUUzedeXB3ph8xuXsW9d22b+X07Z5soU9lBJHFvD+kkhUmL/xd k5S7skBeK1mGvsuJP9dy9YnD45tddC0eYoGSP0/E= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH/RFC 18/32] libcamera: camera_sensor: Expose the Bayer order Date: Fri, 1 Mar 2024 23:21:07 +0200 Message-ID: <20240301212121.9072-19-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> References: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sakari Ailus Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Pipeline handlers may need to know the Bayer order produced by the sensor when a Transform is applied (horizontal or vertical flip). This is currently implemented manually in the Raspberry Pi pipeline handler. Move the implementation to the CameraSensor class to make it usable in other pipeline handlers. Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi Reviewed-by: Daniel Scally --- include/libcamera/internal/camera_sensor.h | 4 +- .../pipeline/rpi/common/pipeline_base.cpp | 54 +++---------------- .../pipeline/rpi/common/pipeline_base.h | 6 +-- src/libcamera/sensor/camera_sensor.cpp | 37 ++++++++++++- 4 files changed, 45 insertions(+), 56 deletions(-) diff --git a/include/libcamera/internal/camera_sensor.h b/include/libcamera/internal/camera_sensor.h index 750d6d729cac..d05f48ebeebe 100644 --- a/include/libcamera/internal/camera_sensor.h +++ b/include/libcamera/internal/camera_sensor.h @@ -22,12 +22,12 @@ #include +#include "libcamera/internal/bayer_format.h" #include "libcamera/internal/formats.h" #include "libcamera/internal/v4l2_subdevice.h" namespace libcamera { -class BayerFormat; class CameraLens; class MediaEntity; class SensorConfiguration; @@ -69,6 +69,7 @@ public: const ControlList &properties() const { return properties_; } int sensorInfo(IPACameraSensorInfo *info) const; Transform computeTransform(Orientation *orientation) const; + BayerFormat::Order bayerOrder(Transform t) const; const ControlInfoMap &controls() const; ControlList getControls(const std::vector &ids); @@ -114,6 +115,7 @@ private: Rectangle activeArea_; const BayerFormat *bayerFormat_; bool supportFlips_; + bool flipsAlterBayerOrder_; Orientation mountingOrientation_; ControlList properties_; diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp index 9449c3dc458c..7e420b3f90a4 100644 --- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp @@ -235,24 +235,16 @@ CameraConfiguration::Status RPiCameraConfiguration::validate() for (auto &raw : rawStreams_) { StreamConfiguration *rawStream = raw.cfg; - /* Adjust the RAW stream to match the computed sensor format. */ - BayerFormat sensorBayer = BayerFormat::fromMbusCode(sensorFormat_.code); - /* - * Some sensors change their Bayer order when they are h-flipped - * or v-flipped, according to the transform. If this one does, we - * must advertise the transformed Bayer order in the raw stream. - * Note how we must fetch the "native" (i.e. untransformed) Bayer - * order, because the sensor may currently be flipped! + * Some sensors change their Bayer order when they are + * h-flipped or v-flipped, according to the transform. Adjust + * the RAW stream to match the computed sensor format by + * applying the sensor Bayer order resulting from the transform + * to the user request. */ - if (data_->flipsAlterBayerOrder_) { - sensorBayer.order = data_->nativeBayerOrder_; - sensorBayer = sensorBayer.transform(combinedTransform_); - } - /* Apply the sensor adjusted Bayer order to the user request. */ BayerFormat cfgBayer = BayerFormat::fromPixelFormat(rawStream->pixelFormat); - cfgBayer.order = sensorBayer.order; + cfgBayer.order = data_->sensor_->bayerOrder(combinedTransform_); if (rawStream->pixelFormat != cfgBayer.toPixelFormat()) { rawStream->pixelFormat = cfgBayer.toPixelFormat(); @@ -840,40 +832,6 @@ int PipelineHandlerBase::registerCamera(std::unique_ptr &camera */ data->properties_.set(properties::ScalerCropMaximum, Rectangle{}); - /* - * We cache two things about the sensor in relation to transforms - * (meaning horizontal and vertical flips): if they affect the Bayer - * ordering, and what the "native" Bayer order is, when no transforms - * are applied. - * - * If flips are supported verify if they affect the Bayer ordering - * and what the "native" Bayer order is, when no transforms are - * applied. - * - * We note that the sensor's cached list of supported formats is - * already in the "native" order, with any flips having been undone. - */ - const V4L2Subdevice *sensor = data->sensor_->device(); - const struct v4l2_query_ext_ctrl *hflipCtrl = sensor->controlInfo(V4L2_CID_HFLIP); - if (hflipCtrl) { - /* We assume it will support vflips too... */ - data->flipsAlterBayerOrder_ = hflipCtrl->flags & V4L2_CTRL_FLAG_MODIFY_LAYOUT; - } - - /* Look for a valid Bayer format. */ - BayerFormat bayerFormat; - for (const auto &iter : data->sensorFormats_) { - bayerFormat = BayerFormat::fromMbusCode(iter.first); - if (bayerFormat.isValid()) - break; - } - - if (!bayerFormat.isValid()) { - LOG(RPI, Error) << "No Bayer format found"; - return -EINVAL; - } - data->nativeBayerOrder_ = bayerFormat.order; - ret = platformRegister(cameraData, frontend, backend); if (ret) return ret; diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.h b/src/libcamera/pipeline/rpi/common/pipeline_base.h index 267eef1102f1..0608bbe5f0c7 100644 --- a/src/libcamera/pipeline/rpi/common/pipeline_base.h +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.h @@ -48,7 +48,7 @@ class CameraData : public Camera::Private public: CameraData(PipelineHandler *pipe) : Camera::Private(pipe), state_(State::Stopped), - flipsAlterBayerOrder_(false), dropFrameCount_(0), buffersAllocated_(false), + dropFrameCount_(0), buffersAllocated_(false), ispOutputCount_(0), ispOutputTotal_(0) { } @@ -131,10 +131,6 @@ public: std::queue requestQueue_; - /* Store the "native" Bayer order (that is, with no transforms applied). */ - bool flipsAlterBayerOrder_; - BayerFormat::Order nativeBayerOrder_; - /* For handling digital zoom. */ IPACameraSensorInfo sensorInfo_; Rectangle ispCrop_; /* crop in ISP (camera mode) pixels */ diff --git a/src/libcamera/sensor/camera_sensor.cpp b/src/libcamera/sensor/camera_sensor.cpp index 402025566544..5c4f35324055 100644 --- a/src/libcamera/sensor/camera_sensor.cpp +++ b/src/libcamera/sensor/camera_sensor.cpp @@ -58,7 +58,7 @@ LOG_DEFINE_CATEGORY(CameraSensor) CameraSensor::CameraSensor(const MediaEntity *entity) : entity_(entity), pad_(UINT_MAX), staticProps_(nullptr), bayerFormat_(nullptr), supportFlips_(false), - properties_(properties::properties) + flipsAlterBayerOrder_(false), properties_(properties::properties) { } @@ -271,9 +271,14 @@ int CameraSensor::validateSensorDriver() const struct v4l2_query_ext_ctrl *hflipInfo = subdev_->controlInfo(V4L2_CID_HFLIP); const struct v4l2_query_ext_ctrl *vflipInfo = subdev_->controlInfo(V4L2_CID_VFLIP); if (hflipInfo && !(hflipInfo->flags & V4L2_CTRL_FLAG_READ_ONLY) && - vflipInfo && !(vflipInfo->flags & V4L2_CTRL_FLAG_READ_ONLY)) + vflipInfo && !(vflipInfo->flags & V4L2_CTRL_FLAG_READ_ONLY)) { supportFlips_ = true; + if (hflipInfo->flags & V4L2_CTRL_FLAG_MODIFY_LAYOUT || + vflipInfo->flags & V4L2_CTRL_FLAG_MODIFY_LAYOUT) + flipsAlterBayerOrder_ = true; + } + if (!supportFlips_) LOG(CameraSensor, Debug) << "Camera sensor does not support horizontal/vertical flip"; @@ -1041,6 +1046,34 @@ Transform CameraSensor::computeTransform(Orientation *orientation) const return transform; } +/** + * \brief Compute the Bayer order that results from the given Transform + * \param[in] t The Transform to apply to the sensor + * + * Some sensors change their Bayer order when they are h-flipped or v-flipped. + * This function computes and returns the Bayer order that would result from the + * given transform applied to the sensor. + * + * This function is valid only when the sensor produces raw Bayer formats. + * + * \return The Bayer order produced by the sensor when the Transform is applied + */ +BayerFormat::Order CameraSensor::bayerOrder(Transform t) const +{ + /* Return a defined by meaningless value for non-Bayer sensors. */ + if (!bayerFormat_) + return BayerFormat::Order::BGGR; + + if (!flipsAlterBayerOrder_) + return bayerFormat_->order; + + /* + * Apply the transform to the native (i.e. untransformed) Bayer order, + * using the rest of the Bayer format supplied by the caller. + */ + return bayerFormat_->transform(t).order; +} + /** * \brief Retrieve the supported V4L2 controls and their information * From patchwork Fri Mar 1 21:21:08 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 19610 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 83811BD160 for ; Fri, 1 Mar 2024 21:21:49 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 44CB762C87; Fri, 1 Mar 2024 22:21:49 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="NH99IXGD"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6C23C62964 for ; Fri, 1 Mar 2024 22:21:47 +0100 (CET) Received: from pendragon.ideasonboard.com (89-27-53-110.bb.dnainternet.fi [89.27.53.110]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id CC13FD04; Fri, 1 Mar 2024 22:21:32 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1709328093; bh=GCqgbrGku0bAvnN7Dr08jbBMDRPurnEkme7R64HAgyQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=NH99IXGD+e084Y9r6IDk7g1DPuHmzIyGPYoL5uF5QQ1Aq/f58bCr3tP21H6Slbv1E koC9HMoFQcdiu/4MokX3ZLCFlhaYQmH61s2rOp2ugax+0fBTCBGr0XaWifpemDRWPW X6dAPt3vjvFFiTSoIqqyqH1aklQ0G67S2mjKfhdY= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH/RFC 19/32] libcamera: camera_sensor: Introduce CameraSensorFactory Date: Fri, 1 Mar 2024 23:21:08 +0200 Message-ID: <20240301212121.9072-20-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> References: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sakari Ailus Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" From: Jacopo Mondi Introduce a factory to create CameraSensor derived classes instances by inspecting the sensor media entity name and provide a convenience macro to register specialized sensor handlers. Signed-off-by: Jacopo Mondi Signed-off-by: Laurent Pinchart Reviewed-by: Stefan Klug --- include/libcamera/internal/camera_sensor.h | 48 +++++- src/libcamera/pipeline/imx8-isi/imx8-isi.cpp | 9 +- src/libcamera/pipeline/ipu3/cio2.cpp | 7 +- src/libcamera/pipeline/rkisp1/rkisp1.cpp | 7 +- .../pipeline/rpi/common/pipeline_base.cpp | 5 +- src/libcamera/pipeline/simple/simple.cpp | 9 +- src/libcamera/pipeline/vimc/vimc.cpp | 7 +- src/libcamera/sensor/camera_sensor.cpp | 162 ++++++++++++++++++ test/camera-sensor.cpp | 7 +- .../v4l2_videodevice_test.cpp | 5 +- test/v4l2_videodevice/v4l2_videodevice_test.h | 2 +- 11 files changed, 231 insertions(+), 37 deletions(-) diff --git a/include/libcamera/internal/camera_sensor.h b/include/libcamera/internal/camera_sensor.h index d05f48ebeebe..577af779cd6e 100644 --- a/include/libcamera/internal/camera_sensor.h +++ b/include/libcamera/internal/camera_sensor.h @@ -39,7 +39,6 @@ enum class Orientation; class CameraSensor : protected Loggable { public: - explicit CameraSensor(const MediaEntity *entity); ~CameraSensor(); int init(); @@ -82,6 +81,7 @@ public: int setTestPatternMode(controls::draft::TestPatternModeEnum mode); protected: + explicit CameraSensor(const MediaEntity *entity); std::string logPrefix() const override; private: @@ -123,4 +123,50 @@ private: std::unique_ptr focusLens_; }; +class CameraSensorFactoryBase +{ +public: + CameraSensorFactoryBase(); + virtual ~CameraSensorFactoryBase() = default; + + static std::unique_ptr create(MediaEntity *entity); + +private: + LIBCAMERA_DISABLE_COPY_AND_MOVE(CameraSensorFactoryBase) + + static std::vector &factories(); + + static void registerFactory(CameraSensorFactoryBase *factory); + + virtual bool match(const MediaEntity *entity) const = 0; + + virtual std::unique_ptr + createInstance(MediaEntity *entity) const = 0; +}; + +template +class CameraSensorFactory final : public CameraSensorFactoryBase +{ +public: + CameraSensorFactory() + : CameraSensorFactoryBase() + { + } + +private: + bool match(const MediaEntity *entity) const override + { + return _CameraSensor::match(entity); + } + + std::unique_ptr + createInstance(MediaEntity *entity) const override + { + return _CameraSensor::create(entity); + } +}; + +#define REGISTER_CAMERA_SENSOR(sensor) \ + static CameraSensorFactory global_##sensor##Factory{}; + } /* namespace libcamera */ diff --git a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp index a3782aea2ba9..a00567c6873c 100644 --- a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp +++ b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp @@ -157,11 +157,10 @@ PipelineHandlerISI *ISICameraData::pipe() /* Open and initialize pipe components. */ int ISICameraData::init() { - int ret = sensor_->init(); - if (ret) - return ret; + if (!sensor_) + return -ENODEV; - ret = csis_->open(); + int ret = csis_->open(); if (ret) return ret; @@ -1063,7 +1062,7 @@ bool PipelineHandlerISI::match(DeviceEnumerator *enumerator) std::unique_ptr data = std::make_unique(this); - data->sensor_ = std::make_unique(sensor); + data->sensor_ = CameraSensorFactoryBase::create(sensor); data->csis_ = std::make_unique(csi); data->xbarSink_ = sink; diff --git a/src/libcamera/pipeline/ipu3/cio2.cpp b/src/libcamera/pipeline/ipu3/cio2.cpp index 43c816baf6ef..e09583ea418f 100644 --- a/src/libcamera/pipeline/ipu3/cio2.cpp +++ b/src/libcamera/pipeline/ipu3/cio2.cpp @@ -134,10 +134,9 @@ int CIO2Device::init(const MediaDevice *media, unsigned int index) MediaLink *link = links[0]; MediaEntity *sensorEntity = link->source()->entity(); - sensor_ = std::make_unique(sensorEntity); - ret = sensor_->init(); - if (ret) - return ret; + sensor_ = CameraSensorFactoryBase::create(sensorEntity); + if (!sensor_) + return -ENODEV; ret = link->setEnabled(true); if (ret) diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp index abb21968413a..1a3e7938fa91 100644 --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp @@ -1109,10 +1109,9 @@ int PipelineHandlerRkISP1::createCamera(MediaEntity *sensor) std::make_unique(this, &mainPath_, hasSelfPath_ ? &selfPath_ : nullptr); - data->sensor_ = std::make_unique(sensor); - ret = data->sensor_->init(); - if (ret) - return ret; + data->sensor_ = CameraSensorFactoryBase::create(sensor); + if (!data->sensor_) + return -ENODEV; /* Initialize the camera properties. */ data->properties_ = data->sensor_->properties(); diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp index 7e420b3f90a4..d662c8f12145 100644 --- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp @@ -772,13 +772,10 @@ int PipelineHandlerBase::registerCamera(std::unique_ptr &camera CameraData *data = cameraData.get(); int ret; - data->sensor_ = std::make_unique(sensorEntity); + data->sensor_ = CameraSensorFactoryBase::create(sensorEntity); if (!data->sensor_) return -EINVAL; - if (data->sensor_->init()) - return -EINVAL; - /* Populate the map of sensor supported formats and sizes. */ for (auto const mbusCode : data->sensor_->mbusCodes()) data->sensorFormats_.emplace(mbusCode, diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp index 01f2a97798ba..0bd021388c8f 100644 --- a/src/libcamera/pipeline/simple/simple.cpp +++ b/src/libcamera/pipeline/simple/simple.cpp @@ -371,8 +371,6 @@ SimpleCameraData::SimpleCameraData(SimplePipelineHandler *pipe, MediaEntity *sensor) : Camera::Private(pipe), streams_(numStreams) { - int ret; - /* * Find the shortest path from the camera sensor to a video capture * device using the breadth-first search algorithm. This heuristic will @@ -463,12 +461,9 @@ SimpleCameraData::SimpleCameraData(SimplePipelineHandler *pipe, } /* Finally also remember the sensor. */ - sensor_ = std::make_unique(sensor); - ret = sensor_->init(); - if (ret) { - sensor_.reset(); + sensor_ = CameraSensorFactoryBase::create(sensor); + if (!sensor_) return; - } LOG(SimplePipeline, Debug) << "Found pipeline: " diff --git a/src/libcamera/pipeline/vimc/vimc.cpp b/src/libcamera/pipeline/vimc/vimc.cpp index 5e66ee1d26c1..ae0ca21907ec 100644 --- a/src/libcamera/pipeline/vimc/vimc.cpp +++ b/src/libcamera/pipeline/vimc/vimc.cpp @@ -510,10 +510,9 @@ int VimcCameraData::init() return ret; /* Create and open the camera sensor, debayer, scaler and video device. */ - sensor_ = std::make_unique(media_->getEntityByName("Sensor B")); - ret = sensor_->init(); - if (ret) - return ret; + sensor_ = CameraSensorFactoryBase::create(media_->getEntityByName("Sensor B")); + if (!sensor_) + return -ENODEV; debayer_ = V4L2Subdevice::fromEntityName(media_, "Debayer B"); if (debayer_->open()) diff --git a/src/libcamera/sensor/camera_sensor.cpp b/src/libcamera/sensor/camera_sensor.cpp index 5c4f35324055..a35683eb4b58 100644 --- a/src/libcamera/sensor/camera_sensor.cpp +++ b/src/libcamera/sensor/camera_sensor.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -1204,4 +1205,165 @@ std::string CameraSensor::logPrefix() const return "'" + entity_->name() + "'"; } +namespace { + +/* Transitory default camera sensor implementation */ +class CameraSensorDefault : public CameraSensor +{ +public: + CameraSensorDefault(MediaEntity *entity) + : CameraSensor(entity) + { + } + + static bool match([[maybe_unused]] const MediaEntity *entity) + { + return true; + } + + static std::unique_ptr create(MediaEntity *entity) + { + std::unique_ptr sensor = + std::make_unique(entity); + + if (sensor->init()) + return nullptr; + + return sensor; + } +}; + +REGISTER_CAMERA_SENSOR(CameraSensorDefault) + +}; /* namespace */ + +/** + * \class CameraSensorFactoryBase + * \brief Base class for camera sensor factories + * + * The CameraSensorFactoryBase class is the base of all specializations of + * the CameraSensorFactory class template. It implements the factory + * registration, maintains a registry of factories, and provides access to the + * registered factories. + */ + +/** + * \brief Construct a camera sensor factory base + * + * Creating an instance of the factory base registers it with the global list of + * factories, accessible through the factories() function. + */ +CameraSensorFactoryBase::CameraSensorFactoryBase() +{ + registerFactory(this); +} + +/** + * \brief Create an instance of the CameraSensor corresponding to a media entity + * \param[in] entity The media entity on the source end of the sensor + * + * \return A unique pointer to a new instance of the CameraSensor subclass + * matching the entity, or a null pointer if no such factory exists + */ +std::unique_ptr CameraSensorFactoryBase::create(MediaEntity *entity) +{ + const std::vector &factories = + CameraSensorFactoryBase::factories(); + + for (const CameraSensorFactoryBase *factory : factories) { + if (!factory->match(entity)) + continue; + + std::unique_ptr sensor = factory->createInstance(entity); + if (!sensor) { + LOG(CameraSensor, Error) + << "Failed to create sensor for '" + << entity->name(); + return nullptr; + } + + return sensor; + } + + return nullptr; +} + +/** + * \brief Retrieve the list of all camera sensor factories + * \return The list of camera sensor factories + */ +std::vector &CameraSensorFactoryBase::factories() +{ + /* + * The static factories map is defined inside the function to ensure + * it gets initialized on first use, without any dependency on link + * order. + */ + static std::vector factories; + return factories; +} + +/** + * \brief Add a camera sensor class to the registry + * \param[in] factory Factory to use to construct the camera sensor + */ +void CameraSensorFactoryBase::registerFactory(CameraSensorFactoryBase *factory) +{ + std::vector &factories = + CameraSensorFactoryBase::factories(); + + factories.push_back(factory); +} + +/** + * \class CameraSensorFactory + * \brief Registration of CameraSensorFactory classes and creation of instances + * \tparam _CameraSensor The camera sensor class type for this factory + * + * To facilitate discovery and instantiation of CameraSensor classes, the + * CameraSensorFactory class implements auto-registration of camera sensors. + * Each CameraSensor subclass shall register itself using the + * REGISTER_CAMERA_SENSOR() macro, which will create a corresponding instance + * of a CameraSensorFactory subclass and register it with the static list of + * factories. + */ + +/** + * \fn CameraSensorFactory::CameraSensorFactory() + * \brief Construct a camera sensor factory + * + * Creating an instance of the factory registers it with the global list of + * factories, accessible through the CameraSensorFactoryBase::factories() + * function. + */ + +/** + * \fn CameraSensorFactory::createInstance() const + * \brief Create an instance of the CameraSensor corresponding to the factory + * + * \return A unique pointer to a newly constructed instance of the CameraSensor + * subclass corresponding to the factory + */ + +/** + * \def REGISTER_CAMERA_SENSOR(sensor) + * \brief Register a camera sensor type to the sensor factory + * \param[in] sensor Class name of the CameraSensor derived class to register + * + * Register a CameraSensor subclass with the factory and make it available to + * try and match sensors. The subclass needs to implement two static functions: + * + * \code{.cpp} + * static bool match(const MediaEntity *entity); + * static std::unique_ptr create(MediaEntity *entity); + * \endcode + * + * The match() function tests if the sensor class supports the camera sensor + * identified by a MediaEntity. + * + * The create() function creates a new instance of the sensor class. It may + * return a null pointer if initialization of the instance fails. It will only + * be called if the match() function has returned true for the given entity. + */ + } /* namespace libcamera */ diff --git a/test/camera-sensor.cpp b/test/camera-sensor.cpp index 9503d7753fb9..acd3a1241ae1 100644 --- a/test/camera-sensor.cpp +++ b/test/camera-sensor.cpp @@ -52,8 +52,8 @@ protected: return TestFail; } - sensor_ = new CameraSensor(entity); - if (sensor_->init() < 0) { + sensor_ = CameraSensorFactoryBase::create(entity); + if (!sensor_) { cerr << "Unable to initialise camera sensor" << endl; return TestFail; } @@ -118,13 +118,12 @@ protected: void cleanup() { - delete sensor_; } private: std::unique_ptr enumerator_; std::shared_ptr media_; - CameraSensor *sensor_; + std::unique_ptr sensor_; CameraLens *lens_; }; diff --git a/test/v4l2_videodevice/v4l2_videodevice_test.cpp b/test/v4l2_videodevice/v4l2_videodevice_test.cpp index 1113cf5bf8cf..9fbd24cc91ea 100644 --- a/test/v4l2_videodevice/v4l2_videodevice_test.cpp +++ b/test/v4l2_videodevice/v4l2_videodevice_test.cpp @@ -64,8 +64,8 @@ int V4L2VideoDeviceTest::init() format.size.height = 480; if (driver_ == "vimc") { - sensor_ = new CameraSensor(media_->getEntityByName("Sensor A")); - if (sensor_->init()) + sensor_ = CameraSensorFactoryBase::create(media_->getEntityByName("Sensor A")); + if (!sensor_) return TestFail; debayer_ = new V4L2Subdevice(media_->getEntityByName("Debayer A")); @@ -98,6 +98,5 @@ void V4L2VideoDeviceTest::cleanup() capture_->close(); delete debayer_; - delete sensor_; delete capture_; } diff --git a/test/v4l2_videodevice/v4l2_videodevice_test.h b/test/v4l2_videodevice/v4l2_videodevice_test.h index d2de1a6de29f..f06db72a9df5 100644 --- a/test/v4l2_videodevice/v4l2_videodevice_test.h +++ b/test/v4l2_videodevice/v4l2_videodevice_test.h @@ -36,7 +36,7 @@ protected: std::string entity_; std::unique_ptr enumerator_; std::shared_ptr media_; - libcamera::CameraSensor *sensor_; + std::unique_ptr sensor_; libcamera::V4L2Subdevice *debayer_; libcamera::V4L2VideoDevice *capture_; std::vector> buffers_; From patchwork Fri Mar 1 21:21:09 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 19611 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 20C62BD160 for ; Fri, 1 Mar 2024 21:21:52 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C113D628AC; Fri, 1 Mar 2024 22:21:51 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="CjpH5qQA"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 46D1762C8C for ; Fri, 1 Mar 2024 22:21:49 +0100 (CET) Received: from pendragon.ideasonboard.com (89-27-53-110.bb.dnainternet.fi [89.27.53.110]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 9C352A9A; Fri, 1 Mar 2024 22:21:34 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1709328095; bh=m8wSPt7m4jBTxlqW2RanvHjAmXwbN7EBuYlfcLLDCLM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=CjpH5qQAWvuerGf9FrfrU27sNU2afOYJogdUBVHBAEs2BAgOofYAeqq+3uqVJReC/ cu53DUpV27k7KVzubAKTW1pqK+aPY4UCjd+Lc+Wi3ccrfWJ9XlXsMIwEPcFhbXvFNB /u2oI1Ji8iKFdHSwSdkDDHBqKGwq0mwALojTGL0A= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH/RFC 20/32] libcamera: camera_sensor: Create abstract base class Date: Fri, 1 Mar 2024 23:21:09 +0200 Message-ID: <20240301212121.9072-21-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> References: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sakari Ailus Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" With a camera sensor factory in place, the next step is to create an abstract base class that all camera sensors implement, providing a uniform API to pipeline handler. Turn all public functions of the CameraSensor class into pure virtual functions, and move the implementation to the CameraSensorLegacy class. Part of the code is likely worth keeping as common helpers in a base class. However, to follow the principle of not designing helpers with a single user, this commit moves the whole implementation. Common helpers will be introduced later, along with other CameraSensor subclasses. Signed-off-by: Laurent Pinchart Reviewed-by: Stefan Klug --- Documentation/Doxyfile.in | 1 + include/libcamera/internal/camera_sensor.h | 126 +- src/libcamera/sensor/camera_sensor.cpp | 981 +--------------- src/libcamera/sensor/camera_sensor_legacy.cpp | 1015 +++++++++++++++++ src/libcamera/sensor/meson.build | 1 + 5 files changed, 1090 insertions(+), 1034 deletions(-) create mode 100644 src/libcamera/sensor/camera_sensor_legacy.cpp diff --git a/Documentation/Doxyfile.in b/Documentation/Doxyfile.in index a86ea6c1ec95..75326c1964e9 100644 --- a/Documentation/Doxyfile.in +++ b/Documentation/Doxyfile.in @@ -42,6 +42,7 @@ EXCLUDE = @TOP_SRCDIR@/include/libcamera/base/span.h \ @TOP_SRCDIR@/src/libcamera/device_enumerator_udev.cpp \ @TOP_SRCDIR@/src/libcamera/ipc_pipe_unixsocket.cpp \ @TOP_SRCDIR@/src/libcamera/pipeline/ \ + @TOP_SRCDIR@/src/libcamera/sensor/camera_sensor_legacy.cpp \ @TOP_SRCDIR@/src/libcamera/tracepoints.cpp \ @TOP_BUILDDIR@/include/libcamera/internal/tracepoints.h \ @TOP_BUILDDIR@/src/libcamera/proxy/ diff --git a/include/libcamera/internal/camera_sensor.h b/include/libcamera/internal/camera_sensor.h index 577af779cd6e..d37e66773195 100644 --- a/include/libcamera/internal/camera_sensor.h +++ b/include/libcamera/internal/camera_sensor.h @@ -9,10 +9,10 @@ #include #include +#include #include #include -#include #include #include @@ -20,8 +20,6 @@ #include #include -#include - #include "libcamera/internal/bayer_format.h" #include "libcamera/internal/formats.h" #include "libcamera/internal/v4l2_subdevice.h" @@ -32,95 +30,50 @@ class CameraLens; class MediaEntity; class SensorConfiguration; -struct CameraSensorProperties; - enum class Orientation; -class CameraSensor : protected Loggable +struct IPACameraSensorInfo; + +class CameraSensor { public: - ~CameraSensor(); + virtual ~CameraSensor(); - int init(); + virtual const std::string &model() const = 0; + virtual const std::string &id() const = 0; - const std::string &model() const { return model_; } - const std::string &id() const { return id_; } + virtual const MediaEntity *entity() const = 0; + virtual V4L2Subdevice *device() = 0; - const MediaEntity *entity() const { return entity_; } - V4L2Subdevice *device() { return subdev_.get(); } + virtual CameraLens *focusLens() = 0; - CameraLens *focusLens() { return focusLens_.get(); } + virtual const std::vector &mbusCodes() const = 0; + virtual std::vector sizes(unsigned int mbusCode) const = 0; + virtual Size resolution() const = 0; - const std::vector &mbusCodes() const { return mbusCodes_; } - std::vector sizes(unsigned int mbusCode) const; - Size resolution() const; + virtual V4L2SubdeviceFormat + getFormat(const std::vector &mbusCodes, + const Size &size) const = 0; + virtual int setFormat(V4L2SubdeviceFormat *format, + Transform transform = Transform::Identity) = 0; + virtual int tryFormat(V4L2SubdeviceFormat *format) const = 0; - V4L2SubdeviceFormat getFormat(const std::vector &mbusCodes, - const Size &size) const; - int setFormat(V4L2SubdeviceFormat *format, - Transform transform = Transform::Identity); - int tryFormat(V4L2SubdeviceFormat *format) const; + virtual int applyConfiguration(const SensorConfiguration &config, + Transform transform = Transform::Identity, + V4L2SubdeviceFormat *sensorFormat = nullptr) = 0; - int applyConfiguration(const SensorConfiguration &config, - Transform transform = Transform::Identity, - V4L2SubdeviceFormat *sensorFormat = nullptr); + virtual const ControlList &properties() const = 0; + virtual int sensorInfo(IPACameraSensorInfo *info) const = 0; + virtual Transform computeTransform(Orientation *orientation) const = 0; + virtual BayerFormat::Order bayerOrder(Transform t) const = 0; - const ControlList &properties() const { return properties_; } - int sensorInfo(IPACameraSensorInfo *info) const; - Transform computeTransform(Orientation *orientation) const; - BayerFormat::Order bayerOrder(Transform t) const; + virtual const ControlInfoMap &controls() const = 0; + virtual ControlList getControls(const std::vector &ids) = 0; + virtual int setControls(ControlList *ctrls) = 0; - const ControlInfoMap &controls() const; - ControlList getControls(const std::vector &ids); - int setControls(ControlList *ctrls); - - const std::vector &testPatternModes() const - { - return testPatternModes_; - } - int setTestPatternMode(controls::draft::TestPatternModeEnum mode); - -protected: - explicit CameraSensor(const MediaEntity *entity); - std::string logPrefix() const override; - -private: - LIBCAMERA_DISABLE_COPY(CameraSensor) - - int generateId(); - int validateSensorDriver(); - void initVimcDefaultProperties(); - void initStaticProperties(); - void initTestPatternModes(); - int initProperties(); - int discoverAncillaryDevices(); - int applyTestPatternMode(controls::draft::TestPatternModeEnum mode); - - const MediaEntity *entity_; - std::unique_ptr subdev_; - unsigned int pad_; - - const CameraSensorProperties *staticProps_; - - std::string model_; - std::string id_; - - V4L2Subdevice::Formats formats_; - std::vector mbusCodes_; - std::vector sizes_; - std::vector testPatternModes_; - controls::draft::TestPatternModeEnum testPatternMode_; - - Size pixelArraySize_; - Rectangle activeArea_; - const BayerFormat *bayerFormat_; - bool supportFlips_; - bool flipsAlterBayerOrder_; - Orientation mountingOrientation_; - - ControlList properties_; - - std::unique_ptr focusLens_; + virtual const std::vector & + testPatternModes() const = 0; + virtual int setTestPatternMode(controls::draft::TestPatternModeEnum mode) = 0; }; class CameraSensorFactoryBase @@ -138,10 +91,8 @@ private: static void registerFactory(CameraSensorFactoryBase *factory); - virtual bool match(const MediaEntity *entity) const = 0; - - virtual std::unique_ptr - createInstance(MediaEntity *entity) const = 0; + virtual std::variant, int> + match(MediaEntity *entity) const = 0; }; template @@ -154,16 +105,11 @@ public: } private: - bool match(const MediaEntity *entity) const override + std::variant, int> + match(MediaEntity *entity) const override { return _CameraSensor::match(entity); } - - std::unique_ptr - createInstance(MediaEntity *entity) const override - { - return _CameraSensor::create(entity); - } }; #define REGISTER_CAMERA_SENSOR(sensor) \ diff --git a/src/libcamera/sensor/camera_sensor.cpp b/src/libcamera/sensor/camera_sensor.cpp index a35683eb4b58..7abbe2c76596 100644 --- a/src/libcamera/sensor/camera_sensor.cpp +++ b/src/libcamera/sensor/camera_sensor.cpp @@ -6,27 +6,13 @@ */ #include "libcamera/internal/camera_sensor.h" -#include "libcamera/internal/media_device.h" -#include -#include -#include -#include -#include -#include -#include +#include +#include -#include -#include -#include +#include -#include - -#include "libcamera/internal/bayer_format.h" -#include "libcamera/internal/camera_lens.h" -#include "libcamera/internal/camera_sensor_properties.h" -#include "libcamera/internal/formats.h" -#include "libcamera/internal/sysfs.h" +#include "libcamera/internal/media_object.h" /** * \file camera_sensor.h @@ -39,537 +25,16 @@ LOG_DEFINE_CATEGORY(CameraSensor) /** * \class CameraSensor - * \brief A camera sensor based on V4L2 subdevices + * \brief A abstract camera sensor * * The CameraSensor class eases handling of sensors for pipeline handlers by - * hiding the details of the V4L2 subdevice kernel API and caching sensor - * information. - * - * The implementation is currently limited to sensors that expose a single V4L2 - * subdevice with a single pad. It will be extended to support more complex - * devices as the needs arise. + * hiding the details of the kernel API and caching sensor information. */ -/** - * \brief Construct a CameraSensor - * \param[in] entity The media entity backing the camera sensor - * - * Once constructed the instance must be initialized with init(). - */ -CameraSensor::CameraSensor(const MediaEntity *entity) - : entity_(entity), pad_(UINT_MAX), staticProps_(nullptr), - bayerFormat_(nullptr), supportFlips_(false), - flipsAlterBayerOrder_(false), properties_(properties::properties) -{ -} - /** * \brief Destroy a CameraSensor */ -CameraSensor::~CameraSensor() -{ -} - -/** - * \brief Initialize the camera sensor instance - * - * This function performs the initialisation steps of the CameraSensor that may - * fail. It shall be called once and only once after constructing the instance. - * - * \return 0 on success or a negative error code otherwise - */ -int CameraSensor::init() -{ - for (const MediaPad *pad : entity_->pads()) { - if (pad->flags() & MEDIA_PAD_FL_SOURCE) { - pad_ = pad->index(); - break; - } - } - - if (pad_ == UINT_MAX) { - LOG(CameraSensor, Error) - << "Sensors with more than one pad are not supported"; - return -EINVAL; - } - - switch (entity_->function()) { - case MEDIA_ENT_F_CAM_SENSOR: - case MEDIA_ENT_F_PROC_VIDEO_ISP: - break; - - default: - LOG(CameraSensor, Error) - << "Invalid sensor function " - << utils::hex(entity_->function()); - return -EINVAL; - } - - /* Create and open the subdev. */ - subdev_ = std::make_unique(entity_); - int ret = subdev_->open(); - if (ret < 0) - return ret; - - /* - * Clear any flips to be sure we get the "native" Bayer order. This is - * harmless for sensors where the flips don't affect the Bayer order. - */ - ControlList ctrls(subdev_->controls()); - if (subdev_->controls().find(V4L2_CID_HFLIP) != subdev_->controls().end()) - ctrls.set(V4L2_CID_HFLIP, 0); - if (subdev_->controls().find(V4L2_CID_VFLIP) != subdev_->controls().end()) - ctrls.set(V4L2_CID_VFLIP, 0); - subdev_->setControls(&ctrls); - - /* Enumerate, sort and cache media bus codes and sizes. */ - formats_ = subdev_->formats(pad_); - if (formats_.empty()) { - LOG(CameraSensor, Error) << "No image format found"; - return -EINVAL; - } - - mbusCodes_ = utils::map_keys(formats_); - std::sort(mbusCodes_.begin(), mbusCodes_.end()); - - for (const auto &format : formats_) { - const std::vector &ranges = format.second; - std::transform(ranges.begin(), ranges.end(), std::back_inserter(sizes_), - [](const SizeRange &range) { return range.max; }); - } - - std::sort(sizes_.begin(), sizes_.end()); - - /* Remove duplicates. */ - auto last = std::unique(sizes_.begin(), sizes_.end()); - sizes_.erase(last, sizes_.end()); - - /* - * VIMC is a bit special, as it does not yet support all the mandatory - * requirements regular sensors have to respect. - * - * Do not validate the driver if it's VIMC and initialize the sensor - * properties with static information. - * - * \todo Remove the special case once the VIMC driver has been - * updated in all test platforms. - */ - if (entity_->device()->driver() == "vimc") { - initVimcDefaultProperties(); - - ret = initProperties(); - if (ret) - return ret; - - return discoverAncillaryDevices(); - } - - /* Get the color filter array pattern (only for RAW sensors). */ - for (unsigned int mbusCode : mbusCodes_) { - const BayerFormat &bayerFormat = BayerFormat::fromMbusCode(mbusCode); - if (bayerFormat.isValid()) { - bayerFormat_ = &bayerFormat; - break; - } - } - - ret = validateSensorDriver(); - if (ret) - return ret; - - ret = initProperties(); - if (ret) - return ret; - - ret = discoverAncillaryDevices(); - if (ret) - return ret; - - /* - * Set HBLANK to the minimum to start with a well-defined line length, - * allowing IPA modules that do not modify HBLANK to use the sensor - * minimum line length in their calculations. - */ - const struct v4l2_query_ext_ctrl *hblankInfo = subdev_->controlInfo(V4L2_CID_HBLANK); - if (hblankInfo && !(hblankInfo->flags & V4L2_CTRL_FLAG_READ_ONLY)) { - ControlList ctrl(subdev_->controls()); - - ctrl.set(V4L2_CID_HBLANK, static_cast(hblankInfo->minimum)); - ret = subdev_->setControls(&ctrl); - if (ret) - return ret; - } - - return applyTestPatternMode(controls::draft::TestPatternModeEnum::TestPatternModeOff); -} - -int CameraSensor::generateId() -{ - const std::string devPath = subdev_->devicePath(); - - /* Try to get ID from firmware description. */ - id_ = sysfs::firmwareNodePath(devPath); - if (!id_.empty()) - return 0; - - /* - * Virtual sensors not described in firmware - * - * Verify it's a platform device and construct ID from the device path - * and model of sensor. - */ - if (devPath.find("/sys/devices/platform/", 0) == 0) { - id_ = devPath.substr(strlen("/sys/devices/")) + " " + model(); - return 0; - } - - LOG(CameraSensor, Error) << "Can't generate sensor ID"; - return -EINVAL; -} - -int CameraSensor::validateSensorDriver() -{ - int err = 0; - - /* - * Optional controls are used to register optional sensor properties. If - * not present, some values will be defaulted. - */ - static constexpr uint32_t optionalControls[] = { - V4L2_CID_CAMERA_SENSOR_ROTATION, - }; - - const ControlIdMap &controls = subdev_->controls().idmap(); - for (uint32_t ctrl : optionalControls) { - if (!controls.count(ctrl)) - LOG(CameraSensor, Debug) - << "Optional V4L2 control " << utils::hex(ctrl) - << " not supported"; - } - - /* - * Recommended controls are similar to optional controls, but will - * become mandatory in the near future. Be loud if they're missing. - */ - static constexpr uint32_t recommendedControls[] = { - V4L2_CID_CAMERA_ORIENTATION, - }; - - for (uint32_t ctrl : recommendedControls) { - if (!controls.count(ctrl)) { - LOG(CameraSensor, Warning) - << "Recommended V4L2 control " << utils::hex(ctrl) - << " not supported"; - err = -EINVAL; - } - } - - /* - * Verify if sensor supports horizontal/vertical flips - * - * \todo Handle horizontal and vertical flips independently. - */ - const struct v4l2_query_ext_ctrl *hflipInfo = subdev_->controlInfo(V4L2_CID_HFLIP); - const struct v4l2_query_ext_ctrl *vflipInfo = subdev_->controlInfo(V4L2_CID_VFLIP); - if (hflipInfo && !(hflipInfo->flags & V4L2_CTRL_FLAG_READ_ONLY) && - vflipInfo && !(vflipInfo->flags & V4L2_CTRL_FLAG_READ_ONLY)) { - supportFlips_ = true; - - if (hflipInfo->flags & V4L2_CTRL_FLAG_MODIFY_LAYOUT || - vflipInfo->flags & V4L2_CTRL_FLAG_MODIFY_LAYOUT) - flipsAlterBayerOrder_ = true; - } - - if (!supportFlips_) - LOG(CameraSensor, Debug) - << "Camera sensor does not support horizontal/vertical flip"; - - /* - * Make sure the required selection targets are supported. - * - * Failures in reading any of the targets are not deemed to be fatal, - * but some properties and features, like constructing a - * IPACameraSensorInfo for the IPA module, won't be supported. - * - * \todo Make support for selection targets mandatory as soon as all - * test platforms have been updated. - */ - Rectangle rect; - int ret = subdev_->getSelection(pad_, V4L2_SEL_TGT_CROP_BOUNDS, &rect); - if (ret) { - /* - * Default the pixel array size to the largest size supported - * by the sensor. The sizes_ vector is sorted in ascending - * order, the largest size is thus the last element. - */ - pixelArraySize_ = sizes_.back(); - - LOG(CameraSensor, Warning) - << "The PixelArraySize property has been defaulted to " - << pixelArraySize_; - err = -EINVAL; - } else { - pixelArraySize_ = rect.size(); - } - - ret = subdev_->getSelection(pad_, V4L2_SEL_TGT_CROP_DEFAULT, &activeArea_); - if (ret) { - activeArea_ = Rectangle(pixelArraySize_); - LOG(CameraSensor, Warning) - << "The PixelArrayActiveAreas property has been defaulted to " - << activeArea_; - err = -EINVAL; - } - - ret = subdev_->getSelection(pad_, V4L2_SEL_TGT_CROP, &rect); - if (ret) { - LOG(CameraSensor, Warning) - << "Failed to retrieve the sensor crop rectangle"; - err = -EINVAL; - } - - if (err) { - LOG(CameraSensor, Warning) - << "The sensor kernel driver needs to be fixed"; - LOG(CameraSensor, Warning) - << "See Documentation/sensor_driver_requirements.rst in the libcamera sources for more information"; - } - - if (!bayerFormat_) - return 0; - - /* - * For raw sensors, make sure the sensor driver supports the controls - * required by the CameraSensor class. - */ - static constexpr uint32_t mandatoryControls[] = { - V4L2_CID_ANALOGUE_GAIN, - V4L2_CID_EXPOSURE, - V4L2_CID_HBLANK, - V4L2_CID_PIXEL_RATE, - V4L2_CID_VBLANK, - }; - - err = 0; - for (uint32_t ctrl : mandatoryControls) { - if (!controls.count(ctrl)) { - LOG(CameraSensor, Error) - << "Mandatory V4L2 control " << utils::hex(ctrl) - << " not available"; - err = -EINVAL; - } - } - - if (err) { - LOG(CameraSensor, Error) - << "The sensor kernel driver needs to be fixed"; - LOG(CameraSensor, Error) - << "See Documentation/sensor_driver_requirements.rst in the libcamera sources for more information"; - return err; - } - - return 0; -} - -/* - * \brief Initialize properties that cannot be intialized by the - * regular initProperties() function for VIMC - */ -void CameraSensor::initVimcDefaultProperties() -{ - /* Use the largest supported size. */ - pixelArraySize_ = sizes_.back(); - activeArea_ = Rectangle(pixelArraySize_); -} - -void CameraSensor::initStaticProperties() -{ - staticProps_ = CameraSensorProperties::get(model_); - if (!staticProps_) - return; - - /* Register the properties retrieved from the sensor database. */ - properties_.set(properties::UnitCellSize, staticProps_->unitCellSize); - - initTestPatternModes(); -} - -void CameraSensor::initTestPatternModes() -{ - const auto &v4l2TestPattern = controls().find(V4L2_CID_TEST_PATTERN); - if (v4l2TestPattern == controls().end()) { - LOG(CameraSensor, Debug) << "V4L2_CID_TEST_PATTERN is not supported"; - return; - } - - const auto &testPatternModes = staticProps_->testPatternModes; - if (testPatternModes.empty()) { - /* - * The camera sensor supports test patterns but we don't know - * how to map them so this should be fixed. - */ - LOG(CameraSensor, Debug) << "No static test pattern map for \'" - << model() << "\'"; - return; - } - - /* - * Create a map that associates the V4L2 control index to the test - * pattern mode by reversing the testPatternModes map provided by the - * camera sensor properties. This makes it easier to verify if the - * control index is supported in the below for loop that creates the - * list of supported test patterns. - */ - std::map indexToTestPatternMode; - for (const auto &it : testPatternModes) - indexToTestPatternMode[it.second] = it.first; - - for (const ControlValue &value : v4l2TestPattern->second.values()) { - const int32_t index = value.get(); - - const auto it = indexToTestPatternMode.find(index); - if (it == indexToTestPatternMode.end()) { - LOG(CameraSensor, Debug) - << "Test pattern mode " << index << " ignored"; - continue; - } - - testPatternModes_.push_back(it->second); - } -} - -int CameraSensor::initProperties() -{ - model_ = subdev_->model(); - properties_.set(properties::Model, utils::toAscii(model_)); - - /* Generate a unique ID for the sensor. */ - int ret = generateId(); - if (ret) - return ret; - - /* Initialize the static properties from the sensor database. */ - initStaticProperties(); - - /* Retrieve and register properties from the kernel interface. */ - const ControlInfoMap &controls = subdev_->controls(); - - const auto &orientation = controls.find(V4L2_CID_CAMERA_ORIENTATION); - if (orientation != controls.end()) { - int32_t v4l2Orientation = orientation->second.def().get(); - int32_t propertyValue; - - switch (v4l2Orientation) { - default: - LOG(CameraSensor, Warning) - << "Unsupported camera location " - << v4l2Orientation << ", setting to External"; - [[fallthrough]]; - case V4L2_CAMERA_ORIENTATION_EXTERNAL: - propertyValue = properties::CameraLocationExternal; - break; - case V4L2_CAMERA_ORIENTATION_FRONT: - propertyValue = properties::CameraLocationFront; - break; - case V4L2_CAMERA_ORIENTATION_BACK: - propertyValue = properties::CameraLocationBack; - break; - } - properties_.set(properties::Location, propertyValue); - } else { - LOG(CameraSensor, Warning) << "Failed to retrieve the camera location"; - } - - const auto &rotationControl = controls.find(V4L2_CID_CAMERA_SENSOR_ROTATION); - if (rotationControl != controls.end()) { - int32_t propertyValue = rotationControl->second.def().get(); - - /* - * Cache the Transform associated with the camera mounting - * rotation for later use in computeTransform(). - */ - bool success; - mountingOrientation_ = orientationFromRotation(propertyValue, &success); - if (!success) { - LOG(CameraSensor, Warning) - << "Invalid rotation of " << propertyValue - << " degrees - ignoring"; - mountingOrientation_ = Orientation::Rotate0; - } - - properties_.set(properties::Rotation, propertyValue); - } else { - LOG(CameraSensor, Warning) - << "Rotation control not available, default to 0 degrees"; - properties_.set(properties::Rotation, 0); - mountingOrientation_ = Orientation::Rotate0; - } - - properties_.set(properties::PixelArraySize, pixelArraySize_); - properties_.set(properties::PixelArrayActiveAreas, { activeArea_ }); - - /* Color filter array pattern, register only for RAW sensors. */ - if (bayerFormat_) { - int32_t cfa; - switch (bayerFormat_->order) { - case BayerFormat::BGGR: - cfa = properties::draft::BGGR; - break; - case BayerFormat::GBRG: - cfa = properties::draft::GBRG; - break; - case BayerFormat::GRBG: - cfa = properties::draft::GRBG; - break; - case BayerFormat::RGGB: - cfa = properties::draft::RGGB; - break; - case BayerFormat::MONO: - cfa = properties::draft::MONO; - break; - } - - properties_.set(properties::draft::ColorFilterArrangement, cfa); - } - - return 0; -} - -/** - * \brief Check for and initialise any ancillary devices - * - * Sensors sometimes have ancillary devices such as a Lens or Flash that could - * be linked to their MediaEntity by the kernel. Search for and handle any - * such device. - * - * \todo Handle MEDIA_ENT_F_FLASH too. - */ -int CameraSensor::discoverAncillaryDevices() -{ - int ret; - - for (MediaEntity *ancillary : entity_->ancillaryEntities()) { - switch (ancillary->function()) { - case MEDIA_ENT_F_LENS: - focusLens_ = std::make_unique(ancillary); - ret = focusLens_->init(); - if (ret) { - LOG(CameraSensor, Error) - << "Lens initialisation failed, lens disabled"; - focusLens_.reset(); - } - break; - - default: - LOG(CameraSensor, Warning) - << "Unsupported ancillary entity function " - << ancillary->function(); - break; - } - } - - return 0; -} +CameraSensor::~CameraSensor() = default; /** * \fn CameraSensor::model() @@ -624,29 +89,15 @@ int CameraSensor::discoverAncillaryDevices() */ /** + * \fn CameraSensor::sizes() * \brief Retrieve the supported frame sizes for a media bus code * \param[in] mbusCode The media bus code for which sizes are requested * * \return The supported frame sizes for \a mbusCode sorted in increasing order */ -std::vector CameraSensor::sizes(unsigned int mbusCode) const -{ - std::vector sizes; - - const auto &format = formats_.find(mbusCode); - if (format == formats_.end()) - return sizes; - - const std::vector &ranges = format->second; - std::transform(ranges.begin(), ranges.end(), std::back_inserter(sizes), - [](const SizeRange &range) { return range.max; }); - - std::sort(sizes.begin(), sizes.end()); - - return sizes; -} /** + * \fn CameraSensor::resolution() * \brief Retrieve the camera sensor resolution * * The camera sensor resolution is the active pixel area size, clamped to the @@ -659,12 +110,9 @@ std::vector CameraSensor::sizes(unsigned int mbusCode) const * * \return The camera sensor resolution in pixels */ -Size CameraSensor::resolution() const -{ - return std::min(sizes_.back(), activeArea_.size()); -} /** + * \fn CameraSensor::getFormat() * \brief Retrieve the best sensor format for a desired output * \param[in] mbusCodes The list of acceptable media bus codes * \param[in] size The desired size @@ -700,59 +148,9 @@ Size CameraSensor::resolution() const * \return The best sensor output format matching the desired media bus codes * and size on success, or an empty format otherwise. */ -V4L2SubdeviceFormat CameraSensor::getFormat(const std::vector &mbusCodes, - const Size &size) const -{ - unsigned int desiredArea = size.width * size.height; - unsigned int bestArea = UINT_MAX; - float desiredRatio = static_cast(size.width) / size.height; - float bestRatio = FLT_MAX; - const Size *bestSize = nullptr; - uint32_t bestCode = 0; - - for (unsigned int code : mbusCodes) { - const auto formats = formats_.find(code); - if (formats == formats_.end()) - continue; - - for (const SizeRange &range : formats->second) { - const Size &sz = range.max; - - if (sz.width < size.width || sz.height < size.height) - continue; - - float ratio = static_cast(sz.width) / sz.height; - float ratioDiff = fabsf(ratio - desiredRatio); - unsigned int area = sz.width * sz.height; - unsigned int areaDiff = area - desiredArea; - - if (ratioDiff > bestRatio) - continue; - - if (ratioDiff < bestRatio || areaDiff < bestArea) { - bestRatio = ratioDiff; - bestArea = areaDiff; - bestSize = &sz; - bestCode = code; - } - } - } - - if (!bestSize) { - LOG(CameraSensor, Debug) << "No supported format or size found"; - return {}; - } - - V4L2SubdeviceFormat format{ - .code = bestCode, - .size = *bestSize, - .colorSpace = ColorSpace::Raw, - }; - - return format; -} /** + * \fn CameraSensor::setFormat() * \brief Set the sensor output format * \param[in] format The desired sensor output format * \param[in] transform The transform to be applied on the sensor. @@ -767,32 +165,9 @@ V4L2SubdeviceFormat CameraSensor::getFormat(const std::vector &mbu * * \return 0 on success or a negative error code otherwise */ -int CameraSensor::setFormat(V4L2SubdeviceFormat *format, Transform transform) -{ - /* Configure flips if the sensor supports that. */ - if (supportFlips_) { - ControlList flipCtrls(subdev_->controls()); - - flipCtrls.set(V4L2_CID_HFLIP, - static_cast(!!(transform & Transform::HFlip))); - flipCtrls.set(V4L2_CID_VFLIP, - static_cast(!!(transform & Transform::VFlip))); - - int ret = subdev_->setControls(&flipCtrls); - if (ret) - return ret; - } - - /* Apply format on the subdev. */ - int ret = subdev_->setFormat(pad_, format); - if (ret) - return ret; - - subdev_->updateControlInfo(); - return 0; -} /** + * \fn CameraSensor::tryFormat() * \brief Try the sensor output format * \param[in] format The desired sensor output format * @@ -803,13 +178,9 @@ int CameraSensor::setFormat(V4L2SubdeviceFormat *format, Transform transform) * * \return 0 on success or a negative error code otherwise */ -int CameraSensor::tryFormat(V4L2SubdeviceFormat *format) const -{ - return subdev_->setFormat(pad_, format, - V4L2Subdevice::Whence::TryFormat); -} /** + * \fn CameraSensor::applyConfiguration() * \brief Apply a sensor configuration to the camera sensor * \param[in] config The sensor configuration * \param[in] transform The transform to be applied on the sensor. @@ -824,74 +195,6 @@ int CameraSensor::tryFormat(V4L2SubdeviceFormat *format) const * \return 0 if \a config is applied correctly to the camera sensor, a negative * error code otherwise */ -int CameraSensor::applyConfiguration(const SensorConfiguration &config, - Transform transform, - V4L2SubdeviceFormat *sensorFormat) -{ - if (!config.isValid()) { - LOG(CameraSensor, Error) << "Invalid sensor configuration"; - return -EINVAL; - } - - std::vector filteredCodes; - std::copy_if(mbusCodes_.begin(), mbusCodes_.end(), - std::back_inserter(filteredCodes), - [&config](unsigned int mbusCode) { - BayerFormat bayer = BayerFormat::fromMbusCode(mbusCode); - if (bayer.bitDepth == config.bitDepth) - return true; - return false; - }); - if (filteredCodes.empty()) { - LOG(CameraSensor, Error) - << "Cannot find any format with bit depth " - << config.bitDepth; - return -EINVAL; - } - - /* - * Compute the sensor's data frame size by applying the cropping - * rectangle, subsampling and output crop to the sensor's pixel array - * size. - * - * \todo The actual size computation is for now ignored and only the - * output size is considered. This implies that resolutions obtained - * with two different cropping/subsampling will look identical and - * only the first found one will be considered. - */ - V4L2SubdeviceFormat subdevFormat = {}; - for (unsigned int code : filteredCodes) { - for (const Size &size : sizes(code)) { - if (size.width != config.outputSize.width || - size.height != config.outputSize.height) - continue; - - subdevFormat.code = code; - subdevFormat.size = size; - break; - } - } - if (!subdevFormat.code) { - LOG(CameraSensor, Error) << "Invalid output size in sensor configuration"; - return -EINVAL; - } - - int ret = setFormat(&subdevFormat, transform); - if (ret) - return ret; - - /* - * Return to the caller the format actually applied to the sensor. - * This is relevant if transform has changed the bayer pattern order. - */ - if (sensorFormat) - *sensorFormat = subdevFormat; - - /* \todo Handle AnalogCrop. Most sensors do not support set_selection */ - /* \todo Handle scaling in the digital domain. */ - - return 0; -} /** * \fn CameraSensor::properties() @@ -900,6 +203,7 @@ int CameraSensor::applyConfiguration(const SensorConfiguration &config, */ /** + * \fn CameraSensor::sensorInfo() * \brief Assemble and return the camera sensor info * \param[out] info The camera sensor info * @@ -913,82 +217,9 @@ int CameraSensor::applyConfiguration(const SensorConfiguration &config, * * \return 0 on success, a negative error code otherwise */ -int CameraSensor::sensorInfo(IPACameraSensorInfo *info) const -{ - if (!bayerFormat_) - return -EINVAL; - - info->model = model(); - - /* - * The active area size is a static property, while the crop - * rectangle needs to be re-read as it depends on the sensor - * configuration. - */ - info->activeAreaSize = { activeArea_.width, activeArea_.height }; - - /* - * \todo Support for retreiving the crop rectangle is scheduled to - * become mandatory. For the time being use the default value if it has - * been initialized at sensor driver validation time. - */ - int ret = subdev_->getSelection(pad_, V4L2_SEL_TGT_CROP, &info->analogCrop); - if (ret) { - info->analogCrop = activeArea_; - LOG(CameraSensor, Warning) - << "The analogue crop rectangle has been defaulted to the active area size"; - } - - /* - * IPACameraSensorInfo::analogCrop::x and IPACameraSensorInfo::analogCrop::y - * are defined relatively to the active pixel area, while V4L2's - * TGT_CROP target is defined in respect to the full pixel array. - * - * Compensate it by subtracting the active area offset. - */ - info->analogCrop.x -= activeArea_.x; - info->analogCrop.y -= activeArea_.y; - - /* The bit depth and image size depend on the currently applied format. */ - V4L2SubdeviceFormat format{}; - ret = subdev_->getFormat(pad_, &format); - if (ret) - return ret; - - info->bitsPerPixel = MediaBusFormatInfo::info(format.code).bitsPerPixel; - info->outputSize = format.size; - - std::optional cfa = properties_.get(properties::draft::ColorFilterArrangement); - info->cfaPattern = cfa ? *cfa : properties::draft::RGB; - - /* - * Retrieve the pixel rate, line length and minimum/maximum frame - * duration through V4L2 controls. Support for the V4L2_CID_PIXEL_RATE, - * V4L2_CID_HBLANK and V4L2_CID_VBLANK controls is mandatory. - */ - ControlList ctrls = subdev_->getControls({ V4L2_CID_PIXEL_RATE, - V4L2_CID_HBLANK, - V4L2_CID_VBLANK }); - if (ctrls.empty()) { - LOG(CameraSensor, Error) - << "Failed to retrieve camera info controls"; - return -EINVAL; - } - - info->pixelRate = ctrls.get(V4L2_CID_PIXEL_RATE).get(); - - const ControlInfo hblank = ctrls.infoMap()->at(V4L2_CID_HBLANK); - info->minLineLength = info->outputSize.width + hblank.min().get(); - info->maxLineLength = info->outputSize.width + hblank.max().get(); - - const ControlInfo vblank = ctrls.infoMap()->at(V4L2_CID_VBLANK); - info->minFrameLength = info->outputSize.height + vblank.min().get(); - info->maxFrameLength = info->outputSize.height + vblank.max().get(); - - return 0; -} /** + * \fn CameraSensor::computeTransform() * \brief Compute the Transform that gives the requested \a orientation * \param[inout] orientation The desired image orientation * @@ -1014,40 +245,9 @@ int CameraSensor::sensorInfo(IPACameraSensorInfo *info) const * \return A Transform instance that applied to the CameraSensor produces images * with \a orientation */ -Transform CameraSensor::computeTransform(Orientation *orientation) const -{ - /* - * If we cannot do any flips we cannot change the native camera mounting - * orientation. - */ - if (!supportFlips_) { - *orientation = mountingOrientation_; - return Transform::Identity; - } - - /* - * Now compute the required transform to obtain 'orientation' starting - * from the mounting rotation. - * - * As a note: - * orientation / mountingOrientation_ = transform - * mountingOrientation_ * transform = orientation - */ - Transform transform = *orientation / mountingOrientation_; - - /* - * If transform contains any Transpose we cannot do it, so adjust - * 'orientation' to report the image native orientation and return Identity. - */ - if (!!(transform & Transform::Transpose)) { - *orientation = mountingOrientation_; - return Transform::Identity; - } - - return transform; -} /** + * \fn CameraSensor::bayerOrder() * \brief Compute the Bayer order that results from the given Transform * \param[in] t The Transform to apply to the sensor * @@ -1059,23 +259,9 @@ Transform CameraSensor::computeTransform(Orientation *orientation) const * * \return The Bayer order produced by the sensor when the Transform is applied */ -BayerFormat::Order CameraSensor::bayerOrder(Transform t) const -{ - /* Return a defined by meaningless value for non-Bayer sensors. */ - if (!bayerFormat_) - return BayerFormat::Order::BGGR; - - if (!flipsAlterBayerOrder_) - return bayerFormat_->order; - - /* - * Apply the transform to the native (i.e. untransformed) Bayer order, - * using the rest of the Bayer format supplied by the caller. - */ - return bayerFormat_->transform(t).order; -} /** + * \fn CameraSensor::controls() * \brief Retrieve the supported V4L2 controls and their information * * Control information is updated automatically to reflect the current sensor @@ -1084,12 +270,9 @@ BayerFormat::Order CameraSensor::bayerOrder(Transform t) const * * \return A map of the V4L2 controls supported by the sensor */ -const ControlInfoMap &CameraSensor::controls() const -{ - return subdev_->controls(); -} /** + * \fn CameraSensor::getControls() * \brief Read V4L2 controls from the sensor * \param[in] ids The list of controls to read, specified by their ID * @@ -1107,12 +290,9 @@ const ControlInfoMap &CameraSensor::controls() const * \return The control values in a ControlList on success, or an empty list on * error */ -ControlList CameraSensor::getControls(const std::vector &ids) -{ - return subdev_->getControls(ids); -} /** + * \fn CameraSensor::setControls() * \brief Write V4L2 controls to the sensor * \param[in] ctrls The list of controls to write * @@ -1137,10 +317,6 @@ ControlList CameraSensor::getControls(const std::vector &ids) * \retval -EINVAL One of the control is not supported or not accessible * \retval i The index of the control that failed */ -int CameraSensor::setControls(ControlList *ctrls) -{ - return subdev_->setControls(ctrls); -} /** * \fn CameraSensor::testPatternModes() @@ -1151,6 +327,7 @@ int CameraSensor::setControls(ControlList *ctrls) */ /** + * \fn CameraSensor::setTestPatternMode() * \brief Set the test pattern mode for the camera sensor * \param[in] mode The test pattern mode * @@ -1158,84 +335,6 @@ int CameraSensor::setControls(ControlList *ctrls) * pattern mode. Otherwise, this function is a no-op. Setting the same test * pattern mode for every frame thus incurs no performance penalty. */ -int CameraSensor::setTestPatternMode(controls::draft::TestPatternModeEnum mode) -{ - if (testPatternMode_ == mode) - return 0; - - if (testPatternModes_.empty()) { - LOG(CameraSensor, Error) - << "Camera sensor does not support test pattern modes."; - return -EINVAL; - } - - return applyTestPatternMode(mode); -} - -int CameraSensor::applyTestPatternMode(controls::draft::TestPatternModeEnum mode) -{ - if (testPatternModes_.empty()) - return 0; - - auto it = std::find(testPatternModes_.begin(), testPatternModes_.end(), - mode); - if (it == testPatternModes_.end()) { - LOG(CameraSensor, Error) << "Unsupported test pattern mode " - << mode; - return -EINVAL; - } - - LOG(CameraSensor, Debug) << "Apply test pattern mode " << mode; - - int32_t index = staticProps_->testPatternModes.at(mode); - ControlList ctrls{ controls() }; - ctrls.set(V4L2_CID_TEST_PATTERN, index); - - int ret = setControls(&ctrls); - if (ret) - return ret; - - testPatternMode_ = mode; - - return 0; -} - -std::string CameraSensor::logPrefix() const -{ - return "'" + entity_->name() + "'"; -} - -namespace { - -/* Transitory default camera sensor implementation */ -class CameraSensorDefault : public CameraSensor -{ -public: - CameraSensorDefault(MediaEntity *entity) - : CameraSensor(entity) - { - } - - static bool match([[maybe_unused]] const MediaEntity *entity) - { - return true; - } - - static std::unique_ptr create(MediaEntity *entity) - { - std::unique_ptr sensor = - std::make_unique(entity); - - if (sensor->init()) - return nullptr; - - return sensor; - } -}; - -REGISTER_CAMERA_SENSOR(CameraSensorDefault) - -}; /* namespace */ /** * \class CameraSensorFactoryBase @@ -1271,18 +370,18 @@ std::unique_ptr CameraSensorFactoryBase::create(MediaEntity *entit CameraSensorFactoryBase::factories(); for (const CameraSensorFactoryBase *factory : factories) { - if (!factory->match(entity)) - continue; + std::variant, int> result = + factory->match(entity); - std::unique_ptr sensor = factory->createInstance(entity); - if (!sensor) { + if (std::holds_alternative>(result)) + return std::get>(std::move(result)); + + if (std::get(result)) { LOG(CameraSensor, Error) << "Failed to create sensor for '" - << entity->name(); + << entity->name() << ": " << std::get(result); return nullptr; } - - return sensor; } return nullptr; @@ -1337,33 +436,27 @@ void CameraSensorFactoryBase::registerFactory(CameraSensorFactoryBase *factory) * function. */ -/** - * \fn CameraSensorFactory::createInstance() const - * \brief Create an instance of the CameraSensor corresponding to the factory - * - * \return A unique pointer to a newly constructed instance of the CameraSensor - * subclass corresponding to the factory - */ - /** * \def REGISTER_CAMERA_SENSOR(sensor) * \brief Register a camera sensor type to the sensor factory * \param[in] sensor Class name of the CameraSensor derived class to register * * Register a CameraSensor subclass with the factory and make it available to - * try and match sensors. The subclass needs to implement two static functions: + * try and match sensors. The subclass needs to implement a static match + * function: * * \code{.cpp} - * static bool match(const MediaEntity *entity); - * static std::unique_ptr create(MediaEntity *entity); + * static std::variant, int> match(MediaEntity *entity); * \endcode * - * The match() function tests if the sensor class supports the camera sensor - * identified by a MediaEntity. + * The function tests if the sensor class supports the camera sensor identified + * by a MediaEntity. If so, it creates a new instance of the sensor class. The + * return value is a variant that contains * - * The create() function creates a new instance of the sensor class. It may - * return a null pointer if initialization of the instance fails. It will only - * be called if the match() function has returned true for the given entity. + * - A new instance of the camera sensor class if the entity matched and + * creation succeeded ; + * - A non-zero error code if the entity matched and the creation failed ; or + * - A zero error code if the entity didn't match. */ } /* namespace libcamera */ diff --git a/src/libcamera/sensor/camera_sensor_legacy.cpp b/src/libcamera/sensor/camera_sensor_legacy.cpp new file mode 100644 index 000000000000..34677339241c --- /dev/null +++ b/src/libcamera/sensor/camera_sensor_legacy.cpp @@ -0,0 +1,1015 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * camera_sensor_legacy.cpp - A V4L2-backed camera sensor + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "libcamera/internal/bayer_format.h" +#include "libcamera/internal/camera_lens.h" +#include "libcamera/internal/camera_sensor.h" +#include "libcamera/internal/camera_sensor_properties.h" +#include "libcamera/internal/formats.h" +#include "libcamera/internal/media_device.h" +#include "libcamera/internal/sysfs.h" +#include "libcamera/internal/v4l2_subdevice.h" + +namespace libcamera { + +class BayerFormat; +class CameraLens; +class MediaEntity; +class SensorConfiguration; + +struct CameraSensorProperties; + +enum class Orientation; + +LOG_DECLARE_CATEGORY(CameraSensor) + +class CameraSensorLegacy : public CameraSensor, protected Loggable +{ +public: + CameraSensorLegacy(const MediaEntity *entity); + ~CameraSensorLegacy(); + + static std::variant, int> + match(MediaEntity *entity); + + const std::string &model() const override { return model_; } + const std::string &id() const override { return id_; } + + const MediaEntity *entity() const override { return entity_; } + V4L2Subdevice *device() override { return subdev_.get(); } + + CameraLens *focusLens() override { return focusLens_.get(); } + + const std::vector &mbusCodes() const override { return mbusCodes_; } + std::vector sizes(unsigned int mbusCode) const override; + Size resolution() const override; + + V4L2SubdeviceFormat getFormat(const std::vector &mbusCodes, + const Size &size) const override; + int setFormat(V4L2SubdeviceFormat *format, + Transform transform = Transform::Identity) override; + int tryFormat(V4L2SubdeviceFormat *format) const override; + + int applyConfiguration(const SensorConfiguration &config, + Transform transform = Transform::Identity, + V4L2SubdeviceFormat *sensorFormat = nullptr) override; + + const ControlList &properties() const override { return properties_; } + int sensorInfo(IPACameraSensorInfo *info) const override; + Transform computeTransform(Orientation *orientation) const override; + BayerFormat::Order bayerOrder(Transform t) const override; + + const ControlInfoMap &controls() const override; + ControlList getControls(const std::vector &ids) override; + int setControls(ControlList *ctrls) override; + + const std::vector & + testPatternModes() const override { return testPatternModes_; } + int setTestPatternMode(controls::draft::TestPatternModeEnum mode) override; + +protected: + std::string logPrefix() const override; + +private: + LIBCAMERA_DISABLE_COPY(CameraSensorLegacy) + + int init(); + int generateId(); + int validateSensorDriver(); + void initVimcDefaultProperties(); + void initStaticProperties(); + void initTestPatternModes(); + int initProperties(); + int applyTestPatternMode(controls::draft::TestPatternModeEnum mode); + int discoverAncillaryDevices(); + + const MediaEntity *entity_; + std::unique_ptr subdev_; + unsigned int pad_; + + const CameraSensorProperties *staticProps_; + + std::string model_; + std::string id_; + + V4L2Subdevice::Formats formats_; + std::vector mbusCodes_; + std::vector sizes_; + std::vector testPatternModes_; + controls::draft::TestPatternModeEnum testPatternMode_; + + Size pixelArraySize_; + Rectangle activeArea_; + const BayerFormat *bayerFormat_; + bool supportFlips_; + bool flipsAlterBayerOrder_; + Orientation mountingOrientation_; + + ControlList properties_; + + std::unique_ptr focusLens_; +}; + +/** + * \class CameraSensorLegacy + * \brief A camera sensor based on V4L2 subdevices + * + * The implementation is currently limited to sensors that expose a single V4L2 + * subdevice with a single pad. It will be extended to support more complex + * devices as the needs arise. + */ + +CameraSensorLegacy::CameraSensorLegacy(const MediaEntity *entity) + : entity_(entity), pad_(UINT_MAX), staticProps_(nullptr), + bayerFormat_(nullptr), supportFlips_(false), + flipsAlterBayerOrder_(false), properties_(properties::properties) +{ +} + +CameraSensorLegacy::~CameraSensorLegacy() = default; + +std::variant, int> +CameraSensorLegacy::match(MediaEntity *entity) +{ + std::unique_ptr sensor = + std::make_unique(entity); + + int ret = sensor->init(); + if (ret) + return { ret }; + + return { std::move(sensor) }; +} + +int CameraSensorLegacy::init() +{ + for (const MediaPad *pad : entity_->pads()) { + if (pad->flags() & MEDIA_PAD_FL_SOURCE) { + pad_ = pad->index(); + break; + } + } + + if (pad_ == UINT_MAX) { + LOG(CameraSensor, Error) + << "Sensors with more than one pad are not supported"; + return -EINVAL; + } + + switch (entity_->function()) { + case MEDIA_ENT_F_CAM_SENSOR: + case MEDIA_ENT_F_PROC_VIDEO_ISP: + break; + + default: + LOG(CameraSensor, Error) + << "Invalid sensor function " + << utils::hex(entity_->function()); + return -EINVAL; + } + + /* Create and open the subdev. */ + subdev_ = std::make_unique(entity_); + int ret = subdev_->open(); + if (ret < 0) + return ret; + + /* + * Clear any flips to be sure we get the "native" Bayer order. This is + * harmless for sensors where the flips don't affect the Bayer order. + */ + ControlList ctrls(subdev_->controls()); + if (subdev_->controls().find(V4L2_CID_HFLIP) != subdev_->controls().end()) + ctrls.set(V4L2_CID_HFLIP, 0); + if (subdev_->controls().find(V4L2_CID_VFLIP) != subdev_->controls().end()) + ctrls.set(V4L2_CID_VFLIP, 0); + subdev_->setControls(&ctrls); + + /* Enumerate, sort and cache media bus codes and sizes. */ + formats_ = subdev_->formats(pad_); + if (formats_.empty()) { + LOG(CameraSensor, Error) << "No image format found"; + return -EINVAL; + } + + mbusCodes_ = utils::map_keys(formats_); + std::sort(mbusCodes_.begin(), mbusCodes_.end()); + + for (const auto &format : formats_) { + const std::vector &ranges = format.second; + std::transform(ranges.begin(), ranges.end(), std::back_inserter(sizes_), + [](const SizeRange &range) { return range.max; }); + } + + std::sort(sizes_.begin(), sizes_.end()); + + /* Remove duplicates. */ + auto last = std::unique(sizes_.begin(), sizes_.end()); + sizes_.erase(last, sizes_.end()); + + /* + * VIMC is a bit special, as it does not yet support all the mandatory + * requirements regular sensors have to respect. + * + * Do not validate the driver if it's VIMC and initialize the sensor + * properties with static information. + * + * \todo Remove the special case once the VIMC driver has been + * updated in all test platforms. + */ + if (entity_->device()->driver() == "vimc") { + initVimcDefaultProperties(); + + ret = initProperties(); + if (ret) + return ret; + + return discoverAncillaryDevices(); + } + + /* Get the color filter array pattern (only for RAW sensors). */ + for (unsigned int mbusCode : mbusCodes_) { + const BayerFormat &bayerFormat = BayerFormat::fromMbusCode(mbusCode); + if (bayerFormat.isValid()) { + bayerFormat_ = &bayerFormat; + break; + } + } + + ret = validateSensorDriver(); + if (ret) + return ret; + + ret = initProperties(); + if (ret) + return ret; + + ret = discoverAncillaryDevices(); + if (ret) + return ret; + + /* + * Set HBLANK to the minimum to start with a well-defined line length, + * allowing IPA modules that do not modify HBLANK to use the sensor + * minimum line length in their calculations. + */ + const struct v4l2_query_ext_ctrl *hblankInfo = subdev_->controlInfo(V4L2_CID_HBLANK); + if (hblankInfo && !(hblankInfo->flags & V4L2_CTRL_FLAG_READ_ONLY)) { + ControlList ctrl(subdev_->controls()); + + ctrl.set(V4L2_CID_HBLANK, static_cast(hblankInfo->minimum)); + ret = subdev_->setControls(&ctrl); + if (ret) + return ret; + } + + return applyTestPatternMode(controls::draft::TestPatternModeEnum::TestPatternModeOff); +} + +int CameraSensorLegacy::generateId() +{ + const std::string devPath = subdev_->devicePath(); + + /* Try to get ID from firmware description. */ + id_ = sysfs::firmwareNodePath(devPath); + if (!id_.empty()) + return 0; + + /* + * Virtual sensors not described in firmware + * + * Verify it's a platform device and construct ID from the device path + * and model of sensor. + */ + if (devPath.find("/sys/devices/platform/", 0) == 0) { + id_ = devPath.substr(strlen("/sys/devices/")) + " " + model(); + return 0; + } + + LOG(CameraSensor, Error) << "Can't generate sensor ID"; + return -EINVAL; +} + +int CameraSensorLegacy::validateSensorDriver() +{ + int err = 0; + + /* + * Optional controls are used to register optional sensor properties. If + * not present, some values will be defaulted. + */ + static constexpr uint32_t optionalControls[] = { + V4L2_CID_CAMERA_SENSOR_ROTATION, + }; + + const ControlIdMap &controls = subdev_->controls().idmap(); + for (uint32_t ctrl : optionalControls) { + if (!controls.count(ctrl)) + LOG(CameraSensor, Debug) + << "Optional V4L2 control " << utils::hex(ctrl) + << " not supported"; + } + + /* + * Recommended controls are similar to optional controls, but will + * become mandatory in the near future. Be loud if they're missing. + */ + static constexpr uint32_t recommendedControls[] = { + V4L2_CID_CAMERA_ORIENTATION, + }; + + for (uint32_t ctrl : recommendedControls) { + if (!controls.count(ctrl)) { + LOG(CameraSensor, Warning) + << "Recommended V4L2 control " << utils::hex(ctrl) + << " not supported"; + err = -EINVAL; + } + } + + /* + * Verify if sensor supports horizontal/vertical flips + * + * \todo Handle horizontal and vertical flips independently. + */ + const struct v4l2_query_ext_ctrl *hflipInfo = subdev_->controlInfo(V4L2_CID_HFLIP); + const struct v4l2_query_ext_ctrl *vflipInfo = subdev_->controlInfo(V4L2_CID_VFLIP); + if (hflipInfo && !(hflipInfo->flags & V4L2_CTRL_FLAG_READ_ONLY) && + vflipInfo && !(vflipInfo->flags & V4L2_CTRL_FLAG_READ_ONLY)) { + supportFlips_ = true; + + if (hflipInfo->flags & V4L2_CTRL_FLAG_MODIFY_LAYOUT || + vflipInfo->flags & V4L2_CTRL_FLAG_MODIFY_LAYOUT) + flipsAlterBayerOrder_ = true; + } + + if (!supportFlips_) + LOG(CameraSensor, Debug) + << "Camera sensor does not support horizontal/vertical flip"; + + /* + * Make sure the required selection targets are supported. + * + * Failures in reading any of the targets are not deemed to be fatal, + * but some properties and features, like constructing a + * IPACameraSensorInfo for the IPA module, won't be supported. + * + * \todo Make support for selection targets mandatory as soon as all + * test platforms have been updated. + */ + Rectangle rect; + int ret = subdev_->getSelection(pad_, V4L2_SEL_TGT_CROP_BOUNDS, &rect); + if (ret) { + /* + * Default the pixel array size to the largest size supported + * by the sensor. The sizes_ vector is sorted in ascending + * order, the largest size is thus the last element. + */ + pixelArraySize_ = sizes_.back(); + + LOG(CameraSensor, Warning) + << "The PixelArraySize property has been defaulted to " + << pixelArraySize_; + err = -EINVAL; + } else { + pixelArraySize_ = rect.size(); + } + + ret = subdev_->getSelection(pad_, V4L2_SEL_TGT_CROP_DEFAULT, &activeArea_); + if (ret) { + activeArea_ = Rectangle(pixelArraySize_); + LOG(CameraSensor, Warning) + << "The PixelArrayActiveAreas property has been defaulted to " + << activeArea_; + err = -EINVAL; + } + + ret = subdev_->getSelection(pad_, V4L2_SEL_TGT_CROP, &rect); + if (ret) { + LOG(CameraSensor, Warning) + << "Failed to retrieve the sensor crop rectangle"; + err = -EINVAL; + } + + if (err) { + LOG(CameraSensor, Warning) + << "The sensor kernel driver needs to be fixed"; + LOG(CameraSensor, Warning) + << "See Documentation/sensor_driver_requirements.rst in the libcamera sources for more information"; + } + + if (!bayerFormat_) + return 0; + + /* + * For raw sensors, make sure the sensor driver supports the controls + * required by the CameraSensor class. + */ + static constexpr uint32_t mandatoryControls[] = { + V4L2_CID_ANALOGUE_GAIN, + V4L2_CID_EXPOSURE, + V4L2_CID_HBLANK, + V4L2_CID_PIXEL_RATE, + V4L2_CID_VBLANK, + }; + + err = 0; + for (uint32_t ctrl : mandatoryControls) { + if (!controls.count(ctrl)) { + LOG(CameraSensor, Error) + << "Mandatory V4L2 control " << utils::hex(ctrl) + << " not available"; + err = -EINVAL; + } + } + + if (err) { + LOG(CameraSensor, Error) + << "The sensor kernel driver needs to be fixed"; + LOG(CameraSensor, Error) + << "See Documentation/sensor_driver_requirements.rst in the libcamera sources for more information"; + return err; + } + + return 0; +} + +void CameraSensorLegacy::initVimcDefaultProperties() +{ + /* Use the largest supported size. */ + pixelArraySize_ = sizes_.back(); + activeArea_ = Rectangle(pixelArraySize_); +} + +void CameraSensorLegacy::initStaticProperties() +{ + staticProps_ = CameraSensorProperties::get(model_); + if (!staticProps_) + return; + + /* Register the properties retrieved from the sensor database. */ + properties_.set(properties::UnitCellSize, staticProps_->unitCellSize); + + initTestPatternModes(); +} + +void CameraSensorLegacy::initTestPatternModes() +{ + const auto &v4l2TestPattern = controls().find(V4L2_CID_TEST_PATTERN); + if (v4l2TestPattern == controls().end()) { + LOG(CameraSensor, Debug) << "V4L2_CID_TEST_PATTERN is not supported"; + return; + } + + const auto &testPatternModes = staticProps_->testPatternModes; + if (testPatternModes.empty()) { + /* + * The camera sensor supports test patterns but we don't know + * how to map them so this should be fixed. + */ + LOG(CameraSensor, Debug) << "No static test pattern map for \'" + << model() << "\'"; + return; + } + + /* + * Create a map that associates the V4L2 control index to the test + * pattern mode by reversing the testPatternModes map provided by the + * camera sensor properties. This makes it easier to verify if the + * control index is supported in the below for loop that creates the + * list of supported test patterns. + */ + std::map indexToTestPatternMode; + for (const auto &it : testPatternModes) + indexToTestPatternMode[it.second] = it.first; + + for (const ControlValue &value : v4l2TestPattern->second.values()) { + const int32_t index = value.get(); + + const auto it = indexToTestPatternMode.find(index); + if (it == indexToTestPatternMode.end()) { + LOG(CameraSensor, Debug) + << "Test pattern mode " << index << " ignored"; + continue; + } + + testPatternModes_.push_back(it->second); + } +} + +int CameraSensorLegacy::initProperties() +{ + model_ = subdev_->model(); + properties_.set(properties::Model, utils::toAscii(model_)); + + /* Generate a unique ID for the sensor. */ + int ret = generateId(); + if (ret) + return ret; + + /* Initialize the static properties from the sensor database. */ + initStaticProperties(); + + /* Retrieve and register properties from the kernel interface. */ + const ControlInfoMap &controls = subdev_->controls(); + + const auto &orientation = controls.find(V4L2_CID_CAMERA_ORIENTATION); + if (orientation != controls.end()) { + int32_t v4l2Orientation = orientation->second.def().get(); + int32_t propertyValue; + + switch (v4l2Orientation) { + default: + LOG(CameraSensor, Warning) + << "Unsupported camera location " + << v4l2Orientation << ", setting to External"; + [[fallthrough]]; + case V4L2_CAMERA_ORIENTATION_EXTERNAL: + propertyValue = properties::CameraLocationExternal; + break; + case V4L2_CAMERA_ORIENTATION_FRONT: + propertyValue = properties::CameraLocationFront; + break; + case V4L2_CAMERA_ORIENTATION_BACK: + propertyValue = properties::CameraLocationBack; + break; + } + properties_.set(properties::Location, propertyValue); + } else { + LOG(CameraSensor, Warning) << "Failed to retrieve the camera location"; + } + + const auto &rotationControl = controls.find(V4L2_CID_CAMERA_SENSOR_ROTATION); + if (rotationControl != controls.end()) { + int32_t propertyValue = rotationControl->second.def().get(); + + /* + * Cache the Transform associated with the camera mounting + * rotation for later use in computeTransform(). + */ + bool success; + mountingOrientation_ = orientationFromRotation(propertyValue, &success); + if (!success) { + LOG(CameraSensor, Warning) + << "Invalid rotation of " << propertyValue + << " degrees - ignoring"; + mountingOrientation_ = Orientation::Rotate0; + } + + properties_.set(properties::Rotation, propertyValue); + } else { + LOG(CameraSensor, Warning) + << "Rotation control not available, default to 0 degrees"; + properties_.set(properties::Rotation, 0); + mountingOrientation_ = Orientation::Rotate0; + } + + properties_.set(properties::PixelArraySize, pixelArraySize_); + properties_.set(properties::PixelArrayActiveAreas, { activeArea_ }); + + /* Color filter array pattern, register only for RAW sensors. */ + if (bayerFormat_) { + int32_t cfa; + switch (bayerFormat_->order) { + case BayerFormat::BGGR: + cfa = properties::draft::BGGR; + break; + case BayerFormat::GBRG: + cfa = properties::draft::GBRG; + break; + case BayerFormat::GRBG: + cfa = properties::draft::GRBG; + break; + case BayerFormat::RGGB: + cfa = properties::draft::RGGB; + break; + case BayerFormat::MONO: + cfa = properties::draft::MONO; + break; + } + + properties_.set(properties::draft::ColorFilterArrangement, cfa); + } + + return 0; +} + +int CameraSensorLegacy::discoverAncillaryDevices() +{ + int ret; + + for (MediaEntity *ancillary : entity_->ancillaryEntities()) { + switch (ancillary->function()) { + case MEDIA_ENT_F_LENS: + focusLens_ = std::make_unique(ancillary); + ret = focusLens_->init(); + if (ret) { + LOG(CameraSensor, Error) + << "Lens initialisation failed, lens disabled"; + focusLens_.reset(); + } + break; + + default: + LOG(CameraSensor, Warning) + << "Unsupported ancillary entity function " + << ancillary->function(); + break; + } + } + + return 0; +} + +std::vector CameraSensorLegacy::sizes(unsigned int mbusCode) const +{ + std::vector sizes; + + const auto &format = formats_.find(mbusCode); + if (format == formats_.end()) + return sizes; + + const std::vector &ranges = format->second; + std::transform(ranges.begin(), ranges.end(), std::back_inserter(sizes), + [](const SizeRange &range) { return range.max; }); + + std::sort(sizes.begin(), sizes.end()); + + return sizes; +} + +Size CameraSensorLegacy::resolution() const +{ + return std::min(sizes_.back(), activeArea_.size()); +} + +V4L2SubdeviceFormat +CameraSensorLegacy::getFormat(const std::vector &mbusCodes, + const Size &size) const +{ + unsigned int desiredArea = size.width * size.height; + unsigned int bestArea = UINT_MAX; + float desiredRatio = static_cast(size.width) / size.height; + float bestRatio = FLT_MAX; + const Size *bestSize = nullptr; + uint32_t bestCode = 0; + + for (unsigned int code : mbusCodes) { + const auto formats = formats_.find(code); + if (formats == formats_.end()) + continue; + + for (const SizeRange &range : formats->second) { + const Size &sz = range.max; + + if (sz.width < size.width || sz.height < size.height) + continue; + + float ratio = static_cast(sz.width) / sz.height; + float ratioDiff = fabsf(ratio - desiredRatio); + unsigned int area = sz.width * sz.height; + unsigned int areaDiff = area - desiredArea; + + if (ratioDiff > bestRatio) + continue; + + if (ratioDiff < bestRatio || areaDiff < bestArea) { + bestRatio = ratioDiff; + bestArea = areaDiff; + bestSize = &sz; + bestCode = code; + } + } + } + + if (!bestSize) { + LOG(CameraSensor, Debug) << "No supported format or size found"; + return {}; + } + + V4L2SubdeviceFormat format{ + .code = bestCode, + .size = *bestSize, + .colorSpace = ColorSpace::Raw, + }; + + return format; +} + +int CameraSensorLegacy::setFormat(V4L2SubdeviceFormat *format, Transform transform) +{ + /* Configure flips if the sensor supports that. */ + if (supportFlips_) { + ControlList flipCtrls(subdev_->controls()); + + flipCtrls.set(V4L2_CID_HFLIP, + static_cast(!!(transform & Transform::HFlip))); + flipCtrls.set(V4L2_CID_VFLIP, + static_cast(!!(transform & Transform::VFlip))); + + int ret = subdev_->setControls(&flipCtrls); + if (ret) + return ret; + } + + /* Apply format on the subdev. */ + int ret = subdev_->setFormat(pad_, format); + if (ret) + return ret; + + subdev_->updateControlInfo(); + return 0; +} + +int CameraSensorLegacy::tryFormat(V4L2SubdeviceFormat *format) const +{ + return subdev_->setFormat(pad_, format, + V4L2Subdevice::Whence::TryFormat); +} + +int CameraSensorLegacy::applyConfiguration(const SensorConfiguration &config, + Transform transform, + V4L2SubdeviceFormat *sensorFormat) +{ + if (!config.isValid()) { + LOG(CameraSensor, Error) << "Invalid sensor configuration"; + return -EINVAL; + } + + std::vector filteredCodes; + std::copy_if(mbusCodes_.begin(), mbusCodes_.end(), + std::back_inserter(filteredCodes), + [&config](unsigned int mbusCode) { + BayerFormat bayer = BayerFormat::fromMbusCode(mbusCode); + if (bayer.bitDepth == config.bitDepth) + return true; + return false; + }); + if (filteredCodes.empty()) { + LOG(CameraSensor, Error) + << "Cannot find any format with bit depth " + << config.bitDepth; + return -EINVAL; + } + + /* + * Compute the sensor's data frame size by applying the cropping + * rectangle, subsampling and output crop to the sensor's pixel array + * size. + * + * \todo The actual size computation is for now ignored and only the + * output size is considered. This implies that resolutions obtained + * with two different cropping/subsampling will look identical and + * only the first found one will be considered. + */ + V4L2SubdeviceFormat subdevFormat = {}; + for (unsigned int code : filteredCodes) { + for (const Size &size : sizes(code)) { + if (size.width != config.outputSize.width || + size.height != config.outputSize.height) + continue; + + subdevFormat.code = code; + subdevFormat.size = size; + break; + } + } + if (!subdevFormat.code) { + LOG(CameraSensor, Error) << "Invalid output size in sensor configuration"; + return -EINVAL; + } + + int ret = setFormat(&subdevFormat, transform); + if (ret) + return ret; + + /* + * Return to the caller the format actually applied to the sensor. + * This is relevant if transform has changed the bayer pattern order. + */ + if (sensorFormat) + *sensorFormat = subdevFormat; + + /* \todo Handle AnalogCrop. Most sensors do not support set_selection */ + /* \todo Handle scaling in the digital domain. */ + + return 0; +} + +int CameraSensorLegacy::sensorInfo(IPACameraSensorInfo *info) const +{ + if (!bayerFormat_) + return -EINVAL; + + info->model = model(); + + /* + * The active area size is a static property, while the crop + * rectangle needs to be re-read as it depends on the sensor + * configuration. + */ + info->activeAreaSize = { activeArea_.width, activeArea_.height }; + + /* + * \todo Support for retreiving the crop rectangle is scheduled to + * become mandatory. For the time being use the default value if it has + * been initialized at sensor driver validation time. + */ + int ret = subdev_->getSelection(pad_, V4L2_SEL_TGT_CROP, &info->analogCrop); + if (ret) { + info->analogCrop = activeArea_; + LOG(CameraSensor, Warning) + << "The analogue crop rectangle has been defaulted to the active area size"; + } + + /* + * IPACameraSensorInfo::analogCrop::x and IPACameraSensorInfo::analogCrop::y + * are defined relatively to the active pixel area, while V4L2's + * TGT_CROP target is defined in respect to the full pixel array. + * + * Compensate it by subtracting the active area offset. + */ + info->analogCrop.x -= activeArea_.x; + info->analogCrop.y -= activeArea_.y; + + /* The bit depth and image size depend on the currently applied format. */ + V4L2SubdeviceFormat format{}; + ret = subdev_->getFormat(pad_, &format); + if (ret) + return ret; + info->bitsPerPixel = MediaBusFormatInfo::info(format.code).bitsPerPixel; + info->outputSize = format.size; + + std::optional cfa = properties_.get(properties::draft::ColorFilterArrangement); + info->cfaPattern = cfa ? *cfa : properties::draft::RGB; + + /* + * Retrieve the pixel rate, line length and minimum/maximum frame + * duration through V4L2 controls. Support for the V4L2_CID_PIXEL_RATE, + * V4L2_CID_HBLANK and V4L2_CID_VBLANK controls is mandatory. + */ + ControlList ctrls = subdev_->getControls({ V4L2_CID_PIXEL_RATE, + V4L2_CID_HBLANK, + V4L2_CID_VBLANK }); + if (ctrls.empty()) { + LOG(CameraSensor, Error) + << "Failed to retrieve camera info controls"; + return -EINVAL; + } + + info->pixelRate = ctrls.get(V4L2_CID_PIXEL_RATE).get(); + + const ControlInfo hblank = ctrls.infoMap()->at(V4L2_CID_HBLANK); + info->minLineLength = info->outputSize.width + hblank.min().get(); + info->maxLineLength = info->outputSize.width + hblank.max().get(); + + const ControlInfo vblank = ctrls.infoMap()->at(V4L2_CID_VBLANK); + info->minFrameLength = info->outputSize.height + vblank.min().get(); + info->maxFrameLength = info->outputSize.height + vblank.max().get(); + + return 0; +} + +Transform CameraSensorLegacy::computeTransform(Orientation *orientation) const +{ + /* + * If we cannot do any flips we cannot change the native camera mounting + * orientation. + */ + if (!supportFlips_) { + *orientation = mountingOrientation_; + return Transform::Identity; + } + + /* + * Now compute the required transform to obtain 'orientation' starting + * from the mounting rotation. + * + * As a note: + * orientation / mountingOrientation_ = transform + * mountingOrientation_ * transform = orientation + */ + Transform transform = *orientation / mountingOrientation_; + + /* + * If transform contains any Transpose we cannot do it, so adjust + * 'orientation' to report the image native orientation and return Identity. + */ + if (!!(transform & Transform::Transpose)) { + *orientation = mountingOrientation_; + return Transform::Identity; + } + + return transform; +} + +BayerFormat::Order CameraSensorLegacy::bayerOrder(Transform t) const +{ + /* Return a defined by meaningless value for non-Bayer sensors. */ + if (!bayerFormat_) + return BayerFormat::Order::BGGR; + + if (!flipsAlterBayerOrder_) + return bayerFormat_->order; + + /* + * Apply the transform to the native (i.e. untransformed) Bayer order, + * using the rest of the Bayer format supplied by the caller. + */ + return bayerFormat_->transform(t).order; +} + +const ControlInfoMap &CameraSensorLegacy::controls() const +{ + return subdev_->controls(); +} + +ControlList CameraSensorLegacy::getControls(const std::vector &ids) +{ + return subdev_->getControls(ids); +} + +int CameraSensorLegacy::setControls(ControlList *ctrls) +{ + return subdev_->setControls(ctrls); +} + +int CameraSensorLegacy::setTestPatternMode(controls::draft::TestPatternModeEnum mode) +{ + if (testPatternMode_ == mode) + return 0; + + if (testPatternModes_.empty()) { + LOG(CameraSensor, Error) + << "Camera sensor does not support test pattern modes."; + return -EINVAL; + } + + return applyTestPatternMode(mode); +} + +int CameraSensorLegacy::applyTestPatternMode(controls::draft::TestPatternModeEnum mode) +{ + if (testPatternModes_.empty()) + return 0; + + auto it = std::find(testPatternModes_.begin(), testPatternModes_.end(), + mode); + if (it == testPatternModes_.end()) { + LOG(CameraSensor, Error) << "Unsupported test pattern mode " + << mode; + return -EINVAL; + } + + LOG(CameraSensor, Debug) << "Apply test pattern mode " << mode; + + int32_t index = staticProps_->testPatternModes.at(mode); + ControlList ctrls{ controls() }; + ctrls.set(V4L2_CID_TEST_PATTERN, index); + + int ret = setControls(&ctrls); + if (ret) + return ret; + + testPatternMode_ = mode; + + return 0; +} + +std::string CameraSensorLegacy::logPrefix() const +{ + return "'" + entity_->name() + "'"; +} + +REGISTER_CAMERA_SENSOR(CameraSensorLegacy) + +} /* namespace libcamera */ diff --git a/src/libcamera/sensor/meson.build b/src/libcamera/sensor/meson.build index bf4b131a94b1..e83020fc22c3 100644 --- a/src/libcamera/sensor/meson.build +++ b/src/libcamera/sensor/meson.build @@ -2,5 +2,6 @@ libcamera_sources += files([ 'camera_sensor.cpp', + 'camera_sensor_legacy.cpp', 'camera_sensor_properties.cpp', ]) From patchwork Fri Mar 1 21:21:10 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 19612 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id B0ADFBD160 for ; Fri, 1 Mar 2024 21:21:53 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 678E862C82; Fri, 1 Mar 2024 22:21:53 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="vZNL0+Wr"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C58E6628AC for ; Fri, 1 Mar 2024 22:21:50 +0100 (CET) Received: from pendragon.ideasonboard.com (89-27-53-110.bb.dnainternet.fi [89.27.53.110]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 5E882293D; Fri, 1 Mar 2024 22:21:36 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1709328096; bh=HTen9yhdwhNj3A4+larhQckfxT8mZx8SBdgV+NXMWkY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=vZNL0+WrW3Eoy+VW4s8eXtxUawTzl3KdWrIK4gRuiNkBxHJN/qoxBVNbqZT8UgTAb yFM33iIukXHqDDCko0g5TRZGgXjzNYPkkA8XpBy/QEJ6G+zKuB1AAuw60x2KaZ2I9b KFJa6K9auV+XPqqTrjELTwaCeuJNshQerHjEmYLI= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH/RFC 21/32] libcamera: camera_sensor: Sort factories by priority Date: Fri, 1 Mar 2024 23:21:10 +0200 Message-ID: <20240301212121.9072-22-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> References: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sakari Ailus Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" In order to support a default implementation for camera sensors when no better implementation matches, libcamera needs to try "specialized" implementations first and pick the default last. Make this possible by adding a priority value for factories. Newly registered factories are inserted in the factories list sorted by descending priority, and the default factory uses a negative priority to be inserted as the last element. This mechanism may be a bit overkill in the sense that there is no expected use cases for priorities other than trying the default last, but the implementation is simple and easy to understand. Signed-off-by: Laurent Pinchart Reviewed-by: Stefan Klug --- include/libcamera/internal/camera_sensor.h | 18 +++++++--- src/libcamera/sensor/camera_sensor.cpp | 34 +++++++++++++++++-- src/libcamera/sensor/camera_sensor_legacy.cpp | 2 +- 3 files changed, 45 insertions(+), 9 deletions(-) diff --git a/include/libcamera/internal/camera_sensor.h b/include/libcamera/internal/camera_sensor.h index d37e66773195..59785ff62019 100644 --- a/include/libcamera/internal/camera_sensor.h +++ b/include/libcamera/internal/camera_sensor.h @@ -79,11 +79,13 @@ public: class CameraSensorFactoryBase { public: - CameraSensorFactoryBase(); + CameraSensorFactoryBase(int priority); virtual ~CameraSensorFactoryBase() = default; static std::unique_ptr create(MediaEntity *entity); + int priority() const { return priority_; } + private: LIBCAMERA_DISABLE_COPY_AND_MOVE(CameraSensorFactoryBase) @@ -93,14 +95,16 @@ private: virtual std::variant, int> match(MediaEntity *entity) const = 0; + + int priority_; }; template class CameraSensorFactory final : public CameraSensorFactoryBase { public: - CameraSensorFactory() - : CameraSensorFactoryBase() + CameraSensorFactory(int priority = 0) + : CameraSensorFactoryBase(priority) { } @@ -112,7 +116,11 @@ private: } }; -#define REGISTER_CAMERA_SENSOR(sensor) \ - static CameraSensorFactory global_##sensor##Factory{}; +#ifndef __DOXYGEN__ +#define REGISTER_CAMERA_SENSOR(sensor, ...) \ + static CameraSensorFactory global_##sensor##Factory{ __VA_ARGS__ }; +#else +#define REGISTER_CAMERA_SENSOR(sensor, priority) +#endif } /* namespace libcamera */ diff --git a/src/libcamera/sensor/camera_sensor.cpp b/src/libcamera/sensor/camera_sensor.cpp index 7abbe2c76596..e7b526c2f050 100644 --- a/src/libcamera/sensor/camera_sensor.cpp +++ b/src/libcamera/sensor/camera_sensor.cpp @@ -348,11 +348,13 @@ CameraSensor::~CameraSensor() = default; /** * \brief Construct a camera sensor factory base + * \param[in] priority Priority order for factory selection * * Creating an instance of the factory base registers it with the global list of * factories, accessible through the factories() function. */ -CameraSensorFactoryBase::CameraSensorFactoryBase() +CameraSensorFactoryBase::CameraSensorFactoryBase(int priority) + : priority_(priority) { registerFactory(this); } @@ -361,6 +363,12 @@ CameraSensorFactoryBase::CameraSensorFactoryBase() * \brief Create an instance of the CameraSensor corresponding to a media entity * \param[in] entity The media entity on the source end of the sensor * + * When multiple factories match the same \a entity, this function selects the + * matching factory with the highest priority as specified to the + * REGISTER_CAMERA_SENSOR() macro at factory registration time. If multiple + * matching factories have the same highest priority value, which factory gets + * selected is undefined and may vary between runs. + * * \return A unique pointer to a new instance of the CameraSensor subclass * matching the entity, or a null pointer if no such factory exists */ @@ -387,8 +395,17 @@ std::unique_ptr CameraSensorFactoryBase::create(MediaEntity *entit return nullptr; } +/** + * \fn CameraSensorFactoryBase::priority() + * \brief Retrieve the priority value for the factory + * \return The priority value for the factory + */ + /** * \brief Retrieve the list of all camera sensor factories + * + * The factories are sorted in decreasing priority order. + * * \return The list of camera sensor factories */ std::vector &CameraSensorFactoryBase::factories() @@ -411,7 +428,12 @@ void CameraSensorFactoryBase::registerFactory(CameraSensorFactoryBase *factory) std::vector &factories = CameraSensorFactoryBase::factories(); - factories.push_back(factory); + auto pos = std::upper_bound(factories.begin(), factories.end(), factory, + [](const CameraSensorFactoryBase *value, + const CameraSensorFactoryBase *elem) { + return value->priority() > elem->priority(); + }); + factories.insert(pos, factory); } /** @@ -437,9 +459,10 @@ void CameraSensorFactoryBase::registerFactory(CameraSensorFactoryBase *factory) */ /** - * \def REGISTER_CAMERA_SENSOR(sensor) + * \def REGISTER_CAMERA_SENSOR(sensor, priority) * \brief Register a camera sensor type to the sensor factory * \param[in] sensor Class name of the CameraSensor derived class to register + * \param[in] priority Priority order for factory selection * * Register a CameraSensor subclass with the factory and make it available to * try and match sensors. The subclass needs to implement a static match @@ -457,6 +480,11 @@ void CameraSensorFactoryBase::registerFactory(CameraSensorFactoryBase *factory) * creation succeeded ; * - A non-zero error code if the entity matched and the creation failed ; or * - A zero error code if the entity didn't match. + * + * When multiple factories can support the same MediaEntity (as in the match() + * function of multiple factories returning true for the same entity), the \a + * priority argument selects which factory will be used. See + * CameraSensorFactoryBase::create() for more information. */ } /* namespace libcamera */ diff --git a/src/libcamera/sensor/camera_sensor_legacy.cpp b/src/libcamera/sensor/camera_sensor_legacy.cpp index 34677339241c..f9f889a125d0 100644 --- a/src/libcamera/sensor/camera_sensor_legacy.cpp +++ b/src/libcamera/sensor/camera_sensor_legacy.cpp @@ -1010,6 +1010,6 @@ std::string CameraSensorLegacy::logPrefix() const return "'" + entity_->name() + "'"; } -REGISTER_CAMERA_SENSOR(CameraSensorLegacy) +REGISTER_CAMERA_SENSOR(CameraSensorLegacy, -100) } /* namespace libcamera */ From patchwork Fri Mar 1 21:21:11 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 19613 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 386BCC3260 for ; Fri, 1 Mar 2024 21:21:54 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id E530E62B3D; Fri, 1 Mar 2024 22:21:53 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="RZz7azGr"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 439D562B3D for ; Fri, 1 Mar 2024 22:21:52 +0100 (CET) Received: from pendragon.ideasonboard.com (89-27-53-110.bb.dnainternet.fi [89.27.53.110]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id AF17F22D9; Fri, 1 Mar 2024 22:21:37 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1709328098; bh=O3EE092agBxtGk7CBnCOEuUDgYBoKpScBBIwx3lgwos=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=RZz7azGrN/p10L2TABDTfZNjIbhnExiRe+iQBtMvk1BWsg98yBUxpTMXKLZrLXnb7 +e/30ORmMtC1JEEqbsC3wqQAq8B78yrIlBwQ9Ena0S7AnM70YUgfienzDfuCOHRfYu scIf/K1s21pH2jB70vhanSVCEBoNzyvW4oBcmNUk= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH/RFC 22/32] libcamera: Add CameraSensor implementation for raw V4L2 sensors Date: Fri, 1 Mar 2024 23:21:11 +0200 Message-ID: <20240301212121.9072-23-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> References: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sakari Ailus Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add a new CameraSensorRaw implementation of the CameraSensor interface tailored to devices that implement the new V4L2 raw camera sensors API. This new class duplicates code from the CameraSensorLegacy class. The two classes will be refactored to share code. Signed-off-by: Laurent Pinchart --- Documentation/Doxyfile.in | 1 + src/libcamera/sensor/camera_sensor_raw.cpp | 1063 ++++++++++++++++++++ src/libcamera/sensor/meson.build | 1 + 3 files changed, 1065 insertions(+) create mode 100644 src/libcamera/sensor/camera_sensor_raw.cpp diff --git a/Documentation/Doxyfile.in b/Documentation/Doxyfile.in index 75326c1964e9..8bc55be60a59 100644 --- a/Documentation/Doxyfile.in +++ b/Documentation/Doxyfile.in @@ -43,6 +43,7 @@ EXCLUDE = @TOP_SRCDIR@/include/libcamera/base/span.h \ @TOP_SRCDIR@/src/libcamera/ipc_pipe_unixsocket.cpp \ @TOP_SRCDIR@/src/libcamera/pipeline/ \ @TOP_SRCDIR@/src/libcamera/sensor/camera_sensor_legacy.cpp \ + @TOP_SRCDIR@/src/libcamera/sensor/camera_sensor_raw.cpp \ @TOP_SRCDIR@/src/libcamera/tracepoints.cpp \ @TOP_BUILDDIR@/include/libcamera/internal/tracepoints.h \ @TOP_BUILDDIR@/src/libcamera/proxy/ diff --git a/src/libcamera/sensor/camera_sensor_raw.cpp b/src/libcamera/sensor/camera_sensor_raw.cpp new file mode 100644 index 000000000000..8c17da5876a4 --- /dev/null +++ b/src/libcamera/sensor/camera_sensor_raw.cpp @@ -0,0 +1,1063 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2024, Ideas on Board Oy. + * + * camera_sensor_raw.cpp - A raw camera sensor using the V4L2 streams API + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "libcamera/internal/bayer_format.h" +#include "libcamera/internal/camera_lens.h" +#include "libcamera/internal/camera_sensor.h" +#include "libcamera/internal/camera_sensor_properties.h" +#include "libcamera/internal/formats.h" +#include "libcamera/internal/media_device.h" +#include "libcamera/internal/sysfs.h" +#include "libcamera/internal/v4l2_subdevice.h" + +namespace libcamera { + +class BayerFormat; +class CameraLens; +class MediaEntity; +class SensorConfiguration; + +struct CameraSensorProperties; + +enum class Orientation; + +LOG_DECLARE_CATEGORY(CameraSensor) + +class CameraSensorRaw : public CameraSensor, protected Loggable +{ +public: + CameraSensorRaw(const MediaEntity *entity); + ~CameraSensorRaw(); + + static std::variant, int> + match(MediaEntity *entity); + + const std::string &model() const override { return model_; } + const std::string &id() const override { return id_; } + + const MediaEntity *entity() const override { return entity_; } + V4L2Subdevice *device() override { return subdev_.get(); } + + CameraLens *focusLens() override { return focusLens_.get(); } + + const std::vector &mbusCodes() const override { return mbusCodes_; } + std::vector sizes(unsigned int mbusCode) const override; + Size resolution() const override; + + V4L2SubdeviceFormat getFormat(const std::vector &mbusCodes, + const Size &size) const override; + int setFormat(V4L2SubdeviceFormat *format, + Transform transform = Transform::Identity) override; + int tryFormat(V4L2SubdeviceFormat *format) const override; + + int applyConfiguration(const SensorConfiguration &config, + Transform transform = Transform::Identity, + V4L2SubdeviceFormat *sensorFormat = nullptr) override; + + const ControlList &properties() const override { return properties_; } + int sensorInfo(IPACameraSensorInfo *info) const override; + Transform computeTransform(Orientation *orientation) const override; + BayerFormat::Order bayerOrder(Transform t) const override; + + const ControlInfoMap &controls() const override; + ControlList getControls(const std::vector &ids) override; + int setControls(ControlList *ctrls) override; + + const std::vector & + testPatternModes() const override { return testPatternModes_; } + int setTestPatternMode(controls::draft::TestPatternModeEnum mode) override; + +protected: + std::string logPrefix() const override; + +private: + LIBCAMERA_DISABLE_COPY(CameraSensorRaw) + + std::optional init(); + int initProperties(); + void initStaticProperties(); + void initTestPatternModes(); + int applyTestPatternMode(controls::draft::TestPatternModeEnum mode); + + const MediaEntity *entity_; + std::unique_ptr subdev_; + + struct Streams { + V4L2Subdevice::Stream sink; + V4L2Subdevice::Stream source; + }; + + struct { + Streams image; + std::optional edata; + } streams_; + + const CameraSensorProperties *staticProps_; + + std::string model_; + std::string id_; + + V4L2Subdevice::Formats formats_; + std::vector mbusCodes_; + std::vector sizes_; + std::vector testPatternModes_; + controls::draft::TestPatternModeEnum testPatternMode_; + + Size pixelArraySize_; + Rectangle activeArea_; + BayerFormat::Order cfaPattern_; + bool supportFlips_; + bool flipsAlterBayerOrder_; + Orientation mountingOrientation_; + + ControlList properties_; + + std::unique_ptr focusLens_; +}; + +/** + * \class CameraSensorRaw + * \brief A camera sensor based on V4L2 subdevices + * + * This class supports single-subdev sensors with a single source pad and one + * or two internal sink pads (for the image and embedded data streams). + */ + +CameraSensorRaw::CameraSensorRaw(const MediaEntity *entity) + : entity_(entity), staticProps_(nullptr), supportFlips_(false), + flipsAlterBayerOrder_(false), properties_(properties::properties) +{ +} + +CameraSensorRaw::~CameraSensorRaw() = default; + +std::variant, int> +CameraSensorRaw::match(MediaEntity *entity) +{ + /* Check the entity type. */ + if (entity->type() != MediaEntity::Type::V4L2Subdevice || + entity->function() != MEDIA_ENT_F_CAM_SENSOR) { + libcamera::LOG(CameraSensor, Debug) + << entity->name() << ": unsupported entity type (" + << utils::to_underlying(entity->type()) + << ") or function (" << utils::hex(entity->function()) << ")"; + return { 0 }; + } + + /* Count and check the number of pads. */ + static constexpr uint32_t kPadFlagsMask = MEDIA_PAD_FL_SINK + | MEDIA_PAD_FL_SOURCE + | MEDIA_PAD_FL_INTERNAL; + unsigned int numSinks = 0; + unsigned int numSources = 0; + + for (const MediaPad *pad : entity->pads()) { + switch (pad->flags() & kPadFlagsMask) { + case MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_INTERNAL: + numSinks++; + break; + + case MEDIA_PAD_FL_SOURCE: + numSources++; + break; + + default: + libcamera::LOG(CameraSensor, Debug) + << entity->name() << ": unsupported pad " << pad->index() + << " type " << utils::hex(pad->flags()); + return { 0 }; + } + } + + if (numSinks < 1 || numSinks > 2 || numSources != 1) { + libcamera::LOG(CameraSensor, Debug) + << entity->name() << ": unsupported number of sinks (" + << numSinks << ") or sources (" << numSources << ")"; + return { 0 }; + } + + /* + * The entity matches. Create the camera sensor and initialize it. The + * init() function will perform further match checks. + */ + std::unique_ptr sensor = + std::make_unique(entity); + + std::optional err = sensor->init(); + if (err) + return { *err }; + + return { std::move(sensor) }; +} + +std::optional CameraSensorRaw::init() +{ + /* Create and open the subdev. */ + subdev_ = std::make_unique(entity_); + int ret = subdev_->open(); + if (ret) + return { ret }; + + /* + * 1. Identify the pads. + */ + + /* + * First locate the source pad. The match() function guarantees there + * is one and only one source pad. + */ + unsigned int sourcePad = UINT_MAX; + + for (const MediaPad *pad : entity_->pads()) { + if (pad->flags() & MEDIA_PAD_FL_SOURCE) { + sourcePad = pad->index(); + break; + } + } + + /* + * Iterate over the routes to identify the streams on the source pad, + * and the internal sink pads. + */ + V4L2Subdevice::Routing routing = {}; + ret = subdev_->getRouting(&routing, V4L2Subdevice::TryFormat); + if (ret) + return { ret }; + + bool imageStreamFound = false; + + for (const V4L2Subdevice::Route &route : routing) { + if (route.source.pad != sourcePad) { + LOG(CameraSensor, Error) << "Invalid route " << route; + return { -EINVAL }; + } + + /* Identify the stream type based on the supported formats. */ + V4L2Subdevice::Formats formats = subdev_->formats(route.source); + + std::optional type; + + for (const auto &[code, sizes] : formats) { + const MediaBusFormatInfo &info = + MediaBusFormatInfo::info(code); + if (info.isValid()) { + type = info.type; + break; + } + } + + if (!type) { + LOG(CameraSensor, Warning) + << "No known format on pad " << route.source; + continue; + } + + switch (*type) { + case MediaBusFormatInfo::Type::Image: + if (imageStreamFound) { + LOG(CameraSensor, Error) + << "Multiple internal image streams (" + << streams_.image.sink << " and " + << route.sink << ")"; + return { -EINVAL }; + } + + imageStreamFound = true; + streams_.image.sink = route.sink; + streams_.image.source = route.source; + break; + + case MediaBusFormatInfo::Type::Metadata: + /* + * Skip metadata streams that are not sensor embedded + * data. The source stream reports a generic metadata + * format, check the sink stream for the exact format. + */ + formats = subdev_->formats(route.sink); + if (formats.size() != 1) + continue; + + if (MediaBusFormatInfo::info(formats.cbegin()->first).type != + MediaBusFormatInfo::Type::EmbeddedData) + continue; + + if (streams_.edata) { + LOG(CameraSensor, Error) + << "Multiple internal embedded data streams (" + << streams_.edata->sink << " and " + << route.sink << ")"; + return { -EINVAL }; + } + + streams_.edata = { route.sink, route.source }; + break; + + default: + break; + } + } + + if (!imageStreamFound) { + LOG(CameraSensor, Error) << "No image stream found"; + return { -EINVAL }; + } + + LOG(CameraSensor, Debug) + << "Found image stream " << streams_.image.sink + << " -> " << streams_.image.source; + + if (streams_.edata) + LOG(CameraSensor, Debug) + << "Found embedded data stream " << streams_.edata->sink + << " -> " << streams_.edata->source; + + /* + * 2. Enumerate and cache the media bus codes, sizes and colour filter + * array order for the image stream. + */ + + /* + * Get the native sensor CFA pattern. It is simpler to retrieve it from + * the internal image sink pad as it is guaranteed to expose a single + * format, and is not affected by flips. + */ + V4L2Subdevice::Formats formats = subdev_->formats(streams_.image.sink); + if (formats.size() != 1) { + LOG(CameraSensor, Error) + << "Image pad has " << formats.size() + << " formats, expected 1"; + return { -EINVAL }; + } + + uint32_t nativeFormat = formats.cbegin()->first; + const BayerFormat &bayerFormat = BayerFormat::fromMbusCode(nativeFormat); + if (!bayerFormat.isValid()) { + LOG(CameraSensor, Error) + << "Invalid native format " << nativeFormat; + return { 0 }; + } + + cfaPattern_ = bayerFormat.order; + + /* + * Retrieve and cache the media bus codes and sizes on the source image + * stream. + */ + formats_ = subdev_->formats(streams_.image.source); + if (formats_.empty()) { + LOG(CameraSensor, Error) << "No image format found"; + return { -EINVAL }; + } + + /* Populate and sort the media bus codes and the sizes. */ + for (const auto &[code, ranges] : formats_) { + /* Drop non-raw formats (in case we have a hybrid sensor). */ + const MediaBusFormatInfo &info = MediaBusFormatInfo::info(code); + if (info.colourEncoding != PixelFormatInfo::ColourEncodingRAW) + continue; + + mbusCodes_.push_back(code); + std::transform(ranges.begin(), ranges.end(), std::back_inserter(sizes_), + [](const SizeRange &range) { return range.max; }); + } + + if (mbusCodes_.empty()) { + LOG(CameraSensor, Debug) << "No raw image formats found"; + return { 0 }; + } + + std::sort(mbusCodes_.begin(), mbusCodes_.end()); + std::sort(sizes_.begin(), sizes_.end()); + + /* + * Remove duplicate sizes. There are no duplicate media bus codes as + * they are the keys in the formats map. + */ + auto last = std::unique(sizes_.begin(), sizes_.end()); + sizes_.erase(last, sizes_.end()); + + /* + * 3. Query selection rectangles. Retrieve properties, and verify that + * all the expected selection rectangles are supported. + */ + + Rectangle rect; + ret = subdev_->getSelection(streams_.image.sink, V4L2_SEL_TGT_CROP_BOUNDS, + &rect); + if (ret) { + LOG(CameraSensor, Error) << "No pixel array crop bounds"; + return { ret }; + } + + pixelArraySize_ = rect.size(); + + ret = subdev_->getSelection(streams_.image.sink, V4L2_SEL_TGT_CROP_DEFAULT, + &activeArea_); + if (ret) { + LOG(CameraSensor, Error) << "No pixel array crop default"; + return { ret }; + } + + ret = subdev_->getSelection(streams_.image.sink, V4L2_SEL_TGT_CROP, + &rect); + if (ret) { + LOG(CameraSensor, Error) << "No pixel array crop rectangle"; + return { ret }; + } + + /* + * 4. Verify that all required controls are present. + */ + + const ControlIdMap &controls = subdev_->controls().idmap(); + + static constexpr uint32_t mandatoryControls[] = { + V4L2_CID_ANALOGUE_GAIN, + V4L2_CID_CAMERA_ORIENTATION, + V4L2_CID_EXPOSURE, + V4L2_CID_HBLANK, + V4L2_CID_PIXEL_RATE, + V4L2_CID_VBLANK, + }; + + ret = 0; + + for (uint32_t ctrl : mandatoryControls) { + if (!controls.count(ctrl)) { + LOG(CameraSensor, Error) + << "Mandatory V4L2 control " << utils::hex(ctrl) + << " not available"; + ret = -EINVAL; + } + } + + if (ret) { + LOG(CameraSensor, Error) + << "The sensor kernel driver needs to be fixed"; + LOG(CameraSensor, Error) + << "See Documentation/sensor_driver_requirements.rst in the libcamera sources for more information"; + return { ret }; + } + + /* + * Verify if sensor supports horizontal/vertical flips + * + * \todo Handle horizontal and vertical flips independently. + */ + const struct v4l2_query_ext_ctrl *hflipInfo = subdev_->controlInfo(V4L2_CID_HFLIP); + const struct v4l2_query_ext_ctrl *vflipInfo = subdev_->controlInfo(V4L2_CID_VFLIP); + if (hflipInfo && !(hflipInfo->flags & V4L2_CTRL_FLAG_READ_ONLY) && + vflipInfo && !(vflipInfo->flags & V4L2_CTRL_FLAG_READ_ONLY)) + supportFlips_ = true; + + if (!supportFlips_) + LOG(CameraSensor, Debug) + << "Camera sensor does not support horizontal/vertical flip"; + + /* + * 5. Discover ancillary devices. + * + * \todo This code may be shared by different V4L2 sensor classes. + */ + for (MediaEntity *ancillary : entity_->ancillaryEntities()) { + switch (ancillary->function()) { + case MEDIA_ENT_F_LENS: + focusLens_ = std::make_unique(ancillary); + ret = focusLens_->init(); + if (ret) { + LOG(CameraSensor, Error) + << "Lens initialisation failed, lens disabled"; + focusLens_.reset(); + } + break; + + default: + LOG(CameraSensor, Warning) + << "Unsupported ancillary entity function " + << ancillary->function(); + break; + } + } + + /* + * 6. Initialize properties. + */ + + ret = initProperties(); + if (ret) + return { ret }; + + /* + * 7. Initialize controls. + */ + + /* + * Set HBLANK to the minimum to start with a well-defined line length, + * allowing IPA modules that do not modify HBLANK to use the sensor + * minimum line length in their calculations. + * + * At present, there is no way of knowing if a control is read-only. + * As a workaround, assume that if the minimum and maximum values of + * the V4L2_CID_HBLANK control are the same, it implies the control + * is read-only. + * + * \todo The control API ought to have a flag to specify if a control + * is read-only which could be used below. + */ + const ControlInfoMap &ctrls = subdev_->controls(); + if (ctrls.find(V4L2_CID_HBLANK) != ctrls.end()) { + const ControlInfo hblank = ctrls.at(V4L2_CID_HBLANK); + const int32_t hblankMin = hblank.min().get(); + const int32_t hblankMax = hblank.max().get(); + + if (hblankMin != hblankMax) { + ControlList ctrl(subdev_->controls()); + + ctrl.set(V4L2_CID_HBLANK, hblankMin); + ret = subdev_->setControls(&ctrl); + if (ret) + return { ret }; + } + } + + ret = applyTestPatternMode(controls::draft::TestPatternModeEnum::TestPatternModeOff); + if (ret) + return { ret }; + + return {}; +} + +int CameraSensorRaw::initProperties() +{ + model_ = subdev_->model(); + properties_.set(properties::Model, utils::toAscii(model_)); + + /* Generate a unique ID for the sensor. */ + id_ = sysfs::firmwareNodePath(subdev_->devicePath()); + if (id_.empty()) { + LOG(CameraSensor, Error) << "Can't generate sensor ID"; + return -EINVAL; + } + + /* Initialize the static properties from the sensor database. */ + initStaticProperties(); + + /* Retrieve and register properties from the kernel interface. */ + const ControlInfoMap &controls = subdev_->controls(); + + const auto &orientation = controls.find(V4L2_CID_CAMERA_ORIENTATION); + if (orientation != controls.end()) { + int32_t v4l2Orientation = orientation->second.def().get(); + int32_t propertyValue; + + switch (v4l2Orientation) { + default: + LOG(CameraSensor, Warning) + << "Unsupported camera location " + << v4l2Orientation << ", setting to External"; + [[fallthrough]]; + case V4L2_CAMERA_ORIENTATION_EXTERNAL: + propertyValue = properties::CameraLocationExternal; + break; + case V4L2_CAMERA_ORIENTATION_FRONT: + propertyValue = properties::CameraLocationFront; + break; + case V4L2_CAMERA_ORIENTATION_BACK: + propertyValue = properties::CameraLocationBack; + break; + } + properties_.set(properties::Location, propertyValue); + } else { + LOG(CameraSensor, Warning) << "Failed to retrieve the camera location"; + } + + const auto &rotationControl = controls.find(V4L2_CID_CAMERA_SENSOR_ROTATION); + if (rotationControl != controls.end()) { + int32_t propertyValue = rotationControl->second.def().get(); + + /* + * Cache the Transform associated with the camera mounting + * rotation for later use in computeTransform(). + */ + bool success; + mountingOrientation_ = orientationFromRotation(propertyValue, &success); + if (!success) { + LOG(CameraSensor, Warning) + << "Invalid rotation of " << propertyValue + << " degrees - ignoring"; + mountingOrientation_ = Orientation::Rotate0; + } + + properties_.set(properties::Rotation, propertyValue); + } else { + LOG(CameraSensor, Warning) + << "Rotation control not available, default to 0 degrees"; + properties_.set(properties::Rotation, 0); + mountingOrientation_ = Orientation::Rotate0; + } + + properties_.set(properties::PixelArraySize, pixelArraySize_); + properties_.set(properties::PixelArrayActiveAreas, { activeArea_ }); + + /* Color filter array pattern. */ + uint32_t cfa; + + switch (cfaPattern_) { + case BayerFormat::BGGR: + cfa = properties::draft::BGGR; + break; + case BayerFormat::GBRG: + cfa = properties::draft::GBRG; + break; + case BayerFormat::GRBG: + cfa = properties::draft::GRBG; + break; + case BayerFormat::RGGB: + cfa = properties::draft::RGGB; + break; + case BayerFormat::MONO: + cfa = properties::draft::MONO; + break; + } + + properties_.set(properties::draft::ColorFilterArrangement, cfa); + + return 0; +} + +void CameraSensorRaw::initStaticProperties() +{ + staticProps_ = CameraSensorProperties::get(model_); + if (!staticProps_) + return; + + /* Register the properties retrieved from the sensor database. */ + properties_.set(properties::UnitCellSize, staticProps_->unitCellSize); + + initTestPatternModes(); +} + +void CameraSensorRaw::initTestPatternModes() +{ + const auto &v4l2TestPattern = controls().find(V4L2_CID_TEST_PATTERN); + if (v4l2TestPattern == controls().end()) { + LOG(CameraSensor, Debug) << "V4L2_CID_TEST_PATTERN is not supported"; + return; + } + + const auto &testPatternModes = staticProps_->testPatternModes; + if (testPatternModes.empty()) { + /* + * The camera sensor supports test patterns but we don't know + * how to map them so this should be fixed. + */ + LOG(CameraSensor, Debug) << "No static test pattern map for \'" + << model() << "\'"; + return; + } + + /* + * Create a map that associates the V4L2 control index to the test + * pattern mode by reversing the testPatternModes map provided by the + * camera sensor properties. This makes it easier to verify if the + * control index is supported in the below for loop that creates the + * list of supported test patterns. + */ + std::map indexToTestPatternMode; + for (const auto &it : testPatternModes) + indexToTestPatternMode[it.second] = it.first; + + for (const ControlValue &value : v4l2TestPattern->second.values()) { + const int32_t index = value.get(); + + const auto it = indexToTestPatternMode.find(index); + if (it == indexToTestPatternMode.end()) { + LOG(CameraSensor, Debug) + << "Test pattern mode " << index << " ignored"; + continue; + } + + testPatternModes_.push_back(it->second); + } +} + +std::vector CameraSensorRaw::sizes(unsigned int mbusCode) const +{ + std::vector sizes; + + const auto &format = formats_.find(mbusCode); + if (format == formats_.end()) + return sizes; + + const std::vector &ranges = format->second; + std::transform(ranges.begin(), ranges.end(), std::back_inserter(sizes), + [](const SizeRange &range) { return range.max; }); + + std::sort(sizes.begin(), sizes.end()); + + return sizes; +} + +Size CameraSensorRaw::resolution() const +{ + return std::min(sizes_.back(), activeArea_.size()); +} + +V4L2SubdeviceFormat +CameraSensorRaw::getFormat(const std::vector &mbusCodes, + const Size &size) const +{ + unsigned int desiredArea = size.width * size.height; + unsigned int bestArea = UINT_MAX; + float desiredRatio = static_cast(size.width) / size.height; + float bestRatio = FLT_MAX; + const Size *bestSize = nullptr; + uint32_t bestCode = 0; + + for (unsigned int code : mbusCodes) { + const auto formats = formats_.find(code); + if (formats == formats_.end()) + continue; + + for (const SizeRange &range : formats->second) { + const Size &sz = range.max; + + if (sz.width < size.width || sz.height < size.height) + continue; + + float ratio = static_cast(sz.width) / sz.height; + float ratioDiff = fabsf(ratio - desiredRatio); + unsigned int area = sz.width * sz.height; + unsigned int areaDiff = area - desiredArea; + + if (ratioDiff > bestRatio) + continue; + + if (ratioDiff < bestRatio || areaDiff < bestArea) { + bestRatio = ratioDiff; + bestArea = areaDiff; + bestSize = &sz; + bestCode = code; + } + } + } + + if (!bestSize) { + LOG(CameraSensor, Debug) << "No supported format or size found"; + return {}; + } + + V4L2SubdeviceFormat format{ + .code = bestCode, + .size = *bestSize, + .colorSpace = ColorSpace::Raw, + }; + + return format; +} + +int CameraSensorRaw::setFormat(V4L2SubdeviceFormat *format, Transform transform) +{ + /* Configure flips if the sensor supports that. */ + if (supportFlips_) { + ControlList flipCtrls(subdev_->controls()); + + flipCtrls.set(V4L2_CID_HFLIP, + static_cast(!!(transform & Transform::HFlip))); + flipCtrls.set(V4L2_CID_VFLIP, + static_cast(!!(transform & Transform::VFlip))); + + int ret = subdev_->setControls(&flipCtrls); + if (ret) + return ret; + } + + /* Apply format on the subdev. */ + int ret = subdev_->setFormat(streams_.image.source, format); + if (ret) + return ret; + + subdev_->updateControlInfo(); + return 0; +} + +int CameraSensorRaw::tryFormat(V4L2SubdeviceFormat *format) const +{ + return subdev_->setFormat(streams_.image.source, format, + V4L2Subdevice::Whence::TryFormat); +} + +int CameraSensorRaw::applyConfiguration(const SensorConfiguration &config, + Transform transform, + V4L2SubdeviceFormat *sensorFormat) +{ + if (!config.isValid()) { + LOG(CameraSensor, Error) << "Invalid sensor configuration"; + return -EINVAL; + } + + std::vector filteredCodes; + std::copy_if(mbusCodes_.begin(), mbusCodes_.end(), + std::back_inserter(filteredCodes), + [&config](unsigned int mbusCode) { + BayerFormat bayer = BayerFormat::fromMbusCode(mbusCode); + if (bayer.bitDepth == config.bitDepth) + return true; + return false; + }); + if (filteredCodes.empty()) { + LOG(CameraSensor, Error) + << "Cannot find any format with bit depth " + << config.bitDepth; + return -EINVAL; + } + + /* + * Compute the sensor's data frame size by applying the cropping + * rectangle, subsampling and output crop to the sensor's pixel array + * size. + * + * \todo The actual size computation is for now ignored and only the + * output size is considered. This implies that resolutions obtained + * with two different cropping/subsampling will look identical and + * only the first found one will be considered. + */ + V4L2SubdeviceFormat subdevFormat = {}; + for (unsigned int code : filteredCodes) { + for (const Size &size : sizes(code)) { + if (size.width != config.outputSize.width || + size.height != config.outputSize.height) + continue; + + subdevFormat.code = code; + subdevFormat.size = size; + break; + } + } + if (!subdevFormat.code) { + LOG(CameraSensor, Error) << "Invalid output size in sensor configuration"; + return -EINVAL; + } + + int ret = setFormat(&subdevFormat, transform); + if (ret) + return ret; + + /* + * Return to the caller the format actually applied to the sensor. + * This is relevant if transform has changed the bayer pattern order. + */ + if (sensorFormat) + *sensorFormat = subdevFormat; + + /* \todo Handle AnalogCrop. Most sensors do not support set_selection */ + /* \todo Handle scaling in the digital domain. */ + + return 0; +} + +int CameraSensorRaw::sensorInfo(IPACameraSensorInfo *info) const +{ + info->model = model(); + + /* + * The active area size is a static property, while the crop + * rectangle needs to be re-read as it depends on the sensor + * configuration. + */ + info->activeAreaSize = { activeArea_.width, activeArea_.height }; + + int ret = subdev_->getSelection(streams_.image.sink, V4L2_SEL_TGT_CROP, + &info->analogCrop); + if (ret) + return ret; + + /* + * IPACameraSensorInfo::analogCrop::x and IPACameraSensorInfo::analogCrop::y + * are defined relatively to the active pixel area, while V4L2's + * TGT_CROP target is defined in respect to the full pixel array. + * + * Compensate it by subtracting the active area offset. + */ + info->analogCrop.x -= activeArea_.x; + info->analogCrop.y -= activeArea_.y; + + /* The bit depth and image size depend on the currently applied format. */ + V4L2SubdeviceFormat format{}; + ret = subdev_->getFormat(streams_.image.source, &format); + if (ret) + return ret; + info->bitsPerPixel = MediaBusFormatInfo::info(format.code).bitsPerPixel; + info->outputSize = format.size; + + std::optional cfa = properties_.get(properties::draft::ColorFilterArrangement); + info->cfaPattern = cfa ? *cfa : properties::draft::RGB; + + /* + * Retrieve the pixel rate, line length and minimum/maximum frame + * duration through V4L2 controls. Support for the V4L2_CID_PIXEL_RATE, + * V4L2_CID_HBLANK and V4L2_CID_VBLANK controls is mandatory. + */ + ControlList ctrls = subdev_->getControls({ V4L2_CID_PIXEL_RATE, + V4L2_CID_HBLANK, + V4L2_CID_VBLANK }); + if (ctrls.empty()) { + LOG(CameraSensor, Error) + << "Failed to retrieve camera info controls"; + return -EINVAL; + } + + info->pixelRate = ctrls.get(V4L2_CID_PIXEL_RATE).get(); + + const ControlInfo hblank = ctrls.infoMap()->at(V4L2_CID_HBLANK); + info->minLineLength = info->outputSize.width + hblank.min().get(); + info->maxLineLength = info->outputSize.width + hblank.max().get(); + + const ControlInfo vblank = ctrls.infoMap()->at(V4L2_CID_VBLANK); + info->minFrameLength = info->outputSize.height + vblank.min().get(); + info->maxFrameLength = info->outputSize.height + vblank.max().get(); + + return 0; +} + +Transform CameraSensorRaw::computeTransform(Orientation *orientation) const +{ + /* + * If we cannot do any flips we cannot change the native camera mounting + * orientation. + */ + if (!supportFlips_) { + *orientation = mountingOrientation_; + return Transform::Identity; + } + + /* + * Now compute the required transform to obtain 'orientation' starting + * from the mounting rotation. + * + * As a note: + * orientation / mountingOrientation_ = transform + * mountingOrientation_ * transform = orientation + */ + Transform transform = *orientation / mountingOrientation_; + + /* + * If transform contains any Transpose we cannot do it, so adjust + * 'orientation' to report the image native orientation and return Identity. + */ + if (!!(transform & Transform::Transpose)) { + *orientation = mountingOrientation_; + return Transform::Identity; + } + + return transform; +} + +BayerFormat::Order CameraSensorRaw::bayerOrder(Transform t) const +{ + if (!flipsAlterBayerOrder_) + return cfaPattern_; + + /* + * Apply the transform to the native (i.e. untransformed) Bayer order, + * using the rest of the Bayer format supplied by the caller. + */ + BayerFormat format{ cfaPattern_, 8, BayerFormat::Packing::None }; + return format.transform(t).order; +} + +const ControlInfoMap &CameraSensorRaw::controls() const +{ + return subdev_->controls(); +} + +ControlList CameraSensorRaw::getControls(const std::vector &ids) +{ + return subdev_->getControls(ids); +} + +int CameraSensorRaw::setControls(ControlList *ctrls) +{ + return subdev_->setControls(ctrls); +} + +int CameraSensorRaw::setTestPatternMode(controls::draft::TestPatternModeEnum mode) +{ + if (testPatternMode_ == mode) + return 0; + + if (testPatternModes_.empty()) { + LOG(CameraSensor, Error) + << "Camera sensor does not support test pattern modes."; + return -EINVAL; + } + + return applyTestPatternMode(mode); +} + +int CameraSensorRaw::applyTestPatternMode(controls::draft::TestPatternModeEnum mode) +{ + if (testPatternModes_.empty()) + return 0; + + auto it = std::find(testPatternModes_.begin(), testPatternModes_.end(), + mode); + if (it == testPatternModes_.end()) { + LOG(CameraSensor, Error) << "Unsupported test pattern mode " + << mode; + return -EINVAL; + } + + LOG(CameraSensor, Debug) << "Apply test pattern mode " << mode; + + int32_t index = staticProps_->testPatternModes.at(mode); + ControlList ctrls{ controls() }; + ctrls.set(V4L2_CID_TEST_PATTERN, index); + + int ret = setControls(&ctrls); + if (ret) + return ret; + + testPatternMode_ = mode; + + return 0; +} + +std::string CameraSensorRaw::logPrefix() const +{ + return "'" + entity_->name() + "'"; +} + +REGISTER_CAMERA_SENSOR(CameraSensorRaw) + +} /* namespace libcamera */ diff --git a/src/libcamera/sensor/meson.build b/src/libcamera/sensor/meson.build index e83020fc22c3..e3c39aaf13b8 100644 --- a/src/libcamera/sensor/meson.build +++ b/src/libcamera/sensor/meson.build @@ -4,4 +4,5 @@ libcamera_sources += files([ 'camera_sensor.cpp', 'camera_sensor_legacy.cpp', 'camera_sensor_properties.cpp', + 'camera_sensor_raw.cpp', ]) From patchwork Fri Mar 1 21:21:12 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 19614 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id F222BBD160 for ; Fri, 1 Mar 2024 21:21:55 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id AB95962C8D; Fri, 1 Mar 2024 22:21:55 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="RrFAE69p"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id A6E186295D for ; Fri, 1 Mar 2024 22:21:53 +0100 (CET) Received: from pendragon.ideasonboard.com (89-27-53-110.bb.dnainternet.fi [89.27.53.110]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 2F9302D6B; Fri, 1 Mar 2024 22:21:39 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1709328099; bh=4YJ0FK29znTDgW2AkigmxM/Bwm0mgVpwSDqui6e3SqI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=RrFAE69pd/UlSXGddSUj72EdCAFeP2sEAh6dCouAsqrzVOFqh3J+5EQKHZBxa94Fy BV5EhdS48apq+xBBW4FcGj4hnAh6kuDeOS7IfgUClaQ7qVjlKXvLGB8ZSKlPK9ajfl z7+C9pBBEcOMRz1UTnW+Z7/6PkWgXPl37pP2iEeo= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH/RFC 23/32] libcamera: camera_sensor: Add support for embedded data Date: Fri, 1 Mar 2024 23:21:12 +0200 Message-ID: <20240301212121.9072-24-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> References: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sakari Ailus Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Some sensors support producing and transmitting embedded data over a stream separate from the image stream. Add support for this feature in the CameraSensor interface, and implement it for the CameraSensorRaw class. The CameraSensorLegacy uses the default stub implementation, as the corresponding kernel drivers don't support embedded data. Signed-off-by: Laurent Pinchart --- include/libcamera/internal/camera_sensor.h | 5 ++ src/libcamera/sensor/camera_sensor.cpp | 67 ++++++++++++++++++++ src/libcamera/sensor/camera_sensor_raw.cpp | 72 ++++++++++++++++++++++ 3 files changed, 144 insertions(+) diff --git a/include/libcamera/internal/camera_sensor.h b/include/libcamera/internal/camera_sensor.h index 59785ff62019..587dacfb7b4c 100644 --- a/include/libcamera/internal/camera_sensor.h +++ b/include/libcamera/internal/camera_sensor.h @@ -62,6 +62,11 @@ public: Transform transform = Transform::Identity, V4L2SubdeviceFormat *sensorFormat = nullptr) = 0; + virtual V4L2Subdevice::Stream imageStream() const; + virtual std::optional embeddedDataStream() const; + virtual V4L2SubdeviceFormat embeddedDataFormat() const; + virtual int setEmbeddedDataEnabled(bool enable); + virtual const ControlList &properties() const = 0; virtual int sensorInfo(IPACameraSensorInfo *info) const = 0; virtual Transform computeTransform(Orientation *orientation) const = 0; diff --git a/src/libcamera/sensor/camera_sensor.cpp b/src/libcamera/sensor/camera_sensor.cpp index e7b526c2f050..b4358b722cd5 100644 --- a/src/libcamera/sensor/camera_sensor.cpp +++ b/src/libcamera/sensor/camera_sensor.cpp @@ -196,6 +196,73 @@ CameraSensor::~CameraSensor() = default; * error code otherwise */ +/** + * \brief Retrieve the image source stream + * + * Sensors that produce multiple streams do not guarantee that the image stream + * is always assigned number 0. This function allows callers to retrieve the + * image stream on the sensor's source pad, in order to configure the receiving + * side accordingly. + * + * \return The image source stream + */ +V4L2Subdevice::Stream CameraSensor::imageStream() const +{ + return { 0, 0 }; +} + +/** + * \brief Retrieve the embedded data source stream + * + * Some sensors produce embedded data in a stream separate from the image + * stream. This function indicates if the sensor supports this feature by + * returning the embedded data stream on the sensor's source pad if available, + * or an std::optional<> without a value otheriwse. + * + * \return The embedded data source stream + */ +std::optional CameraSensor::embeddedDataStream() const +{ + return {}; +} + +/** + * \brief Retrieve the format on the embedded data stream + * + * When an embedded data stream is available, this function returns the + * corresponding format on the sensor's source pad. The format may vary with + * the image stream format, and should therefore be retrieved after configuring + * the image stream. + * + * If the sensor doesn't support embedded data, this function returns a + * default-constructed format. + * + * \return The format on the embedded data stream + */ +V4L2SubdeviceFormat CameraSensor::embeddedDataFormat() const +{ + return {}; +} + +/** + * \brief Enable or disable the embedded data stream + * \param[in] enable True to enable the embedded data stream, false to disable it + * + * For sensors that support embedded data, this function enables or disables + * generation of embedded data. Some of such sensors always produce embedded + * data, in which case this function return -EISCONN if the caller attempts to + * disable embedded data. + * + * If the sensor doesn't support embedded data, this function returns 0 when \a + * enable is false, and -ENOSTR otherwise. + * + * \return 0 on success, or a negative error code otherwise + */ +int CameraSensor::setEmbeddedDataEnabled(bool enable) +{ + return enable ? -ENOSTR : 0; +} + /** * \fn CameraSensor::properties() * \brief Retrieve the camera sensor properties diff --git a/src/libcamera/sensor/camera_sensor_raw.cpp b/src/libcamera/sensor/camera_sensor_raw.cpp index 8c17da5876a4..e79b31cd0bf6 100644 --- a/src/libcamera/sensor/camera_sensor_raw.cpp +++ b/src/libcamera/sensor/camera_sensor_raw.cpp @@ -84,6 +84,11 @@ public: Transform transform = Transform::Identity, V4L2SubdeviceFormat *sensorFormat = nullptr) override; + V4L2Subdevice::Stream imageStream() const override; + std::optional embeddedDataStream() const override; + V4L2SubdeviceFormat embeddedDataFormat() const override; + int setEmbeddedDataEnabled(bool enable) override; + const ControlList &properties() const override { return properties_; } int sensorInfo(IPACameraSensorInfo *info) const override; Transform computeTransform(Orientation *orientation) const override; @@ -886,6 +891,73 @@ int CameraSensorRaw::applyConfiguration(const SensorConfiguration &config, return 0; } +V4L2Subdevice::Stream CameraSensorRaw::imageStream() const +{ + return streams_.image.source; +} + +std::optional CameraSensorRaw::embeddedDataStream() const +{ + if (!streams_.edata) + return {}; + + return { streams_.edata->source }; +} + +V4L2SubdeviceFormat CameraSensorRaw::embeddedDataFormat() const +{ + if (!streams_.edata) + return {}; + + V4L2SubdeviceFormat format; + int ret = subdev_->getFormat(streams_.edata->source, &format); + if (ret) + return {}; + + return format; +} + +int CameraSensorRaw::setEmbeddedDataEnabled(bool enable) +{ + if (!streams_.edata) + return enable ? -ENOSTR : 0; + + V4L2Subdevice::Routing routing{ 2 }; + + routing[0].sink = streams_.image.sink; + routing[0].source = streams_.image.source; + routing[0].flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE; + + routing[1].sink = streams_.edata->sink; + routing[1].source = streams_.edata->source; + routing[1].flags = enable ? V4L2_SUBDEV_ROUTE_FL_ACTIVE : 0; + + int ret = subdev_->setRouting(&routing); + if (ret) + return ret; + + /* + * Check if the embedded data stream has been enabled or disabled + * correctly. Assume at least one route will match the embedded data + * source stream, as there would be something seriously wrong + * otherwise. + */ + bool enabled = false; + + for (const V4L2Subdevice::Route &route : routing) { + if (route.source != streams_.edata->source) + continue; + + enabled = route.flags & V4L2_SUBDEV_ROUTE_FL_ACTIVE; + break; + } + + if (enabled != enable) + return enabled ? -EISCONN : -ENOSTR; + + return 0; +} + int CameraSensorRaw::sensorInfo(IPACameraSensorInfo *info) const { info->model = model(); From patchwork Fri Mar 1 21:21:13 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 19615 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 82A27BD160 for ; Fri, 1 Mar 2024 21:21:57 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 386B862873; Fri, 1 Mar 2024 22:21:57 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="IKmk01+j"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 3E5EE6295D for ; Fri, 1 Mar 2024 22:21:55 +0100 (CET) Received: from pendragon.ideasonboard.com (89-27-53-110.bb.dnainternet.fi [89.27.53.110]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id CEB153372; Fri, 1 Mar 2024 22:21:40 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1709328101; bh=ZUpjYlW9wGcZZwE1ZW6TDDGbT2XWigdxfyoyDQwt30E=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=IKmk01+jSf11ru0RJ/E+OATcu87r3iIx10umthpeOhi56SeiSEpF7hNwGOyl/ypft uZmQafMDFJmYid79bVyyvH4xS+EcrvBNk52LxLBHiTG2w0ZAdn3eV9AoE/eC/JDo9H sqmtZYopUx75IxwqrNbdXYaUhmKv5IJxk2RHcMZM= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH/RFC 24/32] pipeline: raspberrypi: common: Configure sensor embedded data Date: Fri, 1 Mar 2024 23:21:13 +0200 Message-ID: <20240301212121.9072-25-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> References: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sakari Ailus Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Now that the CameraSensor class implements support for embedded data, use the corresponding API to enable or disable the embedded data stream. This changes requires sensor kernel drivers that implement the upstream embedded data API based on V4L2 streams. As the API is under development and not merged in the upstream kernel yet, this breaks compatibility with the downstream Raspberry Pi kernel. Signed-off-by: Laurent Pinchart --- src/libcamera/pipeline/rpi/common/pipeline_base.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp index d662c8f12145..9a2b8b90d5af 100644 --- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp @@ -527,6 +527,18 @@ int PipelineHandlerBase::configure(Camera *camera, CameraConfiguration *config) if (ret) return ret; + /* + * Configure embedded data on the sensor. Only check for errors when + * enabling embedded data, as some sensors don't support disabling it, + * and Unicam will simply drop the embedded data packets if we don't + * capture them. + */ + ret = data->sensor_->setEmbeddedDataEnabled(data->sensorMetadata_); + if (ret && data->sensorMetadata_) { + LOG(RPI, Error) << "Unable to enable embedded data: " << ret; + return ret; + } + /* * Platform specific internal stream configuration. This also assigns * external streams which get configured below. From patchwork Fri Mar 1 21:21:14 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 19616 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id E64A4BD160 for ; Fri, 1 Mar 2024 21:21:59 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id A6B1962875; Fri, 1 Mar 2024 22:21:59 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="Ys8fUx8G"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9F8E262875 for ; Fri, 1 Mar 2024 22:21:56 +0100 (CET) Received: from pendragon.ideasonboard.com (89-27-53-110.bb.dnainternet.fi [89.27.53.110]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 2D4793370; Fri, 1 Mar 2024 22:21:42 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1709328102; bh=9SLYmxbv0qs2VrZvv3mTlIeQUVcGPAV5LswD1uuZUdA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Ys8fUx8GVlPAETWe4yBckz2g7PBbpY2dBVIhsW8Q9gKGRp1u7AXYCT5G3vxrWRDOm Ys1vIuXvL0F70CBOWHHBEm4INFEk/DJ2FmHHhCcFVHl1QPro14mifkhx/hrwJUClaF fRvS96QOo6ZVxVSwcWtrVfz/x4AfOZhd6fWxjur0= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH/RFC 25/32] pipeline: raspberrypi: vc4: Use operator<<(V4L2VideoFormat) Date: Fri, 1 Mar 2024 23:21:14 +0200 Message-ID: <20240301212121.9072-26-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> References: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sakari Ailus Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Use the stream formatting operator for V4L2VideoFormat instead of calling .toString() manually. As the .toString() member function is a wrapper around the stream formatting operator, this makes the code slightly more efficient. Signed-off-by: Laurent Pinchart --- src/libcamera/pipeline/rpi/vc4/vc4.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcamera/pipeline/rpi/vc4/vc4.cpp b/src/libcamera/pipeline/rpi/vc4/vc4.cpp index ad7dddde59f1..4b0eb93745cf 100644 --- a/src/libcamera/pipeline/rpi/vc4/vc4.cpp +++ b/src/libcamera/pipeline/rpi/vc4/vc4.cpp @@ -690,7 +690,7 @@ int Vc4CameraData::platformConfigure(const RPi::RPiCameraConfiguration *rpiConfi format.fourcc = V4L2PixelFormat(V4L2_META_FMT_SENSOR_DATA); format.planes[0].size = embeddedFormat.size.width * embeddedFormat.size.height; - LOG(RPI, Debug) << "Setting embedded data format " << format.toString(); + LOG(RPI, Debug) << "Setting embedded data format " << format; ret = unicam_[Unicam::Embedded].dev()->setFormat(&format); if (ret) { LOG(RPI, Error) << "Failed to set format on Unicam embedded: " From patchwork Fri Mar 1 21:21:15 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 19617 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 90729C3260 for ; Fri, 1 Mar 2024 21:22:00 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 5361962C81; Fri, 1 Mar 2024 22:22:00 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="Ojn4z83s"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0FF2C62875 for ; Fri, 1 Mar 2024 22:21:58 +0100 (CET) Received: from pendragon.ideasonboard.com (89-27-53-110.bb.dnainternet.fi [89.27.53.110]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 8AED9673; Fri, 1 Mar 2024 22:21:43 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1709328103; bh=rnP4WtpVm9uyZJAE8BdIHDQAzE4/weqNrq9j1uWqKmI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Ojn4z83sxubcu8IUsfM/D8NL+1efc5rNkqyE0zzl4OE6izN3JrefHWnsLSrGpq0Fu hvJXlG0D0rgeI4Y3HmoEO9nP9UGCjNLmWynOM2SP/LQn3yRG7XroiZgaO+qXG0IxhN 79iBK/zE1L0etqb9/B9Z3pg2OmypfF7Cwaqqzjbw= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH/RFC 26/32] pipeline: raspberrypi: vc4: Reorganize platformConfigure() Date: Fri, 1 Mar 2024 23:21:15 +0200 Message-ID: <20240301212121.9072-27-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> References: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sakari Ailus Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The Vc4CameraData::platformConfigure() function configures inicam and the ISP. The corresponding configuration steps are interleaved, making it more difficult to read the code and follow the flow. Reorganize the function to improve readability. Signed-off-by: Laurent Pinchart --- src/libcamera/pipeline/rpi/vc4/vc4.cpp | 65 ++++++++++++++------------ 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/src/libcamera/pipeline/rpi/vc4/vc4.cpp b/src/libcamera/pipeline/rpi/vc4/vc4.cpp index 4b0eb93745cf..3c3c1b30f9e3 100644 --- a/src/libcamera/pipeline/rpi/vc4/vc4.cpp +++ b/src/libcamera/pipeline/rpi/vc4/vc4.cpp @@ -537,9 +537,9 @@ int Vc4CameraData::platformPipelineConfigure(const std::unique_ptr & int Vc4CameraData::platformConfigure(const RPi::RPiCameraConfiguration *rpiConfig) { - const std::vector &rawStreams = rpiConfig->rawStreams_; - const std::vector &outStreams = rpiConfig->outStreams_; - int ret; + /* + * 1. Configure the Unicam video devices. + */ V4L2VideoDevice *unicam = unicam_[Unicam::Image].dev(); V4L2DeviceFormat unicamFormat; @@ -548,6 +548,8 @@ int Vc4CameraData::platformConfigure(const RPi::RPiCameraConfiguration *rpiConfi * See which streams are requested, and route the user * StreamConfiguration appropriately. */ + const std::vector &rawStreams = rpiConfig->rawStreams_; + if (!rawStreams.empty()) { rawStreams[0].cfg->setStream(&unicam_[Unicam::Image]); unicam_[Unicam::Image].setFlags(StreamFlag::External); @@ -559,11 +561,7 @@ int Vc4CameraData::platformConfigure(const RPi::RPiCameraConfiguration *rpiConfi BayerFormat::Packing::CSI2); } - ret = unicam->setFormat(&unicamFormat); - if (ret) - return ret; - - ret = isp_[Isp::Input].dev()->setFormat(&unicamFormat); + int ret = unicam->setFormat(&unicamFormat); if (ret) return ret; @@ -571,7 +569,37 @@ int Vc4CameraData::platformConfigure(const RPi::RPiCameraConfiguration *rpiConfi << " - Selected sensor format: " << rpiConfig->sensorFormat_ << " - Selected unicam format: " << unicamFormat; + /* + * Configure the Unicam embedded data output format only if the sensor + * supports it. + */ + if (sensorMetadata_) { + V4L2SubdeviceFormat embeddedFormat; + + sensor_->device()->getFormat(1, &embeddedFormat); + V4L2DeviceFormat format{}; + format.fourcc = V4L2PixelFormat(V4L2_META_FMT_SENSOR_DATA); + format.planes[0].size = embeddedFormat.size.width * embeddedFormat.size.height; + + LOG(RPI, Debug) << "Setting embedded data format " << format; + ret = unicam_[Unicam::Embedded].dev()->setFormat(&format); + if (ret) { + LOG(RPI, Error) << "Failed to set format on Unicam embedded: " + << format; + return ret; + } + } + + /* + * 2. Configure the ISP. + */ + + ret = isp_[Isp::Input].dev()->setFormat(&unicamFormat); + if (ret) + return ret; + /* Use a sensible small default size if no output streams are configured. */ + const std::vector &outStreams = rpiConfig->outStreams_; Size maxSize = outStreams.empty() ? Size(320, 240) : outStreams[0].cfg->size; V4L2DeviceFormat format; @@ -678,27 +706,6 @@ int Vc4CameraData::platformConfigure(const RPi::RPiCameraConfiguration *rpiConfi ispOutputTotal_++; - /* - * Configure the Unicam embedded data output format only if the sensor - * supports it. - */ - if (sensorMetadata_) { - V4L2SubdeviceFormat embeddedFormat; - - sensor_->device()->getFormat(1, &embeddedFormat); - format = {}; - format.fourcc = V4L2PixelFormat(V4L2_META_FMT_SENSOR_DATA); - format.planes[0].size = embeddedFormat.size.width * embeddedFormat.size.height; - - LOG(RPI, Debug) << "Setting embedded data format " << format; - ret = unicam_[Unicam::Embedded].dev()->setFormat(&format); - if (ret) { - LOG(RPI, Error) << "Failed to set format on Unicam embedded: " - << format; - return ret; - } - } - /* Figure out the smallest selection the ISP will allow. */ Rectangle testCrop(0, 0, 1, 1); isp_[Isp::Input].dev()->setSelection(V4L2_SEL_TGT_CROP, &testCrop); From patchwork Fri Mar 1 21:21:16 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 19618 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 2FA72BD160 for ; Fri, 1 Mar 2024 21:22:02 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id D8D0562875; Fri, 1 Mar 2024 22:22:01 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="PO8ghUEo"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6C68162964 for ; Fri, 1 Mar 2024 22:21:59 +0100 (CET) Received: from pendragon.ideasonboard.com (89-27-53-110.bb.dnainternet.fi [89.27.53.110]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id E9001335C; Fri, 1 Mar 2024 22:21:44 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1709328105; bh=X2dfK1U286UER7gay9EgBCokZrhjkVFLfSHMIsfzgf8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=PO8ghUEo5JeHeFjbtCNGJ2eArzzq3/dcMAqO79M8PtOHpHUrzsGjjBMstcYrS8cMu Hls66q36KymYHFBLm+AeWWzWt1zhliZ1UvZbzeXrRUeAsEjXMhTwj5g7E1xHpm5ltx 4Bh0ipQypp1yjLKdeQm9c28b5NLNxOrLRwvVL8d4= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH/RFC 27/32] pipeline: raspberrypi: vc4: Use the CameraSensor embedded data API Date: Fri, 1 Mar 2024 23:21:16 +0200 Message-ID: <20240301212121.9072-28-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> References: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sakari Ailus Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Now that the CameraSensor class implements support for embedded data, use the corresponding API instead of retrieving the embedded data format from the subdev manually. This changes requires sensor kernel drivers that implement the upstream embedded data API based on V4L2 streams. As the API is under development and not merged in the upstream kernel yet, this breaks compatibility with the downstream Raspberry Pi kernel. Signed-off-by: Laurent Pinchart --- src/libcamera/pipeline/rpi/vc4/vc4.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libcamera/pipeline/rpi/vc4/vc4.cpp b/src/libcamera/pipeline/rpi/vc4/vc4.cpp index 3c3c1b30f9e3..75dc85cf62a1 100644 --- a/src/libcamera/pipeline/rpi/vc4/vc4.cpp +++ b/src/libcamera/pipeline/rpi/vc4/vc4.cpp @@ -574,9 +574,7 @@ int Vc4CameraData::platformConfigure(const RPi::RPiCameraConfiguration *rpiConfi * supports it. */ if (sensorMetadata_) { - V4L2SubdeviceFormat embeddedFormat; - - sensor_->device()->getFormat(1, &embeddedFormat); + V4L2SubdeviceFormat embeddedFormat = sensor_->embeddedDataFormat(); V4L2DeviceFormat format{}; format.fourcc = V4L2PixelFormat(V4L2_META_FMT_SENSOR_DATA); format.planes[0].size = embeddedFormat.size.width * embeddedFormat.size.height; From patchwork Fri Mar 1 21:21:17 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 19619 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id D1E9FC32C3 for ; Fri, 1 Mar 2024 21:22:02 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 9E9CF62964; Fri, 1 Mar 2024 22:22:02 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="RJJJDS0d"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id CAF9362878 for ; Fri, 1 Mar 2024 22:22:00 +0100 (CET) Received: from pendragon.ideasonboard.com (89-27-53-110.bb.dnainternet.fi [89.27.53.110]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 4E8513871; Fri, 1 Mar 2024 22:21:46 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1709328106; bh=4nRhZJg1GUFTt3pitfDnfKaZQMka2pKWFZyoReg52TA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=RJJJDS0dLraJVrK4I2dAJ7TJSWCqbV75f4XjatrpPvnCLl+pF80ikIUwp+FuHD5Wi 72FNFBGGulOQjbkmeijTNLznsTWmPGm9gu7vhzui1lAwRWWFpoBzRnv7t+WyNzdrjo E4ylczliIbrz+No53MF5M70hpBTJ4Mu47xyisy4M= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH/RFC 28/32] pipeline: raspberrypi: vc4: Unconditionally create embedded data stream Date: Fri, 1 Mar 2024 23:21:17 +0200 Message-ID: <20240301212121.9072-29-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> References: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sakari Ailus Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The mainline Unicam driver unconditionally creates the embedded data video device. Create the corresponding stream unconditionally. Drop the warning in case of mismatch between Unicam and the CamHelper, as this becomes a normal situation when the sensor doesn't support emebedded data. Signed-off-by: Laurent Pinchart --- src/libcamera/pipeline/rpi/vc4/vc4.cpp | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/src/libcamera/pipeline/rpi/vc4/vc4.cpp b/src/libcamera/pipeline/rpi/vc4/vc4.cpp index 75dc85cf62a1..da925ba5f793 100644 --- a/src/libcamera/pipeline/rpi/vc4/vc4.cpp +++ b/src/libcamera/pipeline/rpi/vc4/vc4.cpp @@ -311,24 +311,19 @@ int PipelineHandlerVc4::platformRegister(std::unique_ptr &camer return -ENOMEM; MediaEntity *unicamImage = unicam->getEntityByName("unicam-image"); + MediaEntity *unicamEmbedded = unicam->getEntityByName("unicam-embedded"); MediaEntity *ispOutput0 = isp->getEntityByName("bcm2835-isp0-output0"); MediaEntity *ispCapture1 = isp->getEntityByName("bcm2835-isp0-capture1"); MediaEntity *ispCapture2 = isp->getEntityByName("bcm2835-isp0-capture2"); MediaEntity *ispCapture3 = isp->getEntityByName("bcm2835-isp0-capture3"); - if (!unicamImage || !ispOutput0 || !ispCapture1 || !ispCapture2 || !ispCapture3) + if (!unicamImage || !unicamEmbedded || + !ispOutput0 || !ispCapture1 || !ispCapture2 || !ispCapture3) return -ENOENT; - /* Locate and open the unicam video streams. */ + /* Create the unicam video streams. */ data->unicam_[Unicam::Image] = RPi::Stream("Unicam Image", unicamImage); - - /* An embedded data node will not be present if the sensor does not support it. */ - MediaEntity *unicamEmbedded = unicam->getEntityByName("unicam-embedded"); - if (unicamEmbedded) { - data->unicam_[Unicam::Embedded] = RPi::Stream("Unicam Embedded", unicamEmbedded); - data->unicam_[Unicam::Embedded].dev()->bufferReady.connect(data, - &Vc4CameraData::unicamBufferDequeue); - } + data->unicam_[Unicam::Embedded] = RPi::Stream("Unicam Embedded", unicamEmbedded); /* Tag the ISP input stream as an import stream. */ data->isp_[Isp::Input] = RPi::Stream("ISP Input", ispOutput0, StreamFlag::ImportOnly); @@ -338,18 +333,15 @@ int PipelineHandlerVc4::platformRegister(std::unique_ptr &camer /* Wire up all the buffer connections. */ data->unicam_[Unicam::Image].dev()->bufferReady.connect(data, &Vc4CameraData::unicamBufferDequeue); + if (data->sensorMetadata_) + data->unicam_[Unicam::Embedded].dev()->bufferReady.connect(data, + &Vc4CameraData::unicamBufferDequeue); + data->isp_[Isp::Input].dev()->bufferReady.connect(data, &Vc4CameraData::ispInputDequeue); data->isp_[Isp::Output0].dev()->bufferReady.connect(data, &Vc4CameraData::ispOutputDequeue); data->isp_[Isp::Output1].dev()->bufferReady.connect(data, &Vc4CameraData::ispOutputDequeue); data->isp_[Isp::Stats].dev()->bufferReady.connect(data, &Vc4CameraData::ispOutputDequeue); - if (data->sensorMetadata_ ^ !!data->unicam_[Unicam::Embedded].dev()) { - LOG(RPI, Warning) << "Mismatch between Unicam and CamHelper for embedded data usage!"; - data->sensorMetadata_ = false; - if (data->unicam_[Unicam::Embedded].dev()) - data->unicam_[Unicam::Embedded].dev()->bufferReady.disconnect(); - } - /* * Open all Unicam and ISP streams. The exception is the embedded data * stream, which only gets opened below if the IPA reports that the sensor From patchwork Fri Mar 1 21:21:18 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 19620 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 5BB99C3260 for ; Fri, 1 Mar 2024 21:22:04 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 18D6362C84; Fri, 1 Mar 2024 22:22:04 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="ByigtAHf"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 3400662C94 for ; Fri, 1 Mar 2024 22:22:02 +0100 (CET) Received: from pendragon.ideasonboard.com (89-27-53-110.bb.dnainternet.fi [89.27.53.110]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id B16EE3DF7; Fri, 1 Mar 2024 22:21:47 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1709328107; bh=LGJCkU8WiFH6nxUqWNKrukB57KBiBbJ9SDEhPjBxC3I=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ByigtAHfZn7Sf6mKKFxJfplcF38unKFtJu2CEmTtwlc5DvvykLjohcj4ewZDkdFXS xTtsjj4z+/ghTSz37RzADKnD1xaQlQ3CO6ugaToOTPGBmiPuGHmbnv5RNykOHWjKku wn4jfV+UB3M/SG4scyMA/7u0LbyfiMasNF/laXhg= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH/RFC 29/32] pipeline: raspberrypi: vc4: Configure format on Unicam subdev Date: Fri, 1 Mar 2024 23:21:18 +0200 Message-ID: <20240301212121.9072-30-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> References: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sakari Ailus Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The mainline Unicam driver creates a V4L2 subdevice, which needs to be configured. Create and open a corresponding V4L2Subdevice instance and configure the format on its sink pad in the platformConfigure() function. Presence of the Unicam subdev is required, to avoid extra complexity. This drops support for the driver from the Raspberry Pi downstream kernel. Users are expected to update their kernel to use the mainline Unicam driver. Signed-off-by: Laurent Pinchart --- src/libcamera/pipeline/rpi/vc4/vc4.cpp | 78 ++++++++++++++++++++++---- 1 file changed, 68 insertions(+), 10 deletions(-) diff --git a/src/libcamera/pipeline/rpi/vc4/vc4.cpp b/src/libcamera/pipeline/rpi/vc4/vc4.cpp index da925ba5f793..81e0bc1b8f7a 100644 --- a/src/libcamera/pipeline/rpi/vc4/vc4.cpp +++ b/src/libcamera/pipeline/rpi/vc4/vc4.cpp @@ -5,6 +5,8 @@ * vc4.cpp - Pipeline handler for VC4-based Raspberry Pi devices */ +#include + #include #include #include @@ -12,6 +14,7 @@ #include #include "libcamera/internal/device_enumerator.h" +#include "libcamera/internal/v4l2_subdevice.h" #include "../common/pipeline_base.h" #include "../common/rpi_stream.h" @@ -32,6 +35,10 @@ namespace { enum class Unicam : unsigned int { Image, Embedded }; enum class Isp : unsigned int { Input, Output0, Output1, Stats }; +static constexpr unsigned int kUnicamSinkPad = 0; +static constexpr unsigned int kUnicamSourceImagePad = 1; +static constexpr unsigned int kUnicamSourceMetadataPad = 2; + } /* namespace */ class Vc4CameraData final : public RPi::CameraData @@ -82,6 +89,8 @@ public: void setIspControls(const ControlList &controls); void setCameraTimeout(uint32_t maxFrameLengthMs); + std::unique_ptr unicamSubdev_; + /* Array of Unicam and ISP device streams and associated buffers/streams. */ RPi::Device unicam_; RPi::Device isp_; @@ -310,6 +319,7 @@ int PipelineHandlerVc4::platformRegister(std::unique_ptr &camer if (!data->dmaHeap_.isValid()) return -ENOMEM; + MediaEntity *unicamSubdev = unicam->getEntityByName("unicam"); MediaEntity *unicamImage = unicam->getEntityByName("unicam-image"); MediaEntity *unicamEmbedded = unicam->getEntityByName("unicam-embedded"); MediaEntity *ispOutput0 = isp->getEntityByName("bcm2835-isp0-output0"); @@ -321,7 +331,13 @@ int PipelineHandlerVc4::platformRegister(std::unique_ptr &camer !ispOutput0 || !ispCapture1 || !ispCapture2 || !ispCapture3) return -ENOENT; - /* Create the unicam video streams. */ + if (!unicamSubdev) { + LOG(RPI, Error) << "Downstream Unicam driver not supported, please update your kernel!"; + return -EINVAL; + } + + /* Create the unicam subdev and video streams. */ + data->unicamSubdev_ = std::make_unique(unicamSubdev); data->unicam_[Unicam::Image] = RPi::Stream("Unicam Image", unicamImage); data->unicam_[Unicam::Embedded] = RPi::Stream("Unicam Embedded", unicamEmbedded); @@ -350,6 +366,10 @@ int PipelineHandlerVc4::platformRegister(std::unique_ptr &camer * The below grouping is just for convenience so that we can easily * iterate over all streams in one go. */ + int ret = data->unicamSubdev_->open(); + if (ret < 0) + return ret; + data->streams_.push_back(&data->unicam_[Unicam::Image]); if (data->sensorMetadata_) data->streams_.push_back(&data->unicam_[Unicam::Embedded]); @@ -358,16 +378,11 @@ int PipelineHandlerVc4::platformRegister(std::unique_ptr &camer data->streams_.push_back(&stream); for (auto stream : data->streams_) { - int ret = stream->dev()->open(); + ret = stream->dev()->open(); if (ret) return ret; } - if (!data->unicam_[Unicam::Image].dev()->caps().hasMediaController()) { - LOG(RPI, Error) << "Unicam driver does not use the MediaController, please update your kernel!"; - return -EINVAL; - } - /* Write up all the IPA connections. */ data->ipa_->processStatsComplete.connect(data, &Vc4CameraData::processStatsComplete); data->ipa_->prepareIspComplete.connect(data, &Vc4CameraData::prepareIspComplete); @@ -530,7 +545,50 @@ int Vc4CameraData::platformPipelineConfigure(const std::unique_ptr & int Vc4CameraData::platformConfigure(const RPi::RPiCameraConfiguration *rpiConfig) { /* - * 1. Configure the Unicam video devices. + * 1. Configure the Unicam subdev. + * + * Start by setting up routes, and then set the formats on the sink pad + * streams. They will be automatically propagated to the source pads by + * the kernel. + */ + + const V4L2Subdevice::Stream imageStream{ + kUnicamSinkPad, + sensor_->imageStream().stream + }; + const V4L2Subdevice::Stream embeddedDataStream{ + kUnicamSinkPad, + sensor_->embeddedDataStream().value_or(V4L2Subdevice::Stream{}).stream + }; + + V4L2Subdevice::Routing routing; + + routing.emplace_back(imageStream, V4L2Subdevice::Stream{ kUnicamSourceImagePad, 0 }, + V4L2_SUBDEV_ROUTE_FL_ACTIVE); + + if (sensorMetadata_) + routing.emplace_back(embeddedDataStream, + V4L2Subdevice::Stream{ kUnicamSourceMetadataPad, 0 }, + V4L2_SUBDEV_ROUTE_FL_ACTIVE); + + int ret = unicamSubdev_->setRouting(&routing); + if (ret) + return ret; + + V4L2SubdeviceFormat subdevFormat = rpiConfig->sensorFormat_; + ret = unicamSubdev_->setFormat(imageStream, &subdevFormat); + if (ret) + return ret; + + if (sensorMetadata_) { + subdevFormat = sensor_->embeddedDataFormat(); + ret = unicamSubdev_->setFormat(embeddedDataStream, &subdevFormat); + if (ret) + return ret; + } + + /* + * 2. Configure the Unicam video devices. */ V4L2VideoDevice *unicam = unicam_[Unicam::Image].dev(); @@ -553,7 +611,7 @@ int Vc4CameraData::platformConfigure(const RPi::RPiCameraConfiguration *rpiConfi BayerFormat::Packing::CSI2); } - int ret = unicam->setFormat(&unicamFormat); + ret = unicam->setFormat(&unicamFormat); if (ret) return ret; @@ -581,7 +639,7 @@ int Vc4CameraData::platformConfigure(const RPi::RPiCameraConfiguration *rpiConfi } /* - * 2. Configure the ISP. + * 3. Configure the ISP. */ ret = isp_[Isp::Input].dev()->setFormat(&unicamFormat); From patchwork Fri Mar 1 21:21:19 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 19621 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id CD625BD160 for ; Fri, 1 Mar 2024 21:22:05 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 8AC9062C94; Fri, 1 Mar 2024 22:22:05 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="f/tl4/OZ"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9AE1262C95 for ; Fri, 1 Mar 2024 22:22:03 +0100 (CET) Received: from pendragon.ideasonboard.com (89-27-53-110.bb.dnainternet.fi [89.27.53.110]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 22A713AC3; Fri, 1 Mar 2024 22:21:49 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1709328109; bh=YSMuEhlQbv/mbS4xuvgyxPFDndM/NDOaJQLd/+dyulI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=f/tl4/OZWyxEdr0KcmhlIClcqeMYfdN+8uSizZo8p3aMRskgbJKeVBxQN+eIrK68r R2XVgCt9s0KQEd39Od+8n0kK/UK38P4t0ooejI4NtMzSVVJxsuNLrkk9pZEdxcimUl C9b0KS+6Tm9ePmhHD0i0oalM184PVZW0pOQBgJaQ= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH/RFC 30/32] pipeline: raspberrypi: vc4: Fix configuration of the embedded data node Date: Fri, 1 Mar 2024 23:21:19 +0200 Message-ID: <20240301212121.9072-31-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> References: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sakari Ailus Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The Unicam embedded data video device suffers from two issues with the upstream driver: - The driver uses the generic metadata V4L2_META_FMT_GENERIC_* formats, instead of the downstream V4L2_META_FMT_SENSOR_DATA. - The driver requires the width and height of the embedded data stream to be configured. Fix them both. Signed-off-by: Laurent Pinchart --- src/libcamera/pipeline/rpi/vc4/vc4.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/libcamera/pipeline/rpi/vc4/vc4.cpp b/src/libcamera/pipeline/rpi/vc4/vc4.cpp index 81e0bc1b8f7a..2ff9b708d021 100644 --- a/src/libcamera/pipeline/rpi/vc4/vc4.cpp +++ b/src/libcamera/pipeline/rpi/vc4/vc4.cpp @@ -624,10 +624,25 @@ int Vc4CameraData::platformConfigure(const RPi::RPiCameraConfiguration *rpiConfi * supports it. */ if (sensorMetadata_) { + static const std::map metaFormats{ + { MEDIA_BUS_FMT_META_8, V4L2PixelFormat(V4L2_META_FMT_GENERIC_8) }, + { MEDIA_BUS_FMT_META_10, V4L2PixelFormat(V4L2_META_FMT_GENERIC_CSI2_10) }, + { MEDIA_BUS_FMT_META_12, V4L2PixelFormat(V4L2_META_FMT_GENERIC_CSI2_12) }, + { MEDIA_BUS_FMT_META_14, V4L2PixelFormat(V4L2_META_FMT_GENERIC_CSI2_14) }, + }; + V4L2SubdeviceFormat embeddedFormat = sensor_->embeddedDataFormat(); + const auto metaFormat = metaFormats.find(embeddedFormat.code); + if (metaFormat == metaFormats.end()) { + LOG(RPI, Error) + << "Unsupported metadata format " + << utils::hex(embeddedFormat.code, 4); + return -EINVAL; + } + V4L2DeviceFormat format{}; - format.fourcc = V4L2PixelFormat(V4L2_META_FMT_SENSOR_DATA); - format.planes[0].size = embeddedFormat.size.width * embeddedFormat.size.height; + format.fourcc = metaFormat->second; + format.size = embeddedFormat.size; LOG(RPI, Debug) << "Setting embedded data format " << format; ret = unicam_[Unicam::Embedded].dev()->setFormat(&format); From patchwork Fri Mar 1 21:21:20 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 19622 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 85690BE080 for ; Fri, 1 Mar 2024 21:22:06 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 4B43362C95; Fri, 1 Mar 2024 22:22:06 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="iPHvN56H"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 006F362878 for ; Fri, 1 Mar 2024 22:22:05 +0100 (CET) Received: from pendragon.ideasonboard.com (89-27-53-110.bb.dnainternet.fi [89.27.53.110]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 7E8C73305; Fri, 1 Mar 2024 22:21:50 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1709328110; bh=YjG9IC8ZwIFxLnRg2Cs+aTI8qi8vomKT+j1iQ4cUxZ8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=iPHvN56Hu4Oog8oY+Qa+YlsmECgqAhzAHeVtu/r8D8RULawxVzfzLLVSrh6Ub3s2/ /h439NeFHIw2ezDIfKLzYA8Ymbboi+KpgCgRo/JSsMkT4F7vtEsVOGIvUAJ/BnxXkk MSsySZSRs/C1cd0CDZcWiibhC4UtgJpOI/SNV6cE= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH/RFC 31/32] include: linux: Drop V4L2_META_FMT_SENSOR_DATA Date: Fri, 1 Mar 2024 23:21:20 +0200 Message-ID: <20240301212121.9072-32-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> References: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sakari Ailus Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The V4L2_META_FMT_SENSOR_DATA format was used by the Raspberry Pi VC4 pipeline handler and the downstream Unicam kernel driver. Now that they have both moved to an upstream API, drop the format definition from the kernel header. This brings videodev2.h closer to the mainline kernel. Signed-off-by: Laurent Pinchart --- include/linux/videodev2.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index 33e0ea95e0fa..4d968f5acb9e 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -809,7 +809,6 @@ struct v4l2_pix_format { #define V4L2_META_FMT_UVC v4l2_fourcc('U', 'V', 'C', 'H') /* UVC Payload Header metadata */ #define V4L2_META_FMT_D4XX v4l2_fourcc('D', '4', 'X', 'X') /* D4XX Payload Header metadata */ #define V4L2_META_FMT_VIVID v4l2_fourcc('V', 'I', 'V', 'D') /* Vivid Metadata */ -#define V4L2_META_FMT_SENSOR_DATA v4l2_fourcc('S', 'E', 'N', 'S') /* Sensor Ancillary metadata */ #define V4L2_META_FMT_BCM2835_ISP_STATS v4l2_fourcc('B', 'S', 'T', 'A') /* BCM2835 ISP image statistics output */ /* Vendor specific - used for RK_ISP1 camera sub-system */ From patchwork Fri Mar 1 21:21:21 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 19623 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 1D20DC3260 for ; Fri, 1 Mar 2024 21:22:09 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C930B62C94; Fri, 1 Mar 2024 22:22:08 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="f3DivMYf"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 5C66062C97 for ; Fri, 1 Mar 2024 22:22:06 +0100 (CET) Received: from pendragon.ideasonboard.com (89-27-53-110.bb.dnainternet.fi [89.27.53.110]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id D57C13263; Fri, 1 Mar 2024 22:21:51 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1709328112; bh=SIW1dtchoyB2VxN8K61D0x222rQYWoins2vc6X8HtlI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=f3DivMYfmnVwCUy1LB2TxSSG734nJxDzkpM1FPPpfBO8s13MkSTzMqhiJFkgSU1er buOwdUKEsswfy+iBxuce5QndzjO6E6/7xlCkw9tz7h/L9sHtn9cSkT2nynGWKw2yC1 lKz+sMyRj0Pg2eVWcJsBlqBCJa3w3XR7k7Tv7kfU= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH/RFC 32/32] [HACK]: ipa: rpi: cam_helper_imx219: Enable embedded data Date: Fri, 1 Mar 2024 23:21:21 +0200 Message-ID: <20240301212121.9072-33-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> References: <20240301212121.9072-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sakari Ailus Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Enable embedded data usage with the IMX219 for testing purpose. Signed-off-by: Laurent Pinchart --- src/ipa/rpi/cam_helper/cam_helper_imx219.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ipa/rpi/cam_helper/cam_helper_imx219.cpp b/src/ipa/rpi/cam_helper/cam_helper_imx219.cpp index c3337ed08466..cd5050c33a0c 100644 --- a/src/ipa/rpi/cam_helper/cam_helper_imx219.cpp +++ b/src/ipa/rpi/cam_helper/cam_helper_imx219.cpp @@ -14,7 +14,7 @@ * We have observed that the imx219 embedded data stream randomly returns junk * register values. Do not rely on embedded data until this has been resolved. */ -#define ENABLE_EMBEDDED_DATA 0 +#define ENABLE_EMBEDDED_DATA 1 #include "cam_helper.h" #if ENABLE_EMBEDDED_DATA