From patchwork Mon Aug 29 10:04:12 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 17223 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 6C617C3272 for ; Mon, 29 Aug 2022 10:04:28 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 2327661FC4; Mon, 29 Aug 2022 12:04:28 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1661767468; bh=HXSEU9XbPmNwni/4BnhJsezUu0yOUCWcVZhGYF5g/1E=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=tn+rgAYxOz0b5qbKLK6lkjbAcRuLV7nxdT2u1I4eFfzemO6g4WFYerE5eG01xjMxI sO/gN3uDj8DUFyzPNUbnRLQExnUWlDQ6dKvRFIxb9105xybHongEPH9wz4SqpRPE0f fAY9qEhd+1ui5598/UjvEgQhDaBSm3AZFYJYmS2vods6dYiASDbtatTy8BeqHVek9Z P9V/rYlmwmVpX80s9FbxFiJN3PP8Ehpunoa5tNFbeO8/9Tp5JT5jAs2nunOmr28Ely 6jBeTVHE6ANXqxM0tLOd5/fDdGSu8evLIxbYU5fioWkaneJGyLZVpV2uexdVL9lMFT a83mk9adAuFCA== 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 B3ED761FBC for ; Mon, 29 Aug 2022 12:04:25 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="EZRjMoA9"; dkim-atps=neutral Received: from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 3F3DFA1D for ; Mon, 29 Aug 2022 12:04:25 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1661767465; bh=HXSEU9XbPmNwni/4BnhJsezUu0yOUCWcVZhGYF5g/1E=; h=From:To:Subject:Date:In-Reply-To:References:From; b=EZRjMoA92AZHU6SH1ZsuyHwurq1eZlC+qIupamT99jAMOiGktlkR6sdsgRuzGly/a vhJOMduFNChwk89Faxl1rd8NUqpbT6DBQveC81AoGJY2k9dWgkhL7Kuv8Is3DqdBD4 yn4p5jmD3bMpBVch2eKbCdBoVnxj+HZ3oDBZM59A= To: libcamera-devel@lists.libcamera.org Date: Mon, 29 Aug 2022 13:04:12 +0300 Message-Id: <20220829100414.28404-2-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220829100414.28404-1-laurent.pinchart@ideasonboard.com> References: <20220829100414.28404-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 1/3] pipeline: uvcvideo: Add color space support 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: , X-Patchwork-Original-From: Laurent Pinchart via libcamera-devel From: Laurent Pinchart Reply-To: Laurent Pinchart Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add support for color space to the uvcvideo pipeline handler. UVC devices have a fixed color space per format, so only the validate() function needs to be extended to retrieve the color space from the kernel. There is no need to pass the value back to the driver in configure(). Signed-off-by: Laurent Pinchart Reviewed-by: Umang Jain --- src/libcamera/pipeline/uvcvideo/uvcvideo.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp index 9cbf126aea57..2ae640a31f68 100644 --- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp +++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp @@ -159,6 +159,11 @@ CameraConfiguration::Status UVCCameraConfiguration::validate() cfg.stride = format.planes[0].bpl; cfg.frameSize = format.planes[0].size; + if (cfg.colorSpace != format.colorSpace) { + cfg.colorSpace = format.colorSpace; + status = Adjusted; + } + return status; } From patchwork Mon Aug 29 10:04:13 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 17224 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 14395C3272 for ; Mon, 29 Aug 2022 10:04:30 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C2BEC61FC6; Mon, 29 Aug 2022 12:04:29 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1661767469; bh=8twypGA1ryQShZKLj+yoixVo829FfaTYwkHXGcLJsMI=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=WfuZYSyp8kbZRfwlCRQonwfz/HggeETtAiKWpvOYre55IUW5lWfHjLeu9PgYVxjTJ 97gL80GEhw4GXIZJD9ZyJRw9SkxhlKnsdMu9pTRIYiFYnXaOCcdN+cJQXNoW1eJqOI eQ7jiEFAmrQNUFuc2gn4DPUsWyjQrvs17jH3R2QP89BSmprRSb+NNY2gYa99dfVPKl thjpu1anRYiY0A/Uugk5ghKGpvnePBOz3HpxvJlDIne8MGbaU9puwnYESS1+UNfUxq T22E4QcTGhTXb3mrFOcxXG1RaYdnQhVXo8QuHl90JbAhY/fZkg8uBZVrTniykzT6B2 wBQxco/QBGFxA== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 73B4E61FC2 for ; Mon, 29 Aug 2022 12:04:27 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="MrLnFhwA"; dkim-atps=neutral Received: from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id E25EC8BD for ; Mon, 29 Aug 2022 12:04:26 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1661767467; bh=8twypGA1ryQShZKLj+yoixVo829FfaTYwkHXGcLJsMI=; h=From:To:Subject:Date:In-Reply-To:References:From; b=MrLnFhwAiYXvejaSZLrA367SIzuQMbiQ3hCUyfx30mKZPhdZ4ix4UxsG+fTmnuApi YpXdXtoGKFmyQuX3Q15A6+ZObVbdp1S4Q64+JqZ2gyjWjZwMx+4XoBaTHQXTRPkUzn /DmPEkAtpRdEb1Fu5QqtS3HhrmUhnR+OjHzCou4c= To: libcamera-devel@lists.libcamera.org Date: Mon, 29 Aug 2022 13:04:13 +0300 Message-Id: <20220829100414.28404-3-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220829100414.28404-1-laurent.pinchart@ideasonboard.com> References: <20220829100414.28404-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 2/3] qcam: Pass color space to ViewFinder::setFormat() 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: , X-Patchwork-Original-From: Laurent Pinchart via libcamera-devel From: Laurent Pinchart Reply-To: Laurent Pinchart Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" To prepare for color space support in the viewfinder, pass the color space to the setFormat() function. Signed-off-by: Laurent Pinchart Reviewed-by: Umang Jain --- src/qcam/main_window.cpp | 6 +++++- src/qcam/viewfinder.h | 2 ++ src/qcam/viewfinder_gl.cpp | 5 +++-- src/qcam/viewfinder_gl.h | 1 + src/qcam/viewfinder_qt.cpp | 5 +++-- src/qcam/viewfinder_qt.h | 1 + 6 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp index 7433d647e8a0..addf0d96daf4 100644 --- a/src/qcam/main_window.cpp +++ b/src/qcam/main_window.cpp @@ -447,9 +447,13 @@ int MainWindow::startCapture() else rawStream_ = nullptr; - /* Configure the viewfinder. */ + /* + * Configure the viewfinder. If no color space is reported, default to + * sYCC. + */ ret = viewfinder_->setFormat(vfConfig.pixelFormat, QSize(vfConfig.size.width, vfConfig.size.height), + vfConfig.colorSpace.value_or(ColorSpace::Sycc), vfConfig.stride); if (ret < 0) { qInfo() << "Failed to set viewfinder format"; diff --git a/src/qcam/viewfinder.h b/src/qcam/viewfinder.h index 260074aed440..a57446e85951 100644 --- a/src/qcam/viewfinder.h +++ b/src/qcam/viewfinder.h @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -24,6 +25,7 @@ public: virtual const QList &nativeFormats() const = 0; virtual int setFormat(const libcamera::PixelFormat &format, const QSize &size, + const libcamera::ColorSpace &colorSpace, unsigned int stride) = 0; virtual void render(libcamera::FrameBuffer *buffer, Image *image) = 0; virtual void stop() = 0; diff --git a/src/qcam/viewfinder_gl.cpp b/src/qcam/viewfinder_gl.cpp index 3ae8b03accb5..ec295b6de0dd 100644 --- a/src/qcam/viewfinder_gl.cpp +++ b/src/qcam/viewfinder_gl.cpp @@ -71,8 +71,9 @@ const QList &ViewFinderGL::nativeFormats() const return supportedFormats; } -int ViewFinderGL::setFormat(const libcamera::PixelFormat &format, - const QSize &size, unsigned int stride) +int ViewFinderGL::setFormat(const libcamera::PixelFormat &format, const QSize &size, + [[maybe_unused]] const libcamera::ColorSpace &colorSpace, + unsigned int stride) { if (format != format_) { /* diff --git a/src/qcam/viewfinder_gl.h b/src/qcam/viewfinder_gl.h index 0a9275baf9b9..798830a31cd2 100644 --- a/src/qcam/viewfinder_gl.h +++ b/src/qcam/viewfinder_gl.h @@ -39,6 +39,7 @@ public: const QList &nativeFormats() const override; int setFormat(const libcamera::PixelFormat &format, const QSize &size, + const libcamera::ColorSpace &colorSpace, unsigned int stride) override; void render(libcamera::FrameBuffer *buffer, Image *image) override; void stop() override; diff --git a/src/qcam/viewfinder_qt.cpp b/src/qcam/viewfinder_qt.cpp index 7a6a60c96393..c20fd6bc8fc2 100644 --- a/src/qcam/viewfinder_qt.cpp +++ b/src/qcam/viewfinder_qt.cpp @@ -54,8 +54,9 @@ const QList &ViewFinderQt::nativeFormats() const return formats; } -int ViewFinderQt::setFormat(const libcamera::PixelFormat &format, - const QSize &size, unsigned int stride) +int ViewFinderQt::setFormat(const libcamera::PixelFormat &format, const QSize &size, + [[maybe_unused]] const libcamera::ColorSpace &colorSpace, + unsigned int stride) { image_ = QImage(); diff --git a/src/qcam/viewfinder_qt.h b/src/qcam/viewfinder_qt.h index 8c62145211d1..eb3a99882d19 100644 --- a/src/qcam/viewfinder_qt.h +++ b/src/qcam/viewfinder_qt.h @@ -32,6 +32,7 @@ public: const QList &nativeFormats() const override; int setFormat(const libcamera::PixelFormat &format, const QSize &size, + const libcamera::ColorSpace &colorSpace, unsigned int stride) override; void render(libcamera::FrameBuffer *buffer, Image *image) override; void stop() override; From patchwork Mon Aug 29 10:04:14 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 17225 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 95D13C3272 for ; Mon, 29 Aug 2022 10:04:32 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 4F45E61FBE; Mon, 29 Aug 2022 12:04:32 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1661767472; bh=6sbzgQdntHRRZ4KlQmYYZ41mnQ+VTWs7kF/CEKL6a4M=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=lM+U05l0oCHRDZQQySTXmgYFB+eyn3IANuouVhgkKuAx+GlZrhvZp2oJsJEIctte6 SqiMPuqZdLZdves8ANKopulZNB8abA/Et8tG+LZELES+7BeGGmu8AAasm1Nu9gKwKl bNWKVzfqmLe51aHaIl3eKaKORwp7fE5CJL4ckyGr5daeOnsJ/yBxALWiWigC9ivULf PpM18T6ZT/Vma7KD+/mX0u7N+iPSYeM2WSxFntC5lXYdh5WEo90dP28AblOnWromPT A2mZRpIZoNeBwIefByoCxns8zGsHlDM+Poa4hS6ZRHmh0IpSBWl0ScYi0xq64D4w7m wvd/BPiNJLpxg== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 932A461FBE for ; Mon, 29 Aug 2022 12:04:30 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="W4abnQlc"; dkim-atps=neutral Received: from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id B82B58BD for ; Mon, 29 Aug 2022 12:04:29 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1661767470; bh=6sbzgQdntHRRZ4KlQmYYZ41mnQ+VTWs7kF/CEKL6a4M=; h=From:To:Subject:Date:In-Reply-To:References:From; b=W4abnQlcu1Vx9iMAE6DwwdLFq8oN7u3tkZ8LWHf8jKzLrJ5VDHKpCZQp7Vc2/WtUa Vl2NWlBXO9+NQJmCL467tpPsFdrxfuaYYOAZ0mE/Ea3QTEE2HKaQF/gp0gf7IMoCvg O7ms//fWgJNrriag66Of5f22k7J21lzX0PwrK3ek= To: libcamera-devel@lists.libcamera.org Date: Mon, 29 Aug 2022 13:04:14 +0300 Message-Id: <20220829100414.28404-4-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220829100414.28404-1-laurent.pinchart@ideasonboard.com> References: <20220829100414.28404-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 3/3] qcam: viewfinder_gl: Take color space into account for YUV rendering 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: , X-Patchwork-Original-From: Laurent Pinchart via libcamera-devel From: Laurent Pinchart Reply-To: Laurent Pinchart Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Update the YUV shaders and the viewfinder_gl to correctly take the Y'CbCr encoding and the quantization range into account when rendering YUV formats to RGB. Support for the primaries and transfer function will be added in a subsequent step. Signed-off-by: Laurent Pinchart Reviewed-by: Umang Jain Reviewed-by: Kunal Agarwal --- src/qcam/assets/shader/YUV_2_planes.frag | 27 ++++---- src/qcam/assets/shader/YUV_3_planes.frag | 23 ++++--- src/qcam/assets/shader/YUV_packed.frag | 17 ++--- src/qcam/viewfinder_gl.cpp | 79 +++++++++++++++++++++++- src/qcam/viewfinder_gl.h | 2 + 5 files changed, 115 insertions(+), 33 deletions(-) diff --git a/src/qcam/assets/shader/YUV_2_planes.frag b/src/qcam/assets/shader/YUV_2_planes.frag index 254463c05cac..da8dbcc5f801 100644 --- a/src/qcam/assets/shader/YUV_2_planes.frag +++ b/src/qcam/assets/shader/YUV_2_planes.frag @@ -13,27 +13,30 @@ varying vec2 textureOut; uniform sampler2D tex_y; uniform sampler2D tex_u; +const mat3 yuv2rgb_matrix = mat3( + YUV2RGB_MATRIX +); + +const vec3 yuv2rgb_offset = vec3( + YUV2RGB_Y_OFFSET / 255.0, 128.0 / 255.0, 128.0 / 255.0 +); + void main(void) { vec3 yuv; - vec3 rgb; - mat3 yuv2rgb_bt601_mat = mat3( - vec3(1.164, 1.164, 1.164), - vec3(0.000, -0.392, 2.017), - vec3(1.596, -0.813, 0.000) - ); - yuv.x = texture2D(tex_y, textureOut).r - 0.063; + yuv.x = texture2D(tex_y, textureOut).r; #if defined(YUV_PATTERN_UV) - yuv.y = texture2D(tex_u, textureOut).r - 0.500; - yuv.z = texture2D(tex_u, textureOut).a - 0.500; + yuv.y = texture2D(tex_u, textureOut).r; + yuv.z = texture2D(tex_u, textureOut).a; #elif defined(YUV_PATTERN_VU) - yuv.y = texture2D(tex_u, textureOut).a - 0.500; - yuv.z = texture2D(tex_u, textureOut).r - 0.500; + yuv.y = texture2D(tex_u, textureOut).a; + yuv.z = texture2D(tex_u, textureOut).r; #else #error Invalid pattern #endif - rgb = yuv2rgb_bt601_mat * yuv; + vec3 rgb = yuv2rgb_matrix * (vec3(y, uv) - yuv2rgb_offset); + gl_FragColor = vec4(rgb, 1.0); } diff --git a/src/qcam/assets/shader/YUV_3_planes.frag b/src/qcam/assets/shader/YUV_3_planes.frag index 2be74b5d2a9d..e754129d74d1 100644 --- a/src/qcam/assets/shader/YUV_3_planes.frag +++ b/src/qcam/assets/shader/YUV_3_planes.frag @@ -14,20 +14,23 @@ uniform sampler2D tex_y; uniform sampler2D tex_u; uniform sampler2D tex_v; +const mat3 yuv2rgb_matrix = mat3( + YUV2RGB_MATRIX +); + +const vec3 yuv2rgb_offset = vec3( + YUV2RGB_Y_OFFSET / 255.0, 128.0 / 255.0, 128.0 / 255.0 +); + void main(void) { vec3 yuv; - vec3 rgb; - mat3 yuv2rgb_bt601_mat = mat3( - vec3(1.164, 1.164, 1.164), - vec3(0.000, -0.392, 2.017), - vec3(1.596, -0.813, 0.000) - ); - yuv.x = texture2D(tex_y, textureOut).r - 0.063; - yuv.y = texture2D(tex_u, textureOut).r - 0.500; - yuv.z = texture2D(tex_v, textureOut).r - 0.500; + yuv.x = texture2D(tex_y, textureOut).r; + yuv.y = texture2D(tex_u, textureOut).r; + yuv.z = texture2D(tex_v, textureOut).r; + + vec3 rgb = yuv2rgb_matrix * (vec3(y, uv) - yuv2rgb_offset); - rgb = yuv2rgb_bt601_mat * yuv; gl_FragColor = vec4(rgb, 1.0); } diff --git a/src/qcam/assets/shader/YUV_packed.frag b/src/qcam/assets/shader/YUV_packed.frag index d6efd4ce92a9..b9ef9d41beae 100644 --- a/src/qcam/assets/shader/YUV_packed.frag +++ b/src/qcam/assets/shader/YUV_packed.frag @@ -14,15 +14,16 @@ varying vec2 textureOut; uniform sampler2D tex_y; uniform vec2 tex_step; +const mat3 yuv2rgb_matrix = mat3( + YUV2RGB_MATRIX +); + +const vec3 yuv2rgb_offset = vec3( + YUV2RGB_Y_OFFSET / 255.0, 128.0 / 255.0, 128.0 / 255.0 +); + void main(void) { - mat3 yuv2rgb_bt601_mat = mat3( - vec3(1.164, 1.164, 1.164), - vec3(0.000, -0.392, 2.017), - vec3(1.596, -0.813, 0.000) - ); - vec3 yuv2rgb_bt601_offset = vec3(0.063, 0.500, 0.500); - /* * The sampler won't interpolate the texture correctly along the X axis, * as each RGBA pixel effectively stores two pixels. We thus need to @@ -76,7 +77,7 @@ void main(void) float y = mix(y_left, y_right, step(0.5, f_x)); - vec3 rgb = yuv2rgb_bt601_mat * (vec3(y, uv) - yuv2rgb_bt601_offset); + vec3 rgb = yuv2rgb_matrix * (vec3(y, uv) - yuv2rgb_offset); gl_FragColor = vec4(rgb, 1.0); } diff --git a/src/qcam/viewfinder_gl.cpp b/src/qcam/viewfinder_gl.cpp index ec295b6de0dd..e2aa24703ff0 100644 --- a/src/qcam/viewfinder_gl.cpp +++ b/src/qcam/viewfinder_gl.cpp @@ -7,9 +7,12 @@ #include "viewfinder_gl.h" +#include + #include #include #include +#include #include @@ -56,7 +59,8 @@ static const QList supportedFormats{ }; ViewFinderGL::ViewFinderGL(QWidget *parent) - : QOpenGLWidget(parent), buffer_(nullptr), image_(nullptr), + : QOpenGLWidget(parent), buffer_(nullptr), + colorSpace_(libcamera::ColorSpace::Raw), image_(nullptr), vertexBuffer_(QOpenGLBuffer::VertexBuffer) { } @@ -72,10 +76,10 @@ const QList &ViewFinderGL::nativeFormats() const } int ViewFinderGL::setFormat(const libcamera::PixelFormat &format, const QSize &size, - [[maybe_unused]] const libcamera::ColorSpace &colorSpace, + const libcamera::ColorSpace &colorSpace, unsigned int stride) { - if (format != format_) { + if (format != format_ || colorSpace != colorSpace_) { /* * If the fragment already exists, remove it and create a new * one for the new format. @@ -89,7 +93,10 @@ int ViewFinderGL::setFormat(const libcamera::PixelFormat &format, const QSize &s if (!selectFormat(format)) return -1; + selectColorSpace(colorSpace); + format_ = format; + colorSpace_ = colorSpace; } size_ = size; @@ -318,6 +325,72 @@ bool ViewFinderGL::selectFormat(const libcamera::PixelFormat &format) return ret; } +void ViewFinderGL::selectColorSpace(const libcamera::ColorSpace &colorSpace) +{ + std::array yuv2rgb; + + /* OpenGL stores arrays in column-major order. */ + switch (colorSpace.ycbcrEncoding) { + case libcamera::ColorSpace::YcbcrEncoding::None: + yuv2rgb = { + 1.0000, 0.0000, 0.0000, + 0.0000, 1.0000, 0.0000, + 0.0000, 0.0000, 1.0000, + }; + break; + + case libcamera::ColorSpace::YcbcrEncoding::Rec601: + yuv2rgb = { + 1.0000, 1.0000, 1.0000, + 0.0000, -0.3441, 1.7720, + 1.4020, -0.7141, 0.0000, + }; + break; + + case libcamera::ColorSpace::YcbcrEncoding::Rec709: + yuv2rgb = { + 1.0000, 1.0000, 1.0000, + 0.0000, -0.1873, 1.8856, + 1.5748, -0.4681, 0.0000, + }; + break; + + case libcamera::ColorSpace::YcbcrEncoding::Rec2020: + yuv2rgb = { + 1.0000, 1.0000, 1.0000, + 0.0000, -0.1646, 1.8814, + 1.4746, -0.5714, 0.0000, + }; + break; + } + + double offset; + + switch (colorSpace.range) { + case libcamera::ColorSpace::Range::Full: + offset = 0.0; + break; + + case libcamera::ColorSpace::Range::Limited: + offset = 16.0; + + for (unsigned int i = 0; i < 3; ++i) + yuv2rgb[i] *= 255.0 / 219.0; + for (unsigned int i = 4; i < 9; ++i) + yuv2rgb[i] *= 255.0 / 224.0; + break; + } + + QStringList matrix; + + for (double coeff : yuv2rgb) + matrix.append(QString::number(coeff, 'f')); + + fragmentShaderDefines_.append("#define YUV2RGB_MATRIX " + matrix.join(", ")); + fragmentShaderDefines_.append(QString("#define YUV2RGB_Y_OFFSET %1") + .arg(offset, 0, 'f', 1)); +} + bool ViewFinderGL::createVertexShader() { /* Create Vertex Shader */ diff --git a/src/qcam/viewfinder_gl.h b/src/qcam/viewfinder_gl.h index 798830a31cd2..68c2912df12f 100644 --- a/src/qcam/viewfinder_gl.h +++ b/src/qcam/viewfinder_gl.h @@ -57,6 +57,7 @@ protected: private: bool selectFormat(const libcamera::PixelFormat &format); + void selectColorSpace(const libcamera::ColorSpace &colorSpace); void configureTexture(QOpenGLTexture &texture); bool createFragmentShader(); @@ -67,6 +68,7 @@ private: /* Captured image size, format and buffer */ libcamera::FrameBuffer *buffer_; libcamera::PixelFormat format_; + libcamera::ColorSpace colorSpace_; QSize size_; unsigned int stride_; Image *image_;